Skip to content

Async import of the appStore packages#10

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

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

Conversation

@akshayutture-augment

@akshayutture-augment akshayutture-augment commented Nov 14, 2025

Copy link
Copy Markdown

Test 2

Summary by CodeRabbit

  • Refactor
    • Converted calendar retrieval operations to asynchronous execution for improved reliability in booking management, cancellations, and event updates.
    • Updated video adapter provisioning to async operations, ensuring proper resolution before meeting operations.
    • Implemented asynchronous app store initialization and payment app retrieval throughout the platform for consistent handling.

Replicated from ai-code-review-evaluation/cal.com-coderabbit#2

@akshayutture-augment

Copy link
Copy Markdown
Author

@coderabbitai review

@akshayutture-augment

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 18, 2025

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Nov 18, 2025

Copy link
Copy Markdown

Walkthrough

This pull request converts the application's synchronous calendar and adapter retrieval patterns to asynchronous ones. The getCalendar function and appStore object are refactored to return Promises, and call sites throughout the codebase are updated to await these async operations.

Changes

Cohort / File(s) Summary
App Store Infrastructure
packages/app-store/index.ts, packages/app-store/_utils/getCalendar.ts
Refactors appStore to use dynamic imports returning Promises instead of static imports; updates getCalendar signature from synchronous to Promise<Calendar | null> and awaits appStore lookups internally.
Calendar Manager & Event Handling
packages/core/CalendarManager.ts, packages/core/EventManager.ts
Updates multiple call sites to await getCalendar; marks deleteEvent as async; ensures calendar resolution before subsequent operations.
Video Client Refactoring
packages/core/videoClient.ts
Converts getVideoAdapters to async with explicit loop-based adapter collection; marks getBusyVideoTimes and deleteMeeting as async; updates all call sites to await adapter retrieval.
Payment Service Integration
packages/lib/payment/deletePayment.ts, packages/lib/payment/handlePayment.ts
Updates appStore lookups for paymentApp to use async retrieval with await.
Booking Management
packages/features/bookings/lib/handleCancelBooking.ts, packages/features/bookings/lib/handleNewBooking.ts, packages/trpc/server/routers/viewer/bookings.tsx
Awaits getCalendar in event deletion and calendar operation paths; converts forEach callbacks to async; awaits payment app retrieval from appStore.
Reschedule Operations
packages/app-store/vital/lib/reschedule.ts, packages/app-store/wipemycalother/lib/reschedule.ts
Converts forEach callbacks to async and awaits calendar deletion operations within the loop.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Handler
    participant appStore
    participant Calendar

    Note over Caller,Calendar: Old Flow (Synchronous)
    Caller->>Handler: handleCancelBooking()
    Handler->>appStore: getCalendar(credential)
    appStore-->>Handler: Calendar object
    Handler->>Calendar: deleteEvent()

    Note over Caller,Calendar: New Flow (Asynchronous)
    Caller->>Handler: handleCancelBooking()
    Handler->>appStore: await import("./calendar")
    appStore-->>Handler: Promise<Calendar>
    Handler->>Handler: await getCalendar(credential)
    Handler->>Calendar: await deleteEvent()
    Calendar-->>Handler: resolved result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Critical areas for review:
    • Verify all call sites of getCalendar have been updated to await; incomplete conversions could silently operate on Promises.
    • Check forEach loops in reschedule and booking handlers for unresolved async callbacks—missing await Promise.all() or similar could leave operations incomplete.
    • Validate that dynamic imports in appStore/index.ts are correctly resolved before use across all modules.
    • Inspect videoClient.ts changes for consistency in adapter provisioning across createMeeting, updateMeeting, deleteMeeting, and related helpers.
    • Ensure error handling paths account for Promise rejections in newly async functions.
    • Review payment app retrieval paths in payment and booking handlers to confirm proper async handling.

Poem

A hop through async lands we go,
Where Promises flow and callbacks await,
Each calendar call now takes its time,
The app grows graceful, less frantic, sublime—
🐰 Refactored with care!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: converting static imports of appStore packages to dynamic imports that return Promises.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch appstore-async-improvements

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/app-store/vital/lib/reschedule.ts (1)

125-133: <!-- [scratchpad_start]
[task review_file_vital_reschedule verify_issue_severity 2/2]
Verification complete.

[observations]

  • getCalendar: export const getCalendar = async (credential: CredentialPayload | null): Promise<Calendar | null> (packages/app-store/_utils/getCalendar.ts:9)
    • Definitely async function
  • deleteMeeting: const deleteMeeting = async (credential: CredentialPayload, uid: string): Promise<unknown> (packages/core/videoClient.ts:142)
    • Definitely async function
  • Correct pattern shown in EventManager.ts:488-489:
    • const calendar = await getCalendar(...)
    • await calendar?.deleteEvent(...)
    • Both are awaited

[analysis]
ISSUE CONFIRMED - The review comment is correct and severe:

  1. forEach(async callback) is NOT awaited → fire-and-forget behavior
  2. Try/catch does NOT catch errors from async callbacks (execute after try/catch completes)
  3. getCalendar is awaited inside callback, but if it rejects, error bypasses outer try/catch
  4. deleteMeeting and calendar?.deleteEvent are returned (not awaited) inside callback
  5. Function returns true before any deletions complete
  6. No error handling for async operations
  7. Codebase shows correct pattern elsewhere (EventManager.ts)

[severity]
This is a MAJOR issue:

  • Critical path: booking rescheduling
  • Real bug: async work not awaited, errors not caught
  • Reliability risk: deletions may not complete
  • Original review marked - verification confirms

[actions]
Generate rewritten review comment with tag
[done]
</scratchpad_end] -->

Async forEach does not wait for deletions and errors bypass try/catch

The code uses forEach with an async callback without awaiting it. This makes all callbacks fire-and-forget—the function returns before deletions complete, and any errors thrown inside the callbacks (from getCalendar or deleteMeeting) will not be caught by the surrounding try/catch block since they execute asynchronously after that block completes.

Switch to an awaited loop to ensure all deletions complete and errors are properly caught:

-    try {
-      bookingRefsFiltered.forEach(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);
-          }
-        }
-      });
-    } catch (error) {
+    try {
+      await Promise.all(
+        bookingRefsFiltered.map(async (bookingRef) => {
+          if (!bookingRef.uid) return;
+          if (bookingRef.type.endsWith("_calendar")) {
+            const calendar = await getCalendar(credentialsMap.get(bookingRef.type));
+            await calendar?.deleteEvent(bookingRef.uid, builder.calendarEvent);
+          } else if (bookingRef.type.endsWith("_video")) {
+            await deleteMeeting(credentialsMap.get(bookingRef.type), bookingRef.uid);
+          }
+        })
+      );
+    } catch (error) {
       if (error instanceof Error) {
         logger.error(error.message);
       }
     }

This ensures deletions complete before proceeding and errors are properly handled.

packages/app-store/wipemycalother/lib/reschedule.ts (1)

117-139: Avoid async forEach for calendar/video deletions; await the operations

bookingRefsFiltered.forEach(async (bookingRef) => { ... }) runs deletions in fire‑and‑forget fashion: the outer function neither waits for them nor can the try/catch see async errors. If getCalendar or deleteEvent/deleteMeeting rejects, it will surface as an unhandled rejection, and Reschedule will return true before cleanup finishes.

Refactor to collect and await the tasks, for example:

-    try {
-      bookingRefsFiltered.forEach(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);
-          }
-        }
-      });
-    } catch (error) {
+    const deletionPromises = bookingRefsFiltered.map(async (bookingRef) => {
+      if (!bookingRef.uid) return;
+
+      const credential = credentialsMap.get(bookingRef.type);
+
+      if (bookingRef.type.endsWith("_calendar")) {
+        const calendar = await getCalendar(credential);
+        await calendar?.deleteEvent(bookingRef.uid, builder.calendarEvent);
+      } else if (bookingRef.type.endsWith("_video")) {
+        await deleteMeeting(credential, bookingRef.uid);
+      }
+    });
+
+    try {
+      await Promise.allSettled(deletionPromises);
+    } catch (error) {
       if (error instanceof Error) {
         logger.error(error.message);
       }
     }

This keeps the error logging behavior while ensuring all deletions are triggered and awaited.

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

544-568: Refactor async forEach when cancelling calendar/video references

Here too, bookingRefsFiltered.forEach(async (bookingRef) => { ... }) launches async work without awaiting it. Any rejection from getCalendar or deleteEvent/deleteMeeting becomes an unhandled rejection, and the mutation returns before cancellations finish.

Prefer an awaited aggregation instead:

-        const bookingRefsFiltered: BookingReference[] = bookingToReschedule.references.filter(
-          (ref) => !!credentialsMap.get(ref.type)
-        );
-        bookingRefsFiltered.forEach(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);
-            }
-          }
-        });
+        const bookingRefsFiltered: BookingReference[] = bookingToReschedule.references.filter(
+          (ref) => !!credentialsMap.get(ref.type)
+        );
+
+        const deletionPromises = bookingRefsFiltered.map(async (bookingRef) => {
+          if (!bookingRef.uid) return;
+
+          const credential = credentialsMap.get(bookingRef.type);
+
+          if (bookingRef.type.endsWith("_calendar")) {
+            const calendar = await getCalendar(credential);
+            await calendar?.deleteEvent(
+              bookingRef.uid,
+              builder.calendarEvent,
+              bookingRef.externalCalendarId
+            );
+          } else if (bookingRef.type.endsWith("_video")) {
+            await deleteMeeting(credential, bookingRef.uid);
+          }
+        });
+
+        await Promise.allSettled(deletionPromises);

This makes the cancellation behavior deterministic and prevents unhandled rejections.


782-804: Fix authorization predicate and booking confirmation message construction

Two correctness issues in confirm should be addressed:

  1. Authorization check always succeeds for collective events
if (
  eventType?.schedulingType === SchedulingType.COLLECTIVE &&
  eventType.users.find((user) => user.id === user.id)
) {

The predicate user.id === user.id is always true, so any collective event with at least one user passes authorization, regardless of the logged‑in user. It should compare against the outer user from ctx:

-      if (
-        eventType?.schedulingType === SchedulingType.COLLECTIVE &&
-        eventType.users.find((user) => user.id === user.id)
-      ) {
+      if (
+        eventType?.schedulingType === SchedulingType.COLLECTIVE &&
+        eventType.users.some((member) => member.id === user.id)
+      ) {
  1. Confirmation/rejection message ignores confirmed value
const message = "Booking " + confirmed ? "confirmed" : "rejected";

Due to operator precedence, "Booking " + confirmed is evaluated first and always truthy, so message is always "confirmed". It should embed the ternary:

-    const message = "Booking " + confirmed ? "confirmed" : "rejected";
+    const message = `Booking ${confirmed ? "confirmed" : "rejected"}`;

These directly impact authorization and API responses and should be fixed before release.

Also applies to: 997-1000

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

437-483: Fix async deletion for recurring bookings and apiDeletes handling

There are a couple of issues around the recurring cancellations and API deletions:

  1. Async forEach + resolved values pushed to apiDeletes
bookingToDelete.user.credentials
  .filter((credential) => credential.type.endsWith("_calendar"))
  .forEach(async (credential) => {
    const calendar = await getCalendar(credential);
    for (const updBooking of updatedBookings) {
      const bookingRef = updBooking.references.find((ref) => ref.type.includes("_calendar"));
      if (bookingRef) {
        const { uid, externalCalendarId } = bookingRef;
        const deletedEvent = await calendar?.deleteEvent(uid, evt, externalCalendarId);
        apiDeletes.push(deletedEvent);
      }
    }
  });
  • forEach(async ...) is never awaited, so apiDeletes may still be empty when Promise.all(prismaPromises.concat(apiDeletes)) is called later.
  • deletedEvent is the resolved result of deleteEvent, but apiDeletes is treated elsewhere as an array of Promises (Promise.all(...), await apiDeletes).

This is a regression from the prior pattern where calendar?.deleteEvent(...) Promises were pushed synchronously and awaited together.

Refactor to push Promises and await them deterministically, e.g.:

-        if (
-          bookingToDelete.eventType?.recurringEvent &&
-          bookingToDelete.recurringEventId &&
-          allRemainingBookings
-        ) {
-          bookingToDelete.user.credentials
-            .filter((credential) => credential.type.endsWith("_calendar"))
-            .forEach(async (credential) => {
-              const calendar = await getCalendar(credential);
-              for (const updBooking of updatedBookings) {
-                const bookingRef = updBooking.references.find((ref) => ref.type.includes("_calendar"));
-                if (bookingRef) {
-                  const { uid, externalCalendarId } = bookingRef;
-                  const deletedEvent = await calendar?.deleteEvent(uid, evt, externalCalendarId);
-                  apiDeletes.push(deletedEvent);
-                }
-              }
-            });
-        } else {
-          apiDeletes.push(calendar?.deleteEvent(uid, evt, externalCalendarId) as Promise<unknown>);
-        }
+        if (
+          bookingToDelete.eventType?.recurringEvent &&
+          bookingToDelete.recurringEventId &&
+          allRemainingBookings
+        ) {
+          const calendarCredentials = bookingToDelete.user.credentials.filter((credential) =>
+            credential.type.endsWith("_calendar")
+          );
+
+          for (const credential of calendarCredentials) {
+            const calendarForCred = await getCalendar(credential);
+            if (!calendarForCred) continue;
+
+            for (const updBooking of updatedBookings) {
+              const bookingRef = updBooking.references.find((ref) => ref.type.includes("_calendar"));
+              if (!bookingRef) continue;
+
+              const { uid, externalCalendarId } = bookingRef;
+              apiDeletes.push(
+                calendarForCred.deleteEvent(uid, evt, externalCalendarId) as Promise<unknown>
+              );
+            }
+          }
+        } else if (calendar) {
+          apiDeletes.push(calendar.deleteEvent(uid, evt, externalCalendarId) as Promise<unknown>);
+        }

Also declare apiDeletes with an explicit type to avoid accidentally mixing values and Promises:

-  const apiDeletes = [];
+  const apiDeletes: Promise<unknown>[] = [];
  1. await apiDeletes in the paid‑booking branch does not wait for deletions

In the paid‑booking path:

// We skip the deletion of the event, because that would also delete the payment reference, which we should keep
await apiDeletes;
req.statusCode = 200;
return { message: "Booking successfully cancelled." };

apiDeletes is an array, so await apiDeletes resolves immediately and does not wait on the contained Promises. If you intend to await them here (and then return early), this should be:

-    await apiDeletes;
+    await Promise.all(apiDeletes);

Together, these changes will restore the original behavior (all deletions dispatched and awaited) under the new async getCalendar model and prevent unhandled rejections or silently skipped deletions for recurring bookings.

Also applies to: 513-620

🧹 Nitpick comments (3)
packages/core/EventManager.ts (1)

478-490: Guard against missing calendar credentials before awaiting getCalendar

The switch to await getCalendar(calendarCredential) is the right move, but prisma.credential.findUnique can return null, so calendarCredential may be undefined here. It would be safer to bail out when no credential is found instead of calling getCalendar on a potentially null value.

For example:

-        if (oldCalendarEvent?.credentialId) {
-          const calendarCredential = await prisma.credential.findUnique({
+        if (oldCalendarEvent?.credentialId) {
+          const calendarCredential = await prisma.credential.findUnique({
             where: {
               id: oldCalendarEvent.credentialId,
             },
           });
-          const calendar = await getCalendar(calendarCredential);
-          await calendar?.deleteEvent(oldCalendarEvent.uid, event, oldCalendarEvent.externalCalendarId);
+          if (calendarCredential) {
+            const calendar = await getCalendar(calendarCredential);
+            await calendar?.deleteEvent(
+              oldCalendarEvent.uid,
+              event,
+              oldCalendarEvent.externalCalendarId
+            );
+          }
         }
packages/lib/payment/handlePayment.ts (1)

26-40: Async resolution of paymentApp matches the dynamic app-store pattern

Awaiting appStore[dirName] here is consistent with a Promise-based appStore and ensures you only touch paymentApp.lib.PaymentService once the module is loaded. You might consider logging paymentAppCredentials.app?.dirName in the warning instead of ${paymentApp} for clearer diagnostics, but the core async change looks good.

packages/core/videoClient.ts (1)

21-36: Consider parallel loading for better performance with multiple credentials.

The sequential await in the loop (line 26) means credentials are processed one at a time. With multiple credentials, this could be noticeably slower than necessary.

Apply this diff to load modules in parallel:

 const getVideoAdapters = async (withCredentials: CredentialPayload[]): Promise<VideoApiAdapter[]> => {
   const videoAdapters: VideoApiAdapter[] = [];
 
-  for (const cred of withCredentials) {
+  const adapterPromises = withCredentials.map(async (cred) => {
     const appName = cred.type.split("_").join(""); // Transform `zoom_video` to `zoomvideo`;
     const app = await appStore[appName as keyof typeof appStore];
 
     if (app && "lib" in app && "VideoApiAdapter" in app.lib) {
       const makeVideoApiAdapter = app.lib.VideoApiAdapter as VideoApiAdapterFactory;
-      const videoAdapter = makeVideoApiAdapter(cred);
-      videoAdapters.push(videoAdapter);
+      return makeVideoApiAdapter(cred);
     }
-  }
+    return null;
+  });
 
-  return videoAdapters;
+  const results = await Promise.all(adapterPromises);
+  return results.filter((adapter): adapter is VideoApiAdapter => adapter !== null);
 };

This processes all credentials concurrently rather than sequentially.

📜 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 comments (15)
packages/features/bookings/lib/handleNewBooking.ts (1)

883-893: Awaiting getCalendar here is correct with the new async calendar API

Using await getCalendar(credential) inside lastAttendeeDeleteBooking matches the async return type and ensures you only enqueue deleteEvent calls once the calendar instance is resolved. No further changes needed in this block.

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

16-24: Async lookup of paymentApp from appStore looks correct

Awaiting appStore[dirName] is consistent with a dynamic-import–backed app store and keeps the subsequent PaymentService checks intact. No issues spotted in this change.

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

962-979: Async appStore payment app lookup is correct

The change to const paymentApp = await appStore[...] aligns with the async appStore design and the subsequent runtime checks on paymentApp.lib.PaymentService. The surrounding error handling (if (!paymentApp...){ console.warn; return null; }) still behaves as before, so the refactor here looks good.

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

9-22: Async getCalendar implementation looks good

Making getCalendar async and awaiting appStore[calendarType...] to resolve the app module is consistent with the new appStore contract. The existing guards for missing credentials and unsupported calendar types are preserved, and returning a CalendarService instance wrapped in a Promise is appropriate. From the surrounding changes, callers are already updated to await getCalendar, so this refactor looks sound.

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

229-276: Seat attendee calendar/video updates now correctly await getCalendar

In the seated‑event branch, switching to const calendar = await getCalendar(credential); and then pushing calendar?.deleteEvent/updateEvent Promises into integrationsToDelete, followed by await Promise.all(integrationsToDelete), keeps the behavior correct with the new async getCalendar. This segment looks good.


588-597: Async appStore payment app resolution is aligned with new design

Updating const paymentApp = await appStore[...] is consistent with the async appStore contract, and the existing guard that checks for paymentApp.lib.PaymentService remains intact. The refund logic wrapped in try/catch still behaves the same. No issues here.

packages/core/CalendarManager.ts (1)

23-36: Async getCalendar usage in CalendarManager is consistent and correct

  • In getCalendarCredentials you now store the Promise from getCalendar(credential) and later await item.calendar in getConnectedCalendars, which keeps the API clean while deferring calendar resolution.
  • getCachedResults correctly resolves calendars with Promise.all(calendarCredentials.map(getCalendar)) before calling getAvailability.
  • createEvent, updateEvent, and deleteEvent now await getCalendar(credential) and guard on a falsy calendar, preserving previous behavior while aligning with the async getCalendar contract. Returning a resolved empty object from deleteEvent when no calendar is available is a reasonable no‑op fallback.

Based on the code shown, these async refactors look sound.

Also applies to: 135-175, 228-341

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

1-31: Clarify: Are lazy-loaded dynamic imports intended here?

All dynamic imports execute immediately when this module loads, rather than being deferred until first access. If the goal is true lazy loading (to reduce initial bundle and defer network/parse cost), wrap each import in a function:

 const appStore = {
-  applecalendar: import("./applecalendar"),
+  applecalendar: () => import("./applecalendar"),

Then consumers would call await appStore.applecalendar() instead of await appStore.applecalendar.

If immediate execution is intentional (e.g., to begin prefetching modules early), the current pattern is correct.

Which behavior do you want?

  • Immediate: Current code is correct; imports start when appStore loads
  • Lazy: Apply the function-wrapper pattern above
packages/core/videoClient.ts (7)

38-41: LGTM!

The async conversion is correct. The function properly awaits adapter retrieval before proceeding with availability checks.


52-53: LGTM!

Correctly awaits the video adapters before destructuring and using them.


111-111: LGTM!

Correctly awaits the video adapters before destructuring.


142-151: LGTM!

The async conversion is correct. The function properly handles both the credential and no-credential cases.


162-172: LGTM!

Correctly awaits the video adapter before using it to create a meeting.


185-195: LGTM!

Correctly awaits the video adapter before retrieving recordings.


206-216: LGTM!

Correctly awaits the video adapter before retrieving the download link.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants