Skip to content

Async import of the appStore packages#2

Open
everettbu wants to merge 1 commit into
appstore-sync-refactor-basefrom
appstore-async-improvements
Open

Async import of the appStore packages#2
everettbu wants to merge 1 commit into
appstore-sync-refactor-basefrom
appstore-async-improvements

Conversation

@everettbu

@everettbu everettbu commented Jul 28, 2025

Copy link
Copy Markdown

Test 2

Summary by CodeRabbit

  • Refactor

    • Improved handling of calendar and payment integrations by making related operations asynchronous, ensuring more reliable loading and execution.
    • Updated booking, payment, and event management processes to properly await external app modules, reducing potential issues with timing or incomplete data.
  • Bug Fixes

    • Resolved potential issues where calendar or payment actions could fail due to asynchronous loading, resulting in more consistent behavior across booking, cancellation, and payment flows.

@coderabbitai

coderabbitai Bot commented Jul 28, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

The changes refactor the app store architecture and related modules to support asynchronous, on-demand loading of application modules using dynamic imports. All functions that interact with the app store or depend on dynamically loaded modules—such as calendar, video, and payment services—are updated to handle asynchronous retrievals via await. This includes updating function signatures, internal logic, and iteration patterns to accommodate asynchronous control flow.

Changes

Cohort / File(s) Change Summary
App Store Dynamic Import Refactor
packages/app-store/index.ts
Converts all static imports to dynamic imports within appStore, making all app module retrievals asynchronous via import().
Calendar Utility Async Update
packages/app-store/_utils/getCalendar.ts
Changes getCalendar from synchronous to asynchronous; updates internal logic to await app retrieval and updates function signature to return a promise.
Calendar Service Async Integration
packages/core/CalendarManager.ts
Refactors all internal usages of getCalendar to be awaited; updates several function signatures to be asynchronous; ensures all calendar operations await calendar instance resolution.
Video Service Async Integration
packages/core/videoClient.ts
Refactors getVideoAdapters and all related functions to be asynchronous, awaiting dynamic app retrievals and updating all usages to handle promises.
Event Manager Calendar Async
packages/core/EventManager.ts
Updates updateAllCalendarEvents to await getCalendar asynchronously.
Booking Cancel Handler Async
packages/features/bookings/lib/handleCancelBooking.ts
Updates all usages of getCalendar to be awaited; changes iteration over credentials to async-compatible patterns; awaits payment app retrieval from appStore.
Booking New Handler Async
packages/features/bookings/lib/handleNewBooking.ts
Updates lastAttendeeDeleteBooking to await getCalendar asynchronously.
Vital App Reschedule Async
packages/app-store/vital/lib/reschedule.ts
Changes forEach callback to async and awaits getCalendar for each booking reference.
Wipemycalother Reschedule Async
packages/app-store/wipemycalother/lib/reschedule.ts
Changes forEach callback to async and awaits getCalendar for each booking reference.
Payment Deletion Async
packages/lib/payment/deletePayment.ts
Awaits dynamic retrieval of payment app from appStore before proceeding.
Payment Handler Async
packages/lib/payment/handlePayment.ts
Awaits dynamic retrieval of payment app from appStore before proceeding.
Viewer Bookings Router Async
packages/trpc/server/routers/viewer/bookings.tsx
Awaits getCalendar in async forEach for rescheduling; awaits payment app retrieval in confirmation mutation.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant AppStore
    participant AppModule
    participant Service

    Caller->>+AppStore: await appStore["calendar"]
    AppStore-->>-Caller: Promise<AppModule>
    Caller->>+AppModule: new CalendarService(credential)
    AppModule-->>-Caller: CalendarService instance
    Caller->>Service: serviceMethod(...)
    Service-->>Caller: result
Loading
sequenceDiagram
    participant Caller
    participant AppStore
    participant AppModule
    participant PaymentService

    Caller->>+AppStore: await appStore["payment"]
    AppStore-->>-Caller: Promise<AppModule>
    Caller->>+AppModule: new PaymentService(credential)
    AppModule-->>-Caller: PaymentService instance
    Caller->>PaymentService: deletePayment(...)
    PaymentService-->>Caller: result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

In the warren of code, async hops abound,
Rabbits refactor, no static imports found!
With promises awaited, each module arrives,
Dynamic and nimble, our logic now thrives.
So raise a carrot, let’s joyfully cheer—
For asynchronous springtime is finally here! 🥕✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch appstore-async-improvements

🪧 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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (3)
packages/trpc/server/routers/viewer/bookings.tsx (1)

553-567: Critical: forEach with async callback doesn't wait for completion.

Using forEach with an async callback is problematic because forEach doesn't wait for the promises to resolve. This means the calendar deletion operations will run concurrently but the function won't wait for them to complete, potentially causing race conditions or unhandled promise rejections.

Replace the forEach with Promise.all and map to properly handle the async operations:

-        bookingRefsFiltered.forEach(async (bookingRef) => {
+        await Promise.all(
+          bookingRefsFiltered.map(async (bookingRef) => {
             if (bookingRef.uid) {
               if (bookingRef.type.endsWith("_calendar")) {
                 const calendar = await getCalendar(credentialsMap.get(bookingRef.type));
 
                 return calendar?.deleteEvent(
                   bookingRef.uid,
                   builder.calendarEvent,
                   bookingRef.externalCalendarId
                 );
               } else if (bookingRef.type.endsWith("_video")) {
                 return deleteMeeting(credentialsMap.get(bookingRef.type), bookingRef.uid);
               }
             }
-        });
+          })
+        );
packages/app-store/vital/lib/reschedule.ts (1)

125-134: Critical: forEach with async callback doesn't wait for completion.

This is the same issue as in the bookings router - forEach doesn't wait for async callbacks to complete, which can lead to race conditions and unhandled promise rejections.

Replace with Promise.all and map for proper async handling:

-      bookingRefsFiltered.forEach(async (bookingRef) => {
+      await Promise.all(
+        bookingRefsFiltered.map(async (bookingRef) => {
           if (bookingRef.uid) {
             if (bookingRef.type.endsWith("_calendar")) {
               const calendar = await getCalendar(credentialsMap.get(bookingRef.type));
               return calendar?.deleteEvent(bookingRef.uid, builder.calendarEvent);
             } else if (bookingRef.type.endsWith("_video")) {
               return deleteMeeting(credentialsMap.get(bookingRef.type), bookingRef.uid);
             }
           }
-        });
+        })
+      );
packages/app-store/wipemycalother/lib/reschedule.ts (1)

125-134: Critical: forEach with async callback doesn't wait for completion.

Same issue as in the other reschedule files - forEach with async callbacks doesn't properly wait for promise resolution.

Apply the same fix using Promise.all:

-      bookingRefsFiltered.forEach(async (bookingRef) => {
+      await Promise.all(
+        bookingRefsFiltered.map(async (bookingRef) => {
           if (bookingRef.uid) {
             if (bookingRef.type.endsWith("_calendar")) {
               const calendar = await getCalendar(credentialsMap.get(bookingRef.type));
               return calendar?.deleteEvent(bookingRef.uid, builder.calendarEvent);
             } else if (bookingRef.type.endsWith("_video")) {
               return deleteMeeting(credentialsMap.get(bookingRef.type), bookingRef.uid);
             }
           }
-        });
+        })
+      );
🧹 Nitpick comments (2)
packages/app-store/wipemycalother/lib/reschedule.ts (1)

125-134: Consider refactoring duplicate reschedule logic.

This reschedule implementation appears very similar to the one in packages/app-store/vital/lib/reschedule.ts. Consider extracting the common booking reference cleanup logic into a shared utility function to reduce code duplication and improve maintainability.

packages/app-store/index.ts (1)

1-31: LGTM: Correct conversion to dynamic imports.

The conversion from static to dynamic imports is properly implemented and provides several benefits:

  1. Lazy loading: Modules are only loaded when actually needed, improving initial bundle size and startup performance
  2. On-demand resolution: Apps are resolved asynchronously, allowing for better resource management
  3. Consistent pattern: All modules follow the same import("./modulename") pattern

The change maintains the same export interface while enabling asynchronous module loading throughout the codebase.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bff28e5 and e043a5e.

📒 Files selected for processing (12)
  • packages/app-store/_utils/getCalendar.ts (1 hunks)
  • packages/app-store/index.ts (1 hunks)
  • packages/app-store/vital/lib/reschedule.ts (1 hunks)
  • packages/app-store/wipemycalother/lib/reschedule.ts (1 hunks)
  • packages/core/CalendarManager.ts (6 hunks)
  • packages/core/EventManager.ts (1 hunks)
  • packages/core/videoClient.ts (7 hunks)
  • packages/features/bookings/lib/handleCancelBooking.ts (6 hunks)
  • packages/features/bookings/lib/handleNewBooking.ts (1 hunks)
  • packages/lib/payment/deletePayment.ts (1 hunks)
  • packages/lib/payment/handlePayment.ts (1 hunks)
  • packages/trpc/server/routers/viewer/bookings.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
packages/app-store/vital/lib/reschedule.ts (1)
packages/app-store/_utils/getCalendar.ts (1)
  • getCalendar (9-23)
packages/trpc/server/routers/viewer/bookings.tsx (1)
packages/app-store/_utils/getCalendar.ts (1)
  • getCalendar (9-23)
packages/app-store/_utils/getCalendar.ts (2)
packages/types/Credential.d.ts (1)
  • CredentialPayload (8-17)
packages/types/Calendar.d.ts (1)
  • Calendar (213-231)
packages/core/EventManager.ts (1)
packages/app-store/_utils/getCalendar.ts (1)
  • getCalendar (9-23)
packages/app-store/wipemycalother/lib/reschedule.ts (1)
packages/app-store/_utils/getCalendar.ts (1)
  • getCalendar (9-23)
packages/features/bookings/lib/handleCancelBooking.ts (1)
packages/app-store/_utils/getCalendar.ts (1)
  • getCalendar (9-23)
packages/features/bookings/lib/handleNewBooking.ts (1)
packages/app-store/_utils/getCalendar.ts (1)
  • getCalendar (9-23)
🔇 Additional comments (25)
packages/features/bookings/lib/handleNewBooking.ts (1)

888-888: LGTM! Correctly updated to await the asynchronous getCalendar function.

The addition of await aligns with the refactored getCalendar function that now returns a Promise<Calendar | null> due to asynchronous app store loading.

packages/core/EventManager.ts (1)

488-488: LGTM! Correctly updated to await the asynchronous getCalendar function.

The addition of await properly handles the asynchronous nature of getCalendar following the app store refactor to dynamic imports.

packages/lib/payment/deletePayment.ts (1)

16-16: LGTM! Correctly updated to await asynchronous app store access.

The addition of await properly handles the asynchronous app store retrieval following the refactor to dynamic imports.

packages/lib/payment/handlePayment.ts (1)

26-26: LGTM! Correctly updated to await asynchronous app store access.

The addition of await properly handles the asynchronous app store retrieval following the refactor to dynamic imports, maintaining consistent behavior while supporting the new async architecture.

packages/trpc/server/routers/viewer/bookings.tsx (1)

967-967: LGTM: Correct async appStore access.

The payment app retrieval correctly awaits the dynamic import from appStore, which aligns with the new asynchronous module loading architecture.

packages/app-store/_utils/getCalendar.ts (1)

9-23: LGTM: Correct async conversion.

The function signature and implementation have been properly updated to handle the asynchronous appStore access. The return type correctly reflects the promise-based nature, and the await usage is appropriate for the dynamic import pattern.

packages/features/bookings/lib/handleCancelBooking.ts (5)

243-243: LGTM! Proper async handling for calendar retrieval.

The getCalendar call is correctly awaited, consistent with the new asynchronous signature.


265-265: LGTM! Consistent async pattern.

Calendar retrieval is properly awaited for the event update scenario.


452-452: LGTM! Async calendar retrieval handled correctly.

The calendar instance is properly awaited before use in the booking reference handling logic.


477-483: LGTM! Proper conversion to sequential async processing.

The code correctly converts from forEach to for...of loop to handle async getCalendar calls sequentially, avoiding race conditions.


589-589: LGTM! Consistent async app store access.

The payment app retrieval from appStore is properly awaited, aligning with the new asynchronous module loading pattern.

packages/core/CalendarManager.ts (6)

31-31: Minor formatting improvement.

Added blank line improves code readability.


47-48: LGTM! Proper async calendar handling.

The calendar is correctly awaited from item.calendar before use, ensuring the Promise is resolved.


142-142: LGTM! Consistent async pattern for calendar array.

All calendar credentials are properly mapped to awaited getCalendar calls using Promise.all.


233-233: LGTM! Proper async calendar retrieval.

The getCalendar call is correctly awaited in the createEvent function.


284-284: LGTM! Consistent async handling.

Calendar retrieval is properly awaited in the updateEvent function.


330-335: LGTM! Proper async deleteEvent implementation.

The function signature is correctly updated to async and the getCalendar call is properly awaited.

packages/core/videoClient.ts (8)

21-36: LGTM! Proper async conversion of getVideoAdapters.

The function is correctly converted to async with proper error handling:

  • Uses for...of loop for sequential async processing
  • Properly awaits app store access
  • Maintains existing logic flow
  • Returns Promise<VideoApiAdapter[]> as expected

38-39: LGTM! Consistent async pattern.

getBusyVideoTimes properly awaits getVideoAdapters before processing results.


52-52: LGTM! Proper async handling in createMeeting.

The getVideoAdapters call is correctly awaited.


111-111: LGTM! Consistent async pattern in updateMeeting.

Video adapters are properly awaited before destructuring.


142-144: LGTM! Proper async handling in deleteMeeting.

The function correctly awaits getVideoAdapters and handles the async flow.


162-171: LGTM! Consistent async pattern for Cal video fallback.

Video adapter creation is properly awaited in the fallback scenario.


185-194: LGTM! Proper async handling for recordings.

The getVideoAdapters call is correctly awaited for Cal video recordings functionality.


206-215: LGTM! Consistent async pattern for download links.

Video adapter retrieval is properly awaited for recording download functionality.

Comment on lines 460 to +461
.forEach(async (credential) => {
const calendar = getCalendar(credential);
const calendar = await getCalendar(credential);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Potential race condition in forEach with async operations.

The forEach loop with async getCalendar calls may not execute sequentially and could lead to race conditions or performance issues.

Replace the forEach with for...of loop to ensure proper sequential execution:

-        bookingToDelete.user.credentials
-          .filter((credential) => credential.type.endsWith("_calendar"))
-          .forEach(async (credential) => {
-            const calendar = await getCalendar(credential);
+        const calendarCredentials = bookingToDelete.user.credentials
+          .filter((credential) => credential.type.endsWith("_calendar"));
+        for (const credential of calendarCredentials) {
+          const calendar = await getCalendar(credential);
🤖 Prompt for AI Agents
In packages/features/bookings/lib/handleCancelBooking.ts at lines 460-461, the
use of forEach with an async callback causes the async operations to run
concurrently, which can lead to race conditions or unexpected behavior. Replace
the forEach loop with a for...of loop to await each async getCalendar call
sequentially, ensuring proper order and avoiding concurrency issues.

@github-actions

Copy link
Copy Markdown
Contributor

This PR is being marked as stale due to inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants