Skip to content

chore: [Booking flow refactor - DI Cleanup - 1] Make ioctopus flow more type-safe and runtime-safe#23541

Merged
hariombalhara merged 1 commit intomainfrom
ioctpus-type-and-runtime-safer
Sep 10, 2025
Merged

chore: [Booking flow refactor - DI Cleanup - 1] Make ioctopus flow more type-safe and runtime-safe#23541
hariombalhara merged 1 commit intomainfrom
ioctpus-type-and-runtime-safer

Conversation

@hariombalhara
Copy link
Copy Markdown
Member

@hariombalhara hariombalhara commented Sep 3, 2025

1. Standardized Module Structure

  • Before: Modules were scattered with inconsistent token management
  • After: All modules now export a consistent moduleLoader:
export const mouleLoader= {
  token,           // Service token
  loadModule,          // The actual module
};
  • Impact: Eliminates token mismatches and provides a single source of truth for each module's identifiers

2. Type-Safe Dependency Binding

  • Added: New bindModuleToClassOnToken utility function in /packages/lib/di/ioctopus.ts
  • Feature: Automatically ensures all dependencies required by a class are properly provided
  • Type Safety: Uses TypeScript generics to validate that depsMap matches the class's dependency requirements
  • Runtime Safety: Generates automatic dependency loading functions

3. Enhanced Container Management

  • Before: Manual, error-prone dependency loading in each container
  • After: Automatic dependency loading through generated loadDeps functions
  • Example: RegularBookingServiceModule now uses type-safe dependency mapping:
depsMap: {
  cacheService: cacheModuleWithToken,
  checkBookingAndDurationLimitsService: checkBookingAndDurationLimitsModuleWithToken,
  // ... other dependencies
}

@vercel
Copy link
Copy Markdown

vercel bot commented Sep 3, 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 Sep 10, 2025 11:17am
cal-eu Ignored Ignored Sep 10, 2025 11:17am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 3, 2025

Walkthrough

This PR migrates DI imports from the external "@evyweb/ioctopus" to local "../di" and introduces a new helper bindModuleToClassOnToken in packages/lib/di/di.ts. It refactors booking-related DI: moves booking tokens into packages/lib/di/bookings/tokens.ts and spreads them into DI_TOKENS, deletes legacy RegularBookingService DI files under packages/features/bookings, and adds new booking modules/containers under packages/lib/di/bookings (including RegularBookingService.module/container). Multiple modules now export moduleLoader wrappers and several repository modules switch to toClass bindings with Prisma client injection. Prisma’s module now exports a moduleLoader with token/readOnlyToken. Numerous containers update createContainer import paths.

Possibly related PRs

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.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
Title Check ✅ Passed The title concisely highlights the primary focus on improving the ioctopus-based DI flow’s type safety and runtime safety, which aligns with the core changes in the PR around refactoring modules, adding type-safe bindings, and standardizing loaders. Although the bracketed segment includes extra context, the central action—making the DI flow type-safe—is clearly communicated.
Description Check ✅ Passed The description clearly outlines the main refactoring objectives—standardizing moduleLoader exports, introducing the bindModuleToClassOnToken utility for type-safe dependency binding, and enhancing container management—and matches the detailed changes summarized in the diff. It remains fully on-topic and provides concrete examples that reflect the actual modifications in the PR.
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ioctpus-type-and-runtime-safer

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Sep 3, 2025

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "Make ioctopus flow more type-safe and runtime-safe". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Sep 3, 2025
Copy link
Copy Markdown
Member Author

hariombalhara commented Sep 3, 2025

@hariombalhara hariombalhara marked this pull request as ready for review September 3, 2025 09:33
@hariombalhara hariombalhara requested a review from a team as a code owner September 3, 2025 09:33
@graphite-app graphite-app bot requested a review from a team September 3, 2025 09:33
@dosubot dosubot bot added the 💻 refactor label Sep 3, 2025
@hariombalhara hariombalhara changed the title Make ioctopus flow more type-safe and runtime-safe fix: Make ioctopus flow more type-safe and runtime-safe Sep 3, 2025
Copy link
Copy Markdown
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 (21)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (2)

15-19: Make the wrapper readonly to prevent accidental mutation.

Add as const to narrow types and freeze shape.

-export const checkBookingAndDurationLimitsModuleWithToken = {
+export const checkBookingAndDurationLimitsModuleWithToken = {
   token,
   moduleToken,
   module: checkBookingAndDurationLimitsModule,
-};
+} as const;

Nit: consider using the same DI_TOKENS import style used elsewhere (absolute alias) for consistency.


15-19: Centralize the wrapper shape.

Define and reuse a shared ModuleWithToken type to standardize these objects across modules.

Example (in a common DI file):

export type ModuleWithToken = Readonly<{
  token: symbol;
  moduleToken: symbol;
  module: ReturnType<typeof createModule>;
}>;

Then annotate:

export const checkBookingAndDurationLimitsModuleWithToken: ModuleWithToken = { ... } as const;
packages/lib/di/modules/Cache.ts (1)

15-19: Harden the wrapper by marking it readonly.

-export const cacheModuleWithToken = {
+export const cacheModuleWithToken = {
   token,
   moduleToken,
   module: cacheModule,
-};
+} as const;
packages/lib/di/modules/CheckBookingLimits.ts (2)

6-11: Add a minimal compile-time guard on dep keys.

Mirror the pattern used in other modules by asserting the dep-map keys.

-  .bind(token)
-  .toClass(CheckBookingLimitsService, { bookingRepo: DI_TOKENS.BOOKING_REPOSITORY });
+  .bind(token)
+  .toClass(
+    CheckBookingLimitsService,
+    { bookingRepo: DI_TOKENS.BOOKING_REPOSITORY } as const satisfies Record<"bookingRepo", symbol>,
+  );

13-17: Mark the wrapper as const for safety and consistency.

-export const checkBookingLimitsModuleWithToken = {
+export const checkBookingLimitsModuleWithToken = {
   token,
   moduleToken,
   module: checkBookingLimitsModule,
-};
+} as const;
packages/prisma/prisma.module.ts (2)

8-10: Use the local token alias in the binding for consistency.

-const token = DI_TOKENS.PRISMA_CLIENT;
+const token = DI_TOKENS.PRISMA_CLIENT;
 const moduleToken = DI_TOKENS.PRISMA_MODULE;
-prismaModule.bind(DI_TOKENS.PRISMA_CLIENT).toFactory(() => prisma, "singleton");
+prismaModule.bind(token).toFactory(() => prisma, "singleton");

13-17: Apply as const to the wrapper.

-export const prismaModuleWithToken = {
+export const prismaModuleWithToken = {
   token,
   moduleToken,
   module: prismaModule,
-};
+} as const;
packages/lib/di/modules/Booking.ts (2)

9-9: Optional: prefer named deps over positional array (if supported).

Positional arrays couple binding to constructor order. A named map is more resilient to constructor changes.


11-15: Freeze the wrapper with as const.

-export const bookingRepositoryModuleWithToken = {
+export const bookingRepositoryModuleWithToken = {
   token,
   moduleToken,
   module: bookingRepositoryModule,
-};
+} as const;
packages/lib/di/modules/Features.ts (2)

9-9: Prefer using the new type-safe binder + export a loadDeps to preload Prisma.

Leverage bindModuleToClassOnToken for compile-time validation and to auto-generate a deps loader. This keeps the module consistent with others (e.g., RegularBookingService). Adjust the deps key to match FeaturesRepository['deps'].

Example refactor:

 import { DI_TOKENS } from "@calcom/lib/di/tokens";
+import { bindModuleToClassOnToken } from "@calcom/lib/di/ioctopus";
+import { prismaModuleWithToken } from "@calcom/prisma/prisma.module";

 export const featuresRepositoryModule = createModule();
 const token = DI_TOKENS.FEATURES_REPOSITORY;
 const moduleToken = DI_TOKENS.FEATURES_REPOSITORY_MODULE;
-featuresRepositoryModule.bind(token).toClass(FeaturesRepository, [DI_TOKENS.PRISMA_CLIENT]);
+export const loadDeps = bindModuleToClassOnToken({
+  module: featuresRepositoryModule,
+  token,
+  classs: FeaturesRepository,
+  depsMap: {
+    // Replace 'prisma' key if FeaturesRepository.deps uses a different key name
+    prisma: prismaModuleWithToken,
+  },
+});

11-15: Add a shared type for the wrapper to enforce shape.

Export and reuse a ModuleWithToken type (e.g., from @calcom/lib/di/ioctopus) to catch shape drift across modules.

packages/lib/di/ioctopus.ts (4)

24-37: Dial down library-wide console noise; gate logs behind an option.

Unconditional console.log in a shared lib is noisy and may leak internals. Make logging opt-in and switch to console.debug.

Apply:

-  return function loadDeps(container: Container) {
-    console.log("[DI DEBUG] Binding Class to token", token);
-    console.log("[DI DEBUG] Deps Object", depsObject);
-    console.log("[DI DEBUG] Bound Class to token", token);
+  return function loadDeps(container: Container, opts?: { debug?: boolean }) {
+    if (opts?.debug) console.debug("[DI DEBUG] Binding Class to token", token);
+    if (opts?.debug) console.debug("[DI DEBUG] Deps Object", depsObject);
+    if (opts?.debug) console.debug("[DI DEBUG] Bound Class to token", token);
 
-    for (const key in depsMap) {
-      const depToken = depsMap[key as keyof typeof depsMap].moduleToken;
-      const depModule = depsMap[key as keyof typeof depsMap].module;
-      console.log("[DI DEBUG] Loading dependency", depToken, depModule);
-      container.load(depToken, depModule);
-      console.log("[DI DEBUG] Successfully loaded dependency", depToken);
-    }
-    console.log("[DI DEBUG] All dependencies loaded for token", token);
+    for (const { moduleToken: depToken, module: depModule } of Object.values(depsMap)) {
+      if (opts?.debug) console.debug("[DI DEBUG] Loading dependency", depToken);
+      container.load(depToken, depModule);
+      if (opts?.debug) console.debug("[DI DEBUG] Successfully loaded dependency", depToken);
+    }
+    if (opts?.debug) console.debug("[DI DEBUG] All dependencies loaded for token", token);
   };

16-19: Introduce and reuse a ModuleWithToken type for stronger typing.

This avoids repeating the shape and keeps modules consistent.

Apply:

 import type { Container, Module } from "@evyweb/ioctopus";
 
+export type ModuleWithToken = {
+  token: string | symbol;
+  moduleToken: string | symbol;
+  module: Module;
+};
+
 ...
   depsMap: Record<
     keyof InstanceType<TClass>["deps"],
-    { token: string | symbol; moduleToken: string | symbol; module: Module }
+    ModuleWithToken
   >;

7-20: Optional: tighten type constraint on classes expected to have deps.

If all participating classes expose deps, constrain TClass to improve errors when misused. Keep as an overload to avoid breaking existing callers.

Example overload:

type HasDeps = { deps: Record<string | number | symbol, unknown> };
export function bindModuleToClassOnToken<TClass extends new (...args: any[]) => any>(args: {
  module: Module; token: string | symbol; classs: TClass; depsMap: Record<keyof InstanceType<TClass>["deps"], ModuleWithToken>;
}): (container: Container, opts?: { debug?: boolean }) => void;
// Stricter version:
export function bindModuleToClassOnToken<TClass extends new (...args: any[]) => HasDeps>(args: {
  module: Module; token: string | symbol; classs: TClass; depsMap: Record<keyof InstanceType<TClass>["deps"], ModuleWithToken>;
}): (container: Container, opts?: { debug?: boolean }) => void;

29-35: Avoid for..in on objects with unknown prototypes.

Swapping to Object.values(depsMap) prevents accidental iteration over inherited props.

packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (1)

17-17: Load dependencies once at module init, not on every call.

Calling loadDeps per invocation can repeatedly call container.load, which may be non-idempotent and adds overhead.

Apply:

-export function getRegularBookingService(): RegularBookingService {
-  loadRegularBookingServiceModuleDeps(regularBookingServiceContainer);
+// Preload deps once
+loadRegularBookingServiceModuleDeps(regularBookingServiceContainer);
+
+export function getRegularBookingService(): RegularBookingService {

And remove the now-redundant call inside the function.

-  loadRegularBookingServiceModuleDeps(regularBookingServiceContainer);
packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (5)

15-16: Narrow token types with as const (optional).

Helps keep literal types and catch mismatches at compile time.

-const token = DI_TOKENS.REGULAR_BOOKING_SERVICE;
-const moduleToken = DI_TOKENS.REGULAR_BOOKING_SERVICE_MODULE;
+const token = DI_TOKENS.REGULAR_BOOKING_SERVICE as const;
+const moduleToken = DI_TOKENS.REGULAR_BOOKING_SERVICE_MODULE as const;

20-20: "classs" reads like a typo—prefer klass or ctor for clarity.

If bindModuleToClassOnToken accepts an alias, consider this rename to avoid confusion; otherwise, ignore.

-  classs: RegularBookingService,
+  klass: RegularBookingService,

21-28: Freeze depsMap literal for stronger inference.

Adding as const preserves key literals and prevents accidental mutation.

   depsMap: {
     cacheService: cacheModuleWithToken,
     checkBookingAndDurationLimitsService: checkBookingAndDurationLimitsModuleWithToken,
     prismaClient: prismaModuleWithToken,
     bookingRepository: bookingRepositoryModuleWithToken,
     featuresRepository: featuresRepositoryModuleWithToken,
     checkBookingLimitsService: checkBookingLimitsModuleWithToken,
-  },
+  } as const,

31-35: Type-guard the WithToken object.

Lock it down with as const (and optionally satisfies a common ModuleWithToken shape if available).

-const regularBookingServiceModuleWithToken = {
+const regularBookingServiceModuleWithToken = {
   token,
   moduleToken,
   module: regularBookingServiceModule,
-};
+} as const;

Optionally, if a helper type exists:

const regularBookingServiceModuleWithToken = {
  token,
  moduleToken,
  module: regularBookingServiceModule,
} satisfies ModuleWithToken;

31-35: Inline-export the WithToken object to reduce export churn (optional).

Keeps declaration and export together; minor readability win.

-const regularBookingServiceModuleWithToken = {
+export const regularBookingServiceModuleWithToken = {
   token,
   moduleToken,
   module: regularBookingServiceModule,
-};
+};
 
-export { loadDeps, regularBookingServiceModuleWithToken };
+export { loadDeps };

Also applies to: 39-39

📜 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 d6cd593 and 5c34efe.

📒 Files selected for processing (9)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (1 hunks)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (1 hunks)
  • packages/lib/di/ioctopus.ts (1 hunks)
  • packages/lib/di/modules/Booking.ts (1 hunks)
  • packages/lib/di/modules/Cache.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingLimits.ts (1 hunks)
  • packages/lib/di/modules/Features.ts (1 hunks)
  • packages/prisma/prisma.module.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/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/modules/Booking.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/ioctopus.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/lib/di/modules/Cache.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.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/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/modules/Booking.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/ioctopus.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/lib/di/modules/Cache.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.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/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/modules/Booking.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/ioctopus.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/lib/di/modules/Cache.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts
🧬 Code graph analysis (7)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (2)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/features/bookings/lib/handleNewBooking/checkBookingAndDurationLimits.ts (1)
  • ICheckBookingAndDurationLimitsService (17-19)
packages/lib/di/modules/Booking.ts (2)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/lib/server/repository/booking.ts (1)
  • BookingRepository (117-948)
packages/prisma/prisma.module.ts (2)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/prisma/index.ts (1)
  • readonlyPrisma (71-75)
packages/lib/di/modules/Features.ts (1)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/lib/di/modules/CheckBookingLimits.ts (1)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/lib/di/modules/Cache.ts (2)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/features/calendar-cache/lib/getShouldServeCache.ts (1)
  • ICacheService (3-5)
packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (1)
packages/features/bookings/lib/handleNewBooking.ts (1)
  • RegularBookingService (2477-2496)
⏰ 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). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (8)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1)

9-13: Good: token/moduleToken aliases and typed deps mapping.

Local aliases + satisfies guard prevent mismatches and catch key drift at compile time.

packages/lib/di/modules/Cache.ts (1)

9-11: Good: local token/moduleToken aliases.

This aligns with the new standard and avoids cross-file token drift.

packages/lib/di/modules/Features.ts (1)

11-15: Good move: standardized ModuleWithToken wrapper.

This aligns with the new pattern and reduces token drift. Naming is consistent with other modules.

packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (3)

11-14: LGTM: module and token loaded correctly.

Using moduleToken with module is consistent with the new pattern.


19-21: LGTM: retrieval uses the module’s service token.

This keeps the container API stable while switching to the wrapper.


17-17: Verify container.load idempotency
Ensure repeated calls to container.load won’t trigger “module already loaded” errors. If load isn’t inherently idempotent, wrap it in a guard (e.g. check container.has(token) or track loaded modules) before invoking.

packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (2)

3-8: LGTM: Consistent shift to WithToken imports.

Imports align with the new token-wrapped module pattern and improve DI consistency.

Also applies to: 10-10


39-39: All legacy DI patterns removed
No occurrences of loadModuleDeps or direct REGULAR_BOOKING_SERVICE_MODULE imports in consumer code; all bindings use regularBookingServiceModuleWithToken and loadDeps.

Comment on lines -26 to -36
function loadModuleDeps(container: Container) {
container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
container.load(
DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE,
checkBookingAndDurationLimitsModule
);
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
container.load(DI_TOKENS.FEATURES_REPOSITORY_MODULE, featuresRepositoryModule);
container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We don't need to maintain it separately. These are loaded automatically now through loadDeps fn.

Comment on lines +11 to +14
regularBookingServiceContainer.load(
regularBookingServiceModuleWithToken.moduleToken,
regularBookingServiceModuleWithToken.module
);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Just realized, this too could be moved to loadDeps and then we could rename loadDeps to loadModule

@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch from 5c34efe to bbdfd82 Compare September 3, 2025 10:46
@hariombalhara
Copy link
Copy Markdown
Member Author

Simplified the flow further and now we don't need to expose moduleToken. Also now, we export a moduleLoader object consistently.

Copy link
Copy Markdown
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: 0

🧹 Nitpick comments (9)
packages/lib/di/modules/Booking.ts (2)

8-11: Good move to localize tokens; consider using the new helper for type-safety

Bindings look fine. To align with the PR’s goal of type-safe wiring, consider replacing manual bind/toClass with the new bindModuleToClassOnToken utility for compile-time checks on deps.


12-17: Export a single “WithToken” object (token, moduleToken, module, loadModule) for SSoT

Current export exposes only token and loadModule. Including moduleToken and module prevents drift and matches the standardized shape.

Apply:

-export const moduleLoader = {
-  token,
-  loadModule: function (container: Container) {
-    container.load(moduleToken, bookingRepositoryModule);
-  },
-};
+export const bookingRepositoryModuleWithToken = {
+  token,
+  moduleToken,
+  module: bookingRepositoryModule,
+  loadModule(container: Container) {
+    container.load(moduleToken, bookingRepositoryModule);
+  },
+};
+// Back-compat alias if callers expect `moduleLoader`
+export const moduleLoader = bookingRepositoryModuleWithToken;
packages/lib/di/modules/CheckBookingLimits.ts (2)

11-12: Add a “satisfies” guard to lock deps map to the service’s contract

Mirror the pattern used in CheckBookingAndDurationLimits to avoid runtime key mismatches.

Apply (adjust interface name if different):

-  .bind(token)
-  .toClass(CheckBookingLimitsService, { bookingRepo: DI_TOKENS.BOOKING_REPOSITORY });
+  .bind(token)
+  .toClass(
+    CheckBookingLimitsService,
+    { bookingRepo: DI_TOKENS.BOOKING_REPOSITORY }
+      satisfies Record<keyof ICheckBookingLimitsService, symbol>
+  );

If no interface exists, I can add a minimal ICheckBookingLimitsService type and wire it up. Want me to push that?


14-19: Export the unified “WithToken” object (include moduleToken and module)

Brings this module in line with the standardized export shape and prevents token/module divergence.

-export const moduleLoader = {
-  token,
-  loadModule: (container: Container) => {
-    container.load(moduleToken, checkBookingLimitsModule);
-  },
-};
+export const checkBookingLimitsModuleWithToken = {
+  token,
+  moduleToken,
+  module: checkBookingLimitsModule,
+  loadModule(container: Container) {
+    container.load(moduleToken, checkBookingLimitsModule);
+  },
+};
+export const moduleLoader = checkBookingLimitsModuleWithToken;
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1)

16-21: Standardize on “WithToken” export shape

Expose moduleToken and module alongside token and loadModule for consistency and easier introspection.

-export const moduleLoader = {
-  token,
-  loadModule: (container: Container) => {
-    container.load(moduleToken, checkBookingAndDurationLimitsModule);
-  },
-};
+export const checkBookingAndDurationLimitsModuleWithToken = {
+  token,
+  moduleToken,
+  module: checkBookingAndDurationLimitsModule,
+  loadModule(container: Container) {
+    container.load(moduleToken, checkBookingAndDurationLimitsModule);
+  },
+};
+export const moduleLoader = checkBookingAndDurationLimitsModuleWithToken;
packages/prisma/prisma.module.ts (1)

14-19: Expose read-only client via its own loader and include module/moduleToken for SSoT

Some modules depend on READ_ONLY_PRISMA_CLIENT; giving it a loader keeps the API symmetric and prevents ad-hoc token references. Also export module and moduleToken.

-export const moduleLoader = {
-  token,
-  loadModule: (container: Container) => {
-    container.load(moduleToken, prismaModule);
-  },
-};
+export const prismaModuleWithToken = {
+  token,
+  moduleToken,
+  module: prismaModule,
+  loadModule(container: Container) {
+    container.load(moduleToken, prismaModule);
+  },
+};
+export const moduleLoader = prismaModuleWithToken;
+
+export const readOnlyPrismaModuleLoader = {
+  token: DI_TOKENS.READ_ONLY_PRISMA_CLIENT,
+  loadModule(container: Container) {
+    container.load(moduleToken, prismaModule);
+  },
+};

If you prefer a single export, we can also expose tokens: [DI_TOKENS.PRISMA_CLIENT, DI_TOKENS.READ_ONLY_PRISMA_CLIENT] on prismaModuleWithToken and keep one loader.

packages/lib/di/modules/Features.ts (1)

12-17: Adopt the unified “WithToken” export (add moduleToken and module)

Keeps exports consistent and future-proof.

-export const moduleLoader = {
-  token,
-  loadModule: (container: Container) => {
-    container.load(moduleToken, featuresRepositoryModule);
-  },
-};
+export const featuresRepositoryModuleWithToken = {
+  token,
+  moduleToken,
+  module: featuresRepositoryModule,
+  loadModule(container: Container) {
+    container.load(moduleToken, featuresRepositoryModule);
+  },
+};
+export const moduleLoader = featuresRepositoryModuleWithToken;
packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (2)

17-21: Confirm bindModuleToClassOnToken option name: classs

Is the option intentionally spelled classs in the util’s signature? If the util expects klass/classRef/Class, this will fail type-checking at call sites. Please verify the util’s param name and adjust here for consistency.


32-35: Export the standardized ModuleWithToken shape (token + moduleToken + module) and alias moduleLoader

Other modules expose a unified object with token, moduleToken, and module, plus a moduleLoader alias. This file currently omits moduleToken and module, and only exports regularBookingServiceModule. For cross-module consistency and single source of truth, export the full shape and an alias.

Apply:

 export const regularBookingServiceModule = {
   token,
+  moduleToken,
+  module: thisModule,
   loadModule,
 };
+
+// For import consistency with other modules:
+export const moduleLoader = regularBookingServiceModule;
📜 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 5c34efe and bbdfd82.

📒 Files selected for processing (9)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (1 hunks)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (1 hunks)
  • packages/lib/di/ioctopus.ts (1 hunks)
  • packages/lib/di/modules/Booking.ts (1 hunks)
  • packages/lib/di/modules/Cache.ts (2 hunks)
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts (2 hunks)
  • packages/lib/di/modules/CheckBookingLimits.ts (1 hunks)
  • packages/lib/di/modules/Features.ts (1 hunks)
  • packages/prisma/prisma.module.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/lib/di/modules/Cache.ts
  • packages/lib/di/ioctopus.ts
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts
🧰 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/lib/di/modules/Booking.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.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/lib/di/modules/Booking.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.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/lib/di/modules/Booking.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.149Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.
📚 Learning: 2025-09-03T09:52:51.149Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.149Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
🧬 Code graph analysis (4)
packages/lib/di/modules/Features.ts (2)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/lib/di/modules/Cache.ts (1)
  • moduleLoader (16-21)
packages/lib/di/modules/CheckBookingLimits.ts (3)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/lib/di/modules/Cache.ts (1)
  • moduleLoader (16-21)
packages/prisma/prisma.module.ts (1)
  • moduleLoader (14-19)
packages/prisma/prisma.module.ts (6)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/prisma/index.ts (1)
  • readonlyPrisma (71-75)
packages/lib/di/modules/Cache.ts (1)
  • moduleLoader (16-21)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1)
  • moduleLoader (16-21)
packages/lib/di/modules/CheckBookingLimits.ts (1)
  • moduleLoader (14-19)
packages/lib/di/modules/Features.ts (1)
  • moduleLoader (12-17)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (3)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/features/bookings/lib/handleNewBooking/checkBookingAndDurationLimits.ts (1)
  • ICheckBookingAndDurationLimitsService (17-19)
packages/lib/di/modules/CheckBookingLimits.ts (1)
  • moduleLoader (14-19)
⏰ 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
🔇 Additional comments (6)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (2)

10-15: Nice: typed deps map with satisfies

This ensures the map keys stay in sync with ICheckBookingAndDurationLimitsService.


7-7: Retain relative import for DI_TOKENS in library modules
The lib package’s tsconfig has no @calcom/lib path mapping, so import { DI_TOKENS } from "../tokens" correctly resolves a single instance. Switching to an alias would break the library build.

Likely an incorrect or invalid review comment.

packages/prisma/prisma.module.ts (1)

11-12: Bindings look correct and scoped singleton is appropriate

Both prisma and readonlyPrisma registrations LGTM.

packages/lib/di/modules/Features.ts (1)

10-10: OK: binding via localized token and PRISMA dependency

Looks consistent with the pattern.

packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (2)

3-10: Imports look consistent with the new moduleLoader pattern

Using named moduleLoader imports across dependencies aligns with the PR’s DI approach.


22-29: Deps map matches IBookingServiceDependencies

All six deps align with the interface used by RegularBookingService. Good.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Sep 3, 2025

E2E results are ready!

@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch from bbdfd82 to 7fd53d0 Compare September 9, 2025 08:34
@graphite-app graphite-app bot requested a review from a team September 9, 2025 08:34
@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch from 7fd53d0 to ccda9ce Compare September 9, 2025 08:39
Copy link
Copy Markdown
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: 3

Caution

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

⚠️ Outside diff range comments (5)
packages/lib/di/modules/Membership.ts (1)

6-10: Export a moduleLoader to align with the new standard module shape.

PR objective says modules should export { token, loadModule }. This file only exports the module; add the loader to keep consumers consistent.

Apply:

 export const membershipRepositoryModule = createModule();
 membershipRepositoryModule
   .bind(DI_TOKENS.MEMBERSHIP_REPOSITORY)
   .toClass(MembershipRepository, [DI_TOKENS.PRISMA_CLIENT]);
 
+export const membershipRepositoryModuleLoader = {
+  token: DI_TOKENS.MEMBERSHIP_REPOSITORY,
+  loadModule: () => membershipRepositoryModule,
+};

If there’s a shared helper (e.g., moduleLoader() in ../di), prefer that for consistency.

packages/lib/di/modules/QualifiedHosts.ts (1)

6-11: Export a moduleLoader to align with the new standard module shape.

This module doesn’t expose moduleLoader yet. Add it so containers can load it consistently via container.load(moduleToken, module) behind a stable API.

Apply this diff:

@@
-import { createModule } from "../di";
+import type { Container } from "../di";
+import { createModule } from "../di";
@@
 } satisfies Record<keyof IQualifiedHostsService, symbol>);
+
+const token = DI_TOKENS.QUALIFIED_HOSTS_SERVICE;
+const moduleToken = DI_TOKENS.QUALIFIED_HOSTS_SERVICE_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, qualifiedHostsModule);
+  },
+};
packages/lib/di/modules/GetUserAvailability.ts (1)

6-12: Expose moduleLoader for consistency and runtime-safe loading.

Publish the standard { token, loadModule } so containers don’t have to import the raw module.

Apply this diff:

@@
-import { createModule } from "../di";
+import type { Container } from "../di";
+import { createModule } from "../di";
@@
 } satisfies Record<keyof IUserAvailabilityService, symbol>);
+
+const token = DI_TOKENS.GET_USER_AVAILABILITY_SERVICE;
+const moduleToken = DI_TOKENS.GET_USER_AVAILABILITY_SERVICE_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, getUserAvailabilityModule);
+  },
+};
packages/lib/di/modules/RoutingFormResponse.ts (1)

6-9: Export moduleLoader to standardize loading.

Add the { token, loadModule } wrapper so containers don’t import the raw module directly.

Apply this diff:

@@
-import { createModule } from "../di";
+import type { Container } from "../di";
+import { createModule } from "../di";
@@
   .bind(DI_TOKENS.ROUTING_FORM_RESPONSE_REPOSITORY)
   .toClass(RoutingFormResponseRepository, [DI_TOKENS.PRISMA_CLIENT]);
+
+const token = DI_TOKENS.ROUTING_FORM_RESPONSE_REPOSITORY;
+const moduleToken = DI_TOKENS.ROUTING_FORM_RESPONSE_REPOSITORY_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, routingFormResponseRepositoryModule);
+  },
+};
packages/lib/di/modules/InsightsBooking.ts (1)

7-10: Expose moduleLoader for InsightsBooking.

Publish the standard loader so containers can adopt the unified loading flow.

Apply this diff:

@@
-import { createModule } from "../di";
+import type { Container } from "../di";
+import { createModule } from "../di";
@@
 } satisfies Record<keyof IInsightsBookingService, symbol>);
+
+const token = DI_TOKENS.INSIGHTS_BOOKING_SERVICE;
+const moduleToken = DI_TOKENS.INSIGHTS_BOOKING_SERVICE_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, insightsBookingModule);
+  },
+};
🧹 Nitpick comments (5)
packages/lib/di/modules/EventType.ts (1)

6-9: Export a standardized moduleLoader to match the new convention.

Per this PR’s objective, modules should export { token, loadModule }. This file currently exposes only eventTypeRepositoryModule. Recommend adding a moduleLoader export (keep the existing export for backwards compatibility).

 export const eventTypeRepositoryModule = createModule();
 eventTypeRepositoryModule
   .bind(DI_TOKENS.EVENT_TYPE_REPOSITORY)
   .toClass(EventTypeRepository, [DI_TOKENS.PRISMA_CLIENT]);
 
+// Standardized loader export to align with repo-wide convention
+export const eventTypeRepositoryModuleLoader = {
+  token: DI_TOKENS.EVENT_TYPE_REPOSITORY,
+  loadModule: async () => eventTypeRepositoryModule,
+};

Please confirm downstream code expects moduleLoader here as with other modules in this PR.

packages/lib/di/modules/Team.ts (1)

6-7: Add moduleLoader export to Team.ts for consistent DI pattern
Other modules under packages/lib/di/modules expose both token and loadModule; Team.ts currently only exports teamRepositoryModule. Retain the existing export for back-compat and append the loader wrapper:

 export const teamRepositoryModule = createModule();
 teamRepositoryModule
   .bind(DI_TOKENS.TEAM_REPOSITORY)
   .toClass(TeamRepository, [DI_TOKENS.PRISMA_CLIENT]);

+// New uniform entrypoint (non-breaking)
+export const moduleLoader = {
+  token: DI_TOKENS.TEAM_REPOSITORY,
+  loadModule: async () => teamRepositoryModule,
+};
packages/lib/di/containers/BookingLimits.ts (2)

12-18: Use moduleLoader.token instead of DI_TOKENS to avoid duplication

Leverage the module’s single source of truth for its token; removes drift risk and matches the standardized moduleLoader shape.

- container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
- container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
- container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
- container.load(
-   DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE,
-   checkBookingAndDurationLimitsModule
- );
+ container.load(prismaModule.token, prismaModule);
+ container.load(bookingRepositoryModule.token, bookingRepositoryModule);
+ container.load(checkBookingLimitsModule.token, checkBookingLimitsModule);
+ container.load(
+   checkBookingAndDurationLimitsModule.token,
+   checkBookingAndDurationLimitsModule
+ );

20-28: Annotate return types on public getters

Makes the public surface explicit and resilient to inference regressions.

-export function getCheckBookingLimitsService() {
+export function getCheckBookingLimitsService(): CheckBookingLimitsService {
   return container.get<CheckBookingLimitsService>(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE);
 }

-export function getCheckBookingAndDurationLimitsService() {
+export function getCheckBookingAndDurationLimitsService(): CheckBookingAndDurationLimitsService {
   return container.get<CheckBookingAndDurationLimitsService>(
     DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE
   );
 }
packages/lib/di/modules/RoutingFormResponse.ts (1)

7-9: Prefer named DI map over positional injection for type-safety.

If the repository supports named deps, switch to an object map with satisfies to catch mismatches at compile time. If not, keep as-is.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 7fd53d0 and ccda9ce.

📒 Files selected for processing (46)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (0 hunks)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (0 hunks)
  • packages/features/redis/di/redisModule.ts (1 hunks)
  • packages/lib/di/containers/AvailableSlots.ts (1 hunks)
  • packages/lib/di/containers/BookingLimits.ts (1 hunks)
  • packages/lib/di/containers/BusyTimes.ts (1 hunks)
  • packages/lib/di/containers/Cache.ts (1 hunks)
  • packages/lib/di/containers/FilterHosts.ts (1 hunks)
  • packages/lib/di/containers/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/containers/InsightsBooking.ts (1 hunks)
  • packages/lib/di/containers/InsightsRouting.ts (1 hunks)
  • packages/lib/di/containers/LuckyUser.ts (1 hunks)
  • packages/lib/di/containers/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/containers/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/containers/bookings/InstantBookingCreateServiceContainer.ts (1 hunks)
  • packages/lib/di/containers/bookings/RecurringBookingServiceContainer.ts (1 hunks)
  • packages/lib/di/containers/bookings/RegularBookingServiceContainer.ts (1 hunks)
  • packages/lib/di/di.ts (1 hunks)
  • packages/lib/di/modules/Attribute.ts (1 hunks)
  • packages/lib/di/modules/AvailableSlots.ts (1 hunks)
  • packages/lib/di/modules/Booking.ts (1 hunks)
  • packages/lib/di/modules/BusyTimes.ts (1 hunks)
  • packages/lib/di/modules/Cache.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingLimits.ts (1 hunks)
  • packages/lib/di/modules/EventType.ts (1 hunks)
  • packages/lib/di/modules/Features.ts (1 hunks)
  • packages/lib/di/modules/FilterHosts.ts (1 hunks)
  • packages/lib/di/modules/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/modules/Host.ts (1 hunks)
  • packages/lib/di/modules/InsightsBooking.ts (1 hunks)
  • packages/lib/di/modules/InsightsRouting.ts (1 hunks)
  • packages/lib/di/modules/LuckyUser.ts (1 hunks)
  • packages/lib/di/modules/Membership.ts (1 hunks)
  • packages/lib/di/modules/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/modules/Ooo.ts (1 hunks)
  • packages/lib/di/modules/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/modules/RoutingFormResponse.ts (1 hunks)
  • packages/lib/di/modules/Schedule.ts (1 hunks)
  • packages/lib/di/modules/SelectedSlots.ts (1 hunks)
  • packages/lib/di/modules/Team.ts (1 hunks)
  • packages/lib/di/modules/User.ts (1 hunks)
  • packages/lib/di/modules/bookings/InstantBookingCreateServiceModule.ts (1 hunks)
  • packages/lib/di/modules/bookings/RecurringBookingServiceModule.ts (1 hunks)
  • packages/lib/di/modules/bookings/RegularBookingServiceModule.ts (1 hunks)
  • packages/prisma/prisma.module.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/features/redis/di/redisModule.ts
🚧 Files skipped from review as they are similar to previous changes (33)
  • packages/lib/di/modules/NoSlotsNotification.ts
  • packages/lib/di/containers/NoSlotsNotification.ts
  • packages/lib/di/modules/bookings/RegularBookingServiceModule.ts
  • packages/lib/di/containers/FilterHosts.ts
  • packages/lib/di/containers/QualifiedHosts.ts
  • packages/lib/di/modules/BusyTimes.ts
  • packages/lib/di/containers/Cache.ts
  • packages/lib/di/modules/AvailableSlots.ts
  • packages/lib/di/containers/InsightsRouting.ts
  • packages/lib/di/modules/InsightsRouting.ts
  • packages/lib/di/modules/LuckyUser.ts
  • packages/lib/di/containers/bookings/InstantBookingCreateServiceContainer.ts
  • packages/lib/di/containers/AvailableSlots.ts
  • packages/lib/di/modules/bookings/RecurringBookingServiceModule.ts
  • packages/lib/di/modules/FilterHosts.ts
  • packages/lib/di/modules/bookings/InstantBookingCreateServiceModule.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/modules/Booking.ts
  • packages/lib/di/containers/GetUserAvailability.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/containers/BusyTimes.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/bookings/RegularBookingServiceContainer.ts
  • packages/lib/di/modules/SelectedSlots.ts
  • packages/lib/di/di.ts
  • packages/lib/di/modules/Ooo.ts
  • packages/lib/di/modules/Attribute.ts
  • packages/lib/di/modules/Cache.ts
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/containers/bookings/RecurringBookingServiceContainer.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/Schedule.ts
🧰 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/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/modules/Team.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/RoutingFormResponse.ts
  • packages/lib/di/modules/QualifiedHosts.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/Membership.ts
  • packages/lib/di/containers/BookingLimits.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/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/modules/Team.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/RoutingFormResponse.ts
  • packages/lib/di/modules/QualifiedHosts.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/Membership.ts
  • packages/lib/di/containers/BookingLimits.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/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/modules/Team.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/RoutingFormResponse.ts
  • packages/lib/di/modules/QualifiedHosts.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/Membership.ts
  • packages/lib/di/containers/BookingLimits.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/containers/BookingLimits.ts
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • packages/lib/di/modules/EventType.ts
🧬 Code graph analysis (1)
packages/prisma/prisma.module.ts (8)
packages/lib/di/di.ts (2)
  • createModule (38-38)
  • Container (38-38)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/prisma/index.ts (1)
  • readonlyPrisma (71-75)
packages/lib/di/modules/Booking.ts (1)
  • moduleLoader (12-17)
packages/lib/di/modules/Cache.ts (1)
  • moduleLoader (15-20)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1)
  • moduleLoader (15-20)
packages/lib/di/modules/CheckBookingLimits.ts (1)
  • moduleLoader (14-19)
packages/lib/di/modules/Features.ts (1)
  • moduleLoader (12-17)
⏰ 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). (2)
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build API v1
🔇 Additional comments (8)
packages/lib/di/modules/EventType.ts (1)

4-5: Good swap to local DI entrypoint.

Importing createModule from the local DI consolidates dependencies and matches the PR direction.

packages/lib/di/modules/Membership.ts (1)

4-5: Local DI import verification complete. createModule is correctly re-exported in packages/lib/di/di.ts, and there are no remaining @evyweb/ioctopus imports.

packages/lib/di/modules/Team.ts (1)

4-4: Good switch to local DI entrypoint.

Importing createModule from the local ../di aligns with the PR direction and removes the external dependency.

packages/lib/di/modules/QualifiedHosts.ts (1)

3-3: Local DI entrypoint import change looks good.

packages/lib/di/modules/GetUserAvailability.ts (1)

3-3: Local DI entrypoint import change looks good.

packages/lib/di/modules/RoutingFormResponse.ts (1)

4-4: Switch to local DI import looks good.

packages/prisma/prisma.module.ts (1)

1-2: Local DI import and Container typing are correct.

packages/lib/di/modules/InsightsBooking.ts (1)

4-4: Local DI import looks good.

@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch from ccda9ce to fd8e133 Compare September 9, 2025 08:55
@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch from fd8e133 to 8d57e82 Compare September 9, 2025 09:04
Copy link
Copy Markdown
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

Caution

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

⚠️ Outside diff range comments (3)
packages/lib/di/modules/GetUserAvailability.ts (1)

6-12: Export a moduleLoader to match the new standardized pattern.

Per PR objectives, modules should expose { token, loadModule }. Add a moduleLoader here so downstream code can uniformly consume it.

 import type { IUserAvailabilityService } from "../../getUserAvailability";
 import { UserAvailabilityService } from "../../getUserAvailability";
 import { createModule } from "../di";
 import { DI_TOKENS } from "../tokens";

 export const getUserAvailabilityModule = createModule();
 getUserAvailabilityModule.bind(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE).toClass(UserAvailabilityService, {
   oooRepo: DI_TOKENS.OOO_REPOSITORY,
   bookingRepo: DI_TOKENS.BOOKING_REPOSITORY,
   eventTypeRepo: DI_TOKENS.EVENT_TYPE_REPOSITORY,
   redisClient: DI_TOKENS.REDIS_CLIENT,
 } satisfies Record<keyof IUserAvailabilityService, symbol>);
 
+// New standardized export for loader-based consumption
+export const getUserAvailabilityModuleLoader = {
+  token: DI_TOKENS.GET_USER_AVAILABILITY_SERVICE,
+  async loadModule() {
+    const mod = createModule();
+    mod.bind(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE).toClass(UserAvailabilityService, {
+      oooRepo: DI_TOKENS.OOO_REPOSITORY,
+      bookingRepo: DI_TOKENS.BOOKING_REPOSITORY,
+      eventTypeRepo: DI_TOKENS.EVENT_TYPE_REPOSITORY,
+      redisClient: DI_TOKENS.REDIS_CLIENT,
+    } satisfies Record<keyof IUserAvailabilityService, symbol>);
+    return mod;
+  },
+};
packages/lib/di/modules/NoSlotsNotification.ts (1)

4-12: Adopt moduleLoader + bindModuleToClassOnToken; stop using createModule.bind(...)

This module still uses createModule and manual bind, which diverges from the PR’s standardized “export a moduleLoader { token, loadModule }” pattern and misses the runtime-safety guarantees from bindModuleToClassOnToken.

Apply:

-import { createModule } from "../di";
+import { bindModuleToClassOnToken } from "../di";
 import { DI_TOKENS } from "../tokens";

-export const noSlotsNotificationModule = createModule();
-noSlotsNotificationModule.bind(DI_TOKENS.NO_SLOTS_NOTIFICATION_SERVICE).toClass(NoSlotsNotificationService, {
-  teamRepo: DI_TOKENS.TEAM_REPOSITORY,
-  membershipRepo: DI_TOKENS.MEMBERSHIP_REPOSITORY,
-  redisClient: DI_TOKENS.REDIS_CLIENT,
-} satisfies Record<keyof INoSlotsNotificationService, symbol>);
+export const noSlotsNotificationModuleWithToken = {
+  token: DI_TOKENS.NO_SLOTS_NOTIFICATION_SERVICE,
+  loadModule: () =>
+    bindModuleToClassOnToken(
+      DI_TOKENS.NO_SLOTS_NOTIFICATION_SERVICE,
+      NoSlotsNotificationService,
+      {
+        teamRepo: DI_TOKENS.TEAM_REPOSITORY,
+        membershipRepo: DI_TOKENS.MEMBERSHIP_REPOSITORY,
+        redisClient: DI_TOKENS.REDIS_CLIENT,
+      } satisfies Record<keyof INoSlotsNotificationService, symbol>
+    ),
+} as const;
  • If other modules use “ModuleWithToken” naming, keep that for consistency; otherwise, rename to whatever convention this PR adopted globally.
packages/lib/di/modules/LuckyUser.ts (1)

6-13: Export standardized moduleLoader
In packages/lib/di/modules/LuckyUser.ts, add:

import { type Container } from "../di";

export const moduleLoader = {
  token: DI_TOKENS.LUCKY_USER_SERVICE,
  loadModule(container: Container) {
    container.load(DI_TOKENS.LUCKY_USER_SERVICE_MODULE, luckyUserServiceModule);
  },
} as const;

No existing code imports moduleLoader from this module.

🧹 Nitpick comments (9)
packages/lib/di/containers/FilterHosts.ts (3)

2-12: Align loads with the new moduleLoader pattern.

Per PR objectives, modules now export a { token, loadModule } moduleLoader. Prefer container.load(moduleLoader) over (token, module) to keep consistency and leverage the standardized shape.

Apply this refactor (adjust names if your modules re-export moduleLoader under a different alias):

-import { prismaModule } from "@calcom/prisma/prisma.module";
+import { moduleLoader as prismaModuleLoader } from "@calcom/prisma/prisma.module";
@@
-import { bookingRepositoryModule } from "../modules/Booking";
-import { filterHostsModule } from "../modules/FilterHosts";
+import { moduleLoader as bookingRepositoryModuleLoader } from "../modules/Booking";
+import { moduleLoader as filterHostsModuleLoader } from "../modules/FilterHosts";
@@
-const container = createContainer();
-container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
-container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
-container.load(DI_TOKENS.FILTER_HOSTS_SERVICE_MODULE, filterHostsModule);
+const container = createContainer();
+container.load(prismaModuleLoader);
+container.load(bookingRepositoryModuleLoader);
+container.load(filterHostsModuleLoader);

9-16: Optional: lazy-init the container for testability and to avoid side effects at import time.

Defers wiring until needed and makes it easier to reset between tests.

-const container = createContainer();
-container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
-container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
-container.load(DI_TOKENS.FILTER_HOSTS_SERVICE_MODULE, filterHostsModule);
-
-export function getFilterHostsService() {
-  return container.get<FilterHostsService>(DI_TOKENS.FILTER_HOSTS_SERVICE);
-}
+let _container: ReturnType<typeof createContainer> | null = null;
+
+export function getFilterHostsService() {
+  if (!_container) {
+    _container = createContainer();
+    // Use moduleLoader-based loads if available
+    // _container.load(prismaModuleLoader);
+    // _container.load(bookingRepositoryModuleLoader);
+    // _container.load(filterHostsModuleLoader);
+    // If still on (token, module), keep the original three loads here.
+  }
+  return _container.get<FilterHostsService>(DI_TOKENS.FILTER_HOSTS_SERVICE);
+}

1-16: Standardize module export/loading conventions across DI containers

  • FilterHosts module doesn’t export a moduleLoader (whereas Booking, Cache, etc. do); either add a moduleLoader export to FilterHosts.ts or remove the unused moduleLoader exports from the other modules.
  • Decide on—and apply—one loading pattern repo-wide: use either the one-arg container.load(moduleLoader) approach or the two-arg container.load(token, module) style (including for prismaModule).
packages/lib/di/modules/Team.ts (1)

6-7: Export a standardized moduleLoader alongside the module to match PR’s unified pattern.

Keeps current export while enabling the new loader-based flow everywhere.

Apply:

 export const teamRepositoryModule = createModule();
 teamRepositoryModule.bind(DI_TOKENS.TEAM_REPOSITORY).toClass(TeamRepository, [DI_TOKENS.PRISMA_CLIENT]);
 
+// PR convention: every module exports a { token, loadModule } loader
+export const moduleLoader = {
+  token: DI_TOKENS.TEAM_REPOSITORY,
+  loadModule: () => teamRepositoryModule,
+};
packages/lib/di/modules/GetUserAvailability.ts (1)

6-12: Optional: adopt bindModuleToClassOnToken for stronger type/runtime safety.

To align with the new DI utility, consider wiring via bindModuleToClassOnToken(...) from ../di so the depsMap is generically validated and loadDeps is auto-generated. I can provide a patch once we confirm the exact helper signature exported by ../di.

packages/lib/di/containers/Cache.ts (2)

1-12: Adopt moduleLoader pattern to decouple from DI_TOKENS and standardize loading

Use each module’s moduleLoader.{loadModule, token} instead of loading by DI_TOKENS._MODULE and getting by DI_TOKENS.. This aligns with the PR’s “single source of truth” and avoids token drift.

-import { DI_TOKENS } from "@calcom/lib/di/tokens";
-import { prismaModule } from "@calcom/prisma/prisma.module";
+import { moduleLoader as prismaModuleWithToken } from "@calcom/prisma/prisma.module";

 import type { CacheService } from "../../../features/calendar-cache/lib/getShouldServeCache";
 import { createContainer } from "../di";
-import { cacheModule } from "../modules/Cache";
-import { featuresRepositoryModule } from "../modules/Features";
+import { moduleLoader as cacheModuleWithToken } from "../modules/Cache";
+import { moduleLoader as featuresRepositoryModuleWithToken } from "../modules/Features";

 const container = createContainer();
-container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
-container.load(DI_TOKENS.FEATURES_REPOSITORY_MODULE, featuresRepositoryModule);
-container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
+prismaModuleWithToken.loadModule(container);
+featuresRepositoryModuleWithToken.loadModule(container);
+cacheModuleWithToken.loadModule(container);

14-16: Get by moduleLoader.token and annotate return type

Minor consistency and typing polish.

-export function getCacheService() {
-  return container.get<CacheService>(DI_TOKENS.CACHE_SERVICE);
+export function getCacheService(): CacheService {
+  return container.get<CacheService>(cacheModuleWithToken.token);
 }
packages/lib/di/modules/Features.ts (2)

11-16: Freeze moduleLoader for immutability and stronger inference

Tiny hardening: mark the loader object immutable.

 export const moduleLoader = {
   token,
   loadModule: (container: Container) => {
     container.load(moduleToken, featuresRepositoryModule);
   },
-};
+} as const;

9-9: Use bindModuleToClassOnToken for type-checked dependencies

Import the helper from "../di" and replace:

featuresRepositoryModule.bind(token).toClass(FeaturesRepository, [DI_TOKENS.PRISMA_CLIENT]);

with:

import { bindModuleToClassOnToken } from "../di";

const loadModule = bindModuleToClassOnToken({
  module: featuresRepositoryModule,
  token,
  class: FeaturesRepository,
  deps: [DI_TOKENS.PRISMA_CLIENT],
});

This enforces compile-time validation of constructor deps and sets up auto-loading hooks.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 fd8e133 and 8d57e82.

📒 Files selected for processing (46)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (0 hunks)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (0 hunks)
  • packages/features/redis/di/redisModule.ts (1 hunks)
  • packages/lib/di/containers/AvailableSlots.ts (1 hunks)
  • packages/lib/di/containers/BookingLimits.ts (1 hunks)
  • packages/lib/di/containers/BusyTimes.ts (1 hunks)
  • packages/lib/di/containers/Cache.ts (1 hunks)
  • packages/lib/di/containers/FilterHosts.ts (1 hunks)
  • packages/lib/di/containers/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/containers/InsightsBooking.ts (1 hunks)
  • packages/lib/di/containers/InsightsRouting.ts (1 hunks)
  • packages/lib/di/containers/LuckyUser.ts (1 hunks)
  • packages/lib/di/containers/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/containers/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/containers/bookings/InstantBookingCreateServiceContainer.ts (1 hunks)
  • packages/lib/di/containers/bookings/RecurringBookingServiceContainer.ts (1 hunks)
  • packages/lib/di/containers/bookings/RegularBookingServiceContainer.ts (1 hunks)
  • packages/lib/di/di.ts (1 hunks)
  • packages/lib/di/modules/Attribute.ts (1 hunks)
  • packages/lib/di/modules/AvailableSlots.ts (1 hunks)
  • packages/lib/di/modules/Booking.ts (1 hunks)
  • packages/lib/di/modules/BusyTimes.ts (1 hunks)
  • packages/lib/di/modules/Cache.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingLimits.ts (1 hunks)
  • packages/lib/di/modules/EventType.ts (1 hunks)
  • packages/lib/di/modules/Features.ts (1 hunks)
  • packages/lib/di/modules/FilterHosts.ts (1 hunks)
  • packages/lib/di/modules/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/modules/Host.ts (1 hunks)
  • packages/lib/di/modules/InsightsBooking.ts (1 hunks)
  • packages/lib/di/modules/InsightsRouting.ts (1 hunks)
  • packages/lib/di/modules/LuckyUser.ts (1 hunks)
  • packages/lib/di/modules/Membership.ts (1 hunks)
  • packages/lib/di/modules/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/modules/Ooo.ts (1 hunks)
  • packages/lib/di/modules/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/modules/RoutingFormResponse.ts (1 hunks)
  • packages/lib/di/modules/Schedule.ts (1 hunks)
  • packages/lib/di/modules/SelectedSlots.ts (1 hunks)
  • packages/lib/di/modules/Team.ts (1 hunks)
  • packages/lib/di/modules/User.ts (1 hunks)
  • packages/lib/di/modules/bookings/InstantBookingCreateServiceModule.ts (1 hunks)
  • packages/lib/di/modules/bookings/RecurringBookingServiceModule.ts (1 hunks)
  • packages/lib/di/modules/bookings/RegularBookingServiceModule.ts (1 hunks)
  • packages/prisma/prisma.module.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts
🚧 Files skipped from review as they are similar to previous changes (36)
  • packages/lib/di/containers/QualifiedHosts.ts
  • packages/features/redis/di/redisModule.ts
  • packages/lib/di/containers/AvailableSlots.ts
  • packages/lib/di/modules/InsightsRouting.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/modules/SelectedSlots.ts
  • packages/lib/di/containers/bookings/RegularBookingServiceContainer.ts
  • packages/lib/di/modules/FilterHosts.ts
  • packages/lib/di/containers/BusyTimes.ts
  • packages/lib/di/containers/NoSlotsNotification.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/bookings/InstantBookingCreateServiceContainer.ts
  • packages/lib/di/modules/Booking.ts
  • packages/lib/di/modules/bookings/InstantBookingCreateServiceModule.ts
  • packages/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/containers/bookings/RecurringBookingServiceContainer.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/lib/di/modules/Ooo.ts
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/modules/Attribute.ts
  • packages/lib/di/containers/InsightsRouting.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/modules/bookings/RecurringBookingServiceModule.ts
  • packages/lib/di/modules/RoutingFormResponse.ts
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/di.ts
  • packages/lib/di/modules/Membership.ts
  • packages/lib/di/modules/bookings/RegularBookingServiceModule.ts
  • packages/lib/di/modules/AvailableSlots.ts
  • packages/lib/di/containers/BookingLimits.ts
  • packages/lib/di/modules/BusyTimes.ts
  • packages/lib/di/containers/GetUserAvailability.ts
  • packages/lib/di/modules/QualifiedHosts.ts
  • packages/lib/di/modules/Cache.ts
  • packages/lib/di/modules/Schedule.ts
🧰 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/lib/di/modules/Team.ts
  • packages/lib/di/containers/Cache.ts
  • packages/lib/di/containers/FilterHosts.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/NoSlotsNotification.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/LuckyUser.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/lib/di/modules/Team.ts
  • packages/lib/di/containers/Cache.ts
  • packages/lib/di/containers/FilterHosts.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/NoSlotsNotification.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/LuckyUser.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/lib/di/modules/Team.ts
  • packages/lib/di/containers/Cache.ts
  • packages/lib/di/containers/FilterHosts.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/NoSlotsNotification.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/LuckyUser.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • packages/lib/di/modules/EventType.ts
🧬 Code graph analysis (1)
packages/lib/di/modules/Features.ts (3)
packages/lib/di/di.ts (2)
  • createModule (38-38)
  • Container (38-38)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/lib/di/modules/Booking.ts (1)
  • moduleLoader (11-16)
⏰ 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). (5)
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Tests / Unit
  • GitHub Check: Type check / check-types
🔇 Additional comments (8)
packages/lib/di/containers/FilterHosts.ts (1)

5-5: Good switch to the local DI entrypoint.

Aligns this container with the repo-wide DI consolidation and removes the external dependency on @evyweb/ioctopus.

packages/lib/di/modules/EventType.ts (1)

6-10: No changes needed: constructor matches binding
The EventTypeRepository constructor accepts a single PrismaClient, which aligns with the .toClass(EventTypeRepository, [DI_TOKENS.PRISMA_CLIENT]) binding.

packages/lib/di/modules/Team.ts (1)

4-5: Approve code changes

packages/lib/di/di.ts re-exports createModule, and no direct imports from “@evyweb/ioctopus” remain outside this entrypoint.

packages/lib/di/modules/GetUserAvailability.ts (2)

3-3: Switching to local DI entrypoint looks good.

Importing createModule from ../di aligns with the repo-wide refactor.


12-12: IUserAvailabilityService correctly defines the four DI dependencies, so using satisfies Record<keyof IUserAvailabilityService, symbol> is accurate.

packages/lib/di/modules/NoSlotsNotification.ts (1)

12-12: No change needed: INoSlotsNotificationService correctly describes the constructor’s dependencies.

packages/lib/di/modules/Features.ts (1)

4-16: Good move to local DI and moduleLoader; structure looks solid

Imports from ../di, local tokens, and moduleLoader wrapper are consistent with the new pattern.

packages/lib/di/modules/LuckyUser.ts (1)

4-4: Local DI import looks good

Switching to the local DI entrypoint aligns with the PR’s consolidation effort.

Comment on lines +4 to +5
import { createModule } from "../di";

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

Switch to the standardized moduleLoader + bindModuleToClassOnToken pattern

This file still exports a createModule-based module, which diverges from the PR-wide standard “export a moduleLoader { token, loadModule }” and misses the compile-time dep checks/runtime auto-loading. Migrate to bindModuleToClassOnToken and export moduleLoader.

-import { createModule } from "../di";
+import { bindModuleToClassOnToken } from "../di";
+// Adjust path/name to match your Prisma module’s export:
+import { moduleLoader as prismaModuleLoader } from "../modules/Prisma";
@@
-export const eventTypeRepositoryModule = createModule();
-eventTypeRepositoryModule
-  .bind(DI_TOKENS.EVENT_TYPE_REPOSITORY)
-  .toClass(EventTypeRepository, [DI_TOKENS.PRISMA_CLIENT]);
+export const moduleLoader = bindModuleToClassOnToken({
+  token: DI_TOKENS.EVENT_TYPE_REPOSITORY,
+  Class: EventTypeRepository,
+  depsMap: {
+    prismaClient: prismaModuleLoader,
+  },
+});
📝 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
import { createModule } from "../di";
// packages/lib/di/modules/EventType.ts
import { bindModuleToClassOnToken } from "../di";
// Adjust path/name to match your Prisma module’s export:
import { moduleLoader as prismaModuleLoader } from "../modules/Prisma";
// … other existing imports (e.g. DI_TOKENS, EventTypeRepository)
export const moduleLoader = bindModuleToClassOnToken({
token: DI_TOKENS.EVENT_TYPE_REPOSITORY,
Class: EventTypeRepository,
depsMap: {
prismaClient: prismaModuleLoader,
},
});
🤖 Prompt for AI Agents
In packages/lib/di/modules/EventType.ts around lines 4 to 5, replace the current
createModule export with the standardized moduleLoader pattern: define and
export a moduleLoader object with { token, loadModule } and use
bindModuleToClassOnToken to bind the EventType class to its DI token inside
loadModule; ensure the token is exported/used consistently, import
bindModuleToClassOnToken instead of createModule, and implement loadModule to
perform the class binding so compile-time dependency checks and runtime
auto-loading work as expected.

Copy link
Copy Markdown
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: 0

Caution

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

⚠️ Outside diff range comments (2)
packages/lib/di/containers/AvailableSlots.ts (1)

43-44: Duplicate load for BUSY_TIMES service module.

container.load(DI_TOKENS.BUSY_TIMES_SERVICE_MODULE, busyTimesModule); is called twice. Depending on the container’s behavior, this can error, override, or cause unintended side effects. Drop the duplicate.

- container.load(DI_TOKENS.BUSY_TIMES_SERVICE_MODULE, busyTimesModule);
packages/lib/di/modules/LuckyUser.ts (1)

6-14: Export standardized module loader for LuckyUser module

 export const luckyUserServiceModule = createModule();
 luckyUserServiceModule.bind(DI_TOKENS.LUCKY_USER_SERVICE).toClass(LuckyUserService, {
   bookingRepository: DI_TOKENS.BOOKING_REPOSITORY,
   hostRepository: DI_TOKENS.HOST_REPOSITORY,
   oooRepository: DI_TOKENS.OOO_REPOSITORY,
   userRepository: DI_TOKENS.USER_REPOSITORY,
   attributeRepository: DI_TOKENS.ATTRIBUTE_REPOSITORY,
 });

+// Standardized loader export for container consumption
+export const moduleLoader = {
+  token: DI_TOKENS.LUCKY_USER_SERVICE_MODULE,
+  loadModule: () => luckyUserServiceModule,
+};
♻️ Duplicate comments (1)
packages/lib/di/containers/BookingLimits.ts (1)

6-6: Internalize DI import: LGTM

Switching createContainer to the local DI entrypoint aligns with the PR direction and keeps DI concerns in-repo.

🧹 Nitpick comments (6)
packages/lib/di/containers/BookingLimits.ts (2)

7-9: Consider adopting the new moduleLoader pattern here for consistency and type-safety

This container still manually loads modules via DI_TOKENS. To match the PR’s standardized pattern ({ token, loadModule }) and gain type-safe wiring, load via the per-module loader objects.

Example refactor (assuming these modules export ...ModuleLoader):

-import { bookingRepositoryModule } from "../modules/Booking";
-import { checkBookingAndDurationLimitsModule } from "../modules/CheckBookingAndDurationLimits";
-import { checkBookingLimitsModule } from "../modules/CheckBookingLimits";
+import { bookingRepositoryModuleLoader } from "../modules/Booking";
+import { checkBookingAndDurationLimitsModuleLoader } from "../modules/CheckBookingAndDurationLimits";
+import { checkBookingLimitsModuleLoader } from "../modules/CheckBookingLimits";

-const container = createContainer();
-container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
-container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
-container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
-container.load(
-  DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE,
-  checkBookingAndDurationLimitsModule
-);
+const container = createContainer();
+// If prisma also exposes a loader, prefer that for consistency:
+// container.load(prismaModuleLoader.token, prismaModuleLoader.loadModule);
+container.load(bookingRepositoryModuleLoader.token, bookingRepositoryModuleLoader.loadModule);
+container.load(checkBookingLimitsModuleLoader.token, checkBookingLimitsModuleLoader.loadModule);
+container.load(
+  checkBookingAndDurationLimitsModuleLoader.token,
+  checkBookingAndDurationLimitsModuleLoader.loadModule
+);

If you’ve generated loadDeps for a higher-level module/container, you can replace these manual loads entirely with that helper.

Also applies to: 11-18


20-28: Add explicit return types on exported getters

Locks the public API and protects against accidental type drift if internal implementations change.

-export function getCheckBookingLimitsService() {
+export function getCheckBookingLimitsService(): CheckBookingLimitsService {
   return container.get<CheckBookingLimitsService>(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE);
 }

-export function getCheckBookingAndDurationLimitsService() {
+export function getCheckBookingAndDurationLimitsService(): CheckBookingAndDurationLimitsService {
   return container.get<CheckBookingAndDurationLimitsService>(
     DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE
   );
 }
packages/lib/di/containers/AvailableSlots.ts (2)

27-47: Align with the new moduleLoader pattern to remove token duplication.

Per PR objectives, modules export { token, loadModule }. Prefer container.load(moduleLoader) to avoid drift between DI_TOKENS.* and the module’s internal token and to gain type/runtime safety.

- container.load(DI_TOKENS.REDIS_CLIENT, redisModule);
- container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
- container.load(DI_TOKENS.OOO_REPOSITORY_MODULE, oooRepositoryModule);
- container.load(DI_TOKENS.SCHEDULE_REPOSITORY_MODULE, scheduleRepositoryModule);
- container.load(DI_TOKENS.SELECTED_SLOT_REPOSITORY_MODULE, selectedSlotsRepositoryModule);
- container.load(DI_TOKENS.TEAM_REPOSITORY_MODULE, teamRepositoryModule);
- container.load(DI_TOKENS.MEMBERSHIP_REPOSITORY_MODULE, membershipRepositoryModule);
- container.load(DI_TOKENS.USER_REPOSITORY_MODULE, userRepositoryModule);
- container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
- container.load(DI_TOKENS.EVENT_TYPE_REPOSITORY_MODULE, eventTypeRepositoryModule);
- container.load(DI_TOKENS.ROUTING_FORM_RESPONSE_REPOSITORY_MODULE, routingFormResponseRepositoryModule);
- container.load(DI_TOKENS.FEATURES_REPOSITORY_MODULE, featuresRepositoryModule);
- container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
- container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
- container.load(DI_TOKENS.AVAILABLE_SLOTS_SERVICE_MODULE, availableSlotsModule);
- container.load(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE_MODULE, getUserAvailabilityModule);
- container.load(DI_TOKENS.BUSY_TIMES_SERVICE_MODULE, busyTimesModule);
- container.load(DI_TOKENS.FILTER_HOSTS_SERVICE_MODULE, filterHostsModule);
- container.load(DI_TOKENS.QUALIFIED_HOSTS_SERVICE_MODULE, qualifiedHostsModule);
- container.load(DI_TOKENS.NO_SLOTS_NOTIFICATION_SERVICE_MODULE, noSlotsNotificationModule);
+ container.load(redisModule);
+ container.load(prismaModule);
+ container.load(oooRepositoryModule);
+ container.load(scheduleRepositoryModule);
+ container.load(selectedSlotsRepositoryModule);
+ container.load(teamRepositoryModule);
+ container.load(membershipRepositoryModule);
+ container.load(userRepositoryModule);
+ container.load(bookingRepositoryModule);
+ container.load(eventTypeRepositoryModule);
+ container.load(routingFormResponseRepositoryModule);
+ container.load(featuresRepositoryModule);
+ container.load(cacheModule);
+ container.load(checkBookingLimitsModule);
+ container.load(availableSlotsModule);
+ container.load(getUserAvailabilityModule);
+ container.load(busyTimesModule);
+ container.load(filterHostsModule);
+ container.load(qualifiedHostsModule);
+ container.load(noSlotsNotificationModule);

49-51: Prefer moduleLoader.token for retrieval to keep token definitions single-sourced.

This avoids mismatches between DI_TOKENS and the module’s declared token.

- return container.get<AvailableSlotsService>(DI_TOKENS.AVAILABLE_SLOTS_SERVICE);
+ return container.get<AvailableSlotsService>(availableSlotsModule.token);
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (2)

4-4: Adopt the new helper for stronger typing and consistency with the PR’s pattern.

Prefer using bindModuleToClassOnToken from ../di rather than hand-rolling the toClass + satisfies check. It yields tighter compile-time guarantees and better aligns with the new moduleLoader flow.

Apply:

-import { type Container, createModule } from "../di";
+import { type Container, createModule, bindModuleToClassOnToken } from "../di";

14-19: Minor: freeze the loader object.

Mark moduleLoader as const to prevent accidental mutation and keep its shape stable.

 export const moduleLoader = {
   token,
   loadModule: (container: Container) => {
     container.load(moduleToken, checkBookingAndDurationLimitsModule);
   },
-};
+} as const;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 8d57e82 and 93f51c3.

📒 Files selected for processing (46)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (0 hunks)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (0 hunks)
  • packages/features/redis/di/redisModule.ts (1 hunks)
  • packages/lib/di/containers/AvailableSlots.ts (1 hunks)
  • packages/lib/di/containers/BookingLimits.ts (1 hunks)
  • packages/lib/di/containers/BusyTimes.ts (1 hunks)
  • packages/lib/di/containers/Cache.ts (1 hunks)
  • packages/lib/di/containers/FilterHosts.ts (1 hunks)
  • packages/lib/di/containers/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/containers/InsightsBooking.ts (1 hunks)
  • packages/lib/di/containers/InsightsRouting.ts (1 hunks)
  • packages/lib/di/containers/LuckyUser.ts (1 hunks)
  • packages/lib/di/containers/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/containers/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/containers/bookings/InstantBookingCreateServiceContainer.ts (1 hunks)
  • packages/lib/di/containers/bookings/RecurringBookingServiceContainer.ts (1 hunks)
  • packages/lib/di/containers/bookings/RegularBookingServiceContainer.ts (1 hunks)
  • packages/lib/di/di.ts (1 hunks)
  • packages/lib/di/modules/Attribute.ts (1 hunks)
  • packages/lib/di/modules/AvailableSlots.ts (1 hunks)
  • packages/lib/di/modules/Booking.ts (1 hunks)
  • packages/lib/di/modules/BusyTimes.ts (1 hunks)
  • packages/lib/di/modules/Cache.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingLimits.ts (1 hunks)
  • packages/lib/di/modules/EventType.ts (1 hunks)
  • packages/lib/di/modules/Features.ts (1 hunks)
  • packages/lib/di/modules/FilterHosts.ts (1 hunks)
  • packages/lib/di/modules/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/modules/Host.ts (1 hunks)
  • packages/lib/di/modules/InsightsBooking.ts (1 hunks)
  • packages/lib/di/modules/InsightsRouting.ts (1 hunks)
  • packages/lib/di/modules/LuckyUser.ts (1 hunks)
  • packages/lib/di/modules/Membership.ts (1 hunks)
  • packages/lib/di/modules/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/modules/Ooo.ts (1 hunks)
  • packages/lib/di/modules/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/modules/RoutingFormResponse.ts (1 hunks)
  • packages/lib/di/modules/Schedule.ts (1 hunks)
  • packages/lib/di/modules/SelectedSlots.ts (1 hunks)
  • packages/lib/di/modules/Team.ts (1 hunks)
  • packages/lib/di/modules/User.ts (1 hunks)
  • packages/lib/di/modules/bookings/InstantBookingCreateServiceModule.ts (1 hunks)
  • packages/lib/di/modules/bookings/RecurringBookingServiceModule.ts (1 hunks)
  • packages/lib/di/modules/bookings/RegularBookingServiceModule.ts (1 hunks)
  • packages/prisma/prisma.module.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
🚧 Files skipped from review as they are similar to previous changes (40)
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/modules/FilterHosts.ts
  • packages/lib/di/containers/bookings/RegularBookingServiceContainer.ts
  • packages/features/redis/di/redisModule.ts
  • packages/lib/di/modules/bookings/RecurringBookingServiceModule.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/modules/bookings/RegularBookingServiceModule.ts
  • packages/lib/di/containers/Cache.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/lib/di/modules/Schedule.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/FilterHosts.ts
  • packages/lib/di/containers/BusyTimes.ts
  • packages/lib/di/containers/bookings/RecurringBookingServiceContainer.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/containers/GetUserAvailability.ts
  • packages/lib/di/modules/NoSlotsNotification.ts
  • packages/lib/di/modules/Ooo.ts
  • packages/lib/di/modules/Membership.ts
  • packages/lib/di/modules/InsightsRouting.ts
  • packages/lib/di/modules/bookings/InstantBookingCreateServiceModule.ts
  • packages/lib/di/containers/NoSlotsNotification.ts
  • packages/lib/di/modules/AvailableSlots.ts
  • packages/lib/di/modules/SelectedSlots.ts
  • packages/lib/di/modules/Attribute.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/modules/QualifiedHosts.ts
  • packages/lib/di/containers/QualifiedHosts.ts
  • packages/lib/di/modules/Team.ts
  • packages/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/Booking.ts
  • packages/lib/di/containers/InsightsRouting.ts
  • packages/lib/di/modules/BusyTimes.ts
  • packages/lib/di/modules/Cache.ts
  • packages/lib/di/containers/bookings/InstantBookingCreateServiceContainer.ts
  • packages/lib/di/di.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/modules/RoutingFormResponse.ts
🧰 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/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/containers/AvailableSlots.ts
  • packages/lib/di/containers/BookingLimits.ts
  • packages/lib/di/modules/LuckyUser.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/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/containers/AvailableSlots.ts
  • packages/lib/di/containers/BookingLimits.ts
  • packages/lib/di/modules/LuckyUser.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/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/containers/AvailableSlots.ts
  • packages/lib/di/containers/BookingLimits.ts
  • packages/lib/di/modules/LuckyUser.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/containers/BookingLimits.ts
🧬 Code graph analysis (1)
packages/lib/di/modules/CheckBookingAndDurationLimits.ts (5)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (1-60)
packages/features/bookings/lib/handleNewBooking/checkBookingAndDurationLimits.ts (1)
  • ICheckBookingAndDurationLimitsService (17-19)
packages/lib/di/modules/Booking.ts (1)
  • moduleLoader (11-16)
packages/lib/di/modules/Cache.ts (1)
  • moduleLoader (14-19)
packages/lib/di/modules/CheckBookingLimits.ts (1)
  • moduleLoader (13-18)
⏰ 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). (8)
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build Docs
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Type check / check-types
  • GitHub Check: Tests / Unit
  • GitHub Check: Linters / lint
  • GitHub Check: Production builds / Build Atoms
🔇 Additional comments (4)
packages/lib/di/containers/AvailableSlots.ts (1)

6-6: Import source swap to internal DI looks good—confirm API parity.

Ensure ../di re-exports createContainer as a named export (ESM/CJS) with the same semantics as before.

packages/lib/di/modules/CheckBookingAndDurationLimits.ts (2)

8-9: Token wiring looks correct.

CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE and its MODULE token match tokens.ts and the new pattern.


10-12: Use bindModuleToClassOnToken instead of manual toClass binding

- checkBookingAndDurationLimitsModule.bind(token).toClass(CheckBookingAndDurationLimitsService, {
-   checkBookingLimitsService: DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE,
- } satisfies Record<keyof ICheckBookingAndDurationLimitsService, symbol>);
+ bindModuleToClassOnToken<ICheckBookingAndDurationLimitsService>(
+   checkBookingAndDurationLimitsModule,
+   token,
+   CheckBookingAndDurationLimitsService,
+   { checkBookingLimitsService: DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE },
+ );

Ensure that every file importing CheckBookingAndDurationLimitsService also imports CheckBookingLimits – the provided verification script failed to execute in this environment, so please manually confirm.

packages/lib/di/modules/LuckyUser.ts (1)

4-4: LGTM on DI import migration

Switching to the local DI entrypoint aligns with the refactor direction.

@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch 3 times, most recently from d0d7baa to fa2efbe Compare September 9, 2025 10:26
@hariombalhara hariombalhara changed the title fix: Make ioctopus flow more type-safe and runtime-safe fix: [Booking flow refactor - DI Cleanup - 1] Make ioctopus flow more type-safe and runtime-safe Sep 9, 2025
@hariombalhara hariombalhara changed the title fix: [Booking flow refactor - DI Cleanup - 1] Make ioctopus flow more type-safe and runtime-safe chore: [Booking flow refactor - DI Cleanup - 1] Make ioctopus flow more type-safe and runtime-safe Sep 9, 2025
@hariombalhara hariombalhara force-pushed the ioctpus-type-and-runtime-safer branch from fa2efbe to 66952a8 Compare September 10, 2025 11:17
Copy link
Copy Markdown
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

Caution

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

⚠️ Outside diff range comments (4)
packages/lib/di/bookings/modules/RecurringBookingService.module.ts (1)

1-12: Adopt the moduleLoader pattern for consistency (and future-proof containers).

This module still exports a raw module via createModule and relies on DI_TOKENS.RECURRING_BOOKING_SERVICE_MODULE for container.load(...). Per PR objective, modules should expose a moduleLoader with token + loadModule. Propose:

-import { createModule } from "../../di";
+import { type Container, createModule } from "../../di";

 export const recurringBookingServiceModule = createModule();

 recurringBookingServiceModule.bind(DI_TOKENS.RECURRING_BOOKING_SERVICE).toClass(RecurringBookingService, {
   regularBookingService: DI_TOKENS.REGULAR_BOOKING_SERVICE,
 });

 export type { RecurringBookingService };
+
+const token = DI_TOKENS.RECURRING_BOOKING_SERVICE;
+const moduleToken = DI_TOKENS.RECURRING_BOOKING_SERVICE_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, recurringBookingServiceModule);
+  },
+};

Follow-up: migrate containers to use recurringBookingServiceModule.loadModule(...) and recurringBookingServiceModule.token, then (optionally) stop exporting the raw module to prevent regressions.

packages/lib/di/modules/Schedule.ts (1)

4-10: Export a moduleLoader to match the new standard.

Schedule still exposes a raw module; export a loader with token + loadModule, mirroring Cache/Prisma.

-import { createModule } from "../di";
+import { type Container, createModule } from "../di";

 export const scheduleRepositoryModule = createModule();
 scheduleRepositoryModule
   .bind(DI_TOKENS.SCHEDULE_REPOSITORY)
   .toClass(ScheduleRepository, [DI_TOKENS.PRISMA_CLIENT]); // Maps 'prismaClient' param to PRISMA_CLIENT token
+
+const token = DI_TOKENS.SCHEDULE_REPOSITORY;
+const moduleToken = DI_TOKENS.SCHEDULE_REPOSITORY_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, scheduleRepositoryModule);
+  },
+};
packages/lib/di/bookings/containers/RecurringBookingService.container.ts (1)

15-29: Replace direct container.load calls with module loaders in booking containers

  • RecurringBookingService.container.ts still uses container.load at lines 16–21 and 25; swap each container.load(DI_TOKENS…, …) with the corresponding *ModuleLoader.loadModule(container) and update getRecurringBookingService() to use recurringBookingServiceModule.token per the suggested diff.
  • InstantBookingCreateService.container.ts (line 10) likewise needs its container.load(DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE_MODULE, instantBookingCreateServiceModule) replaced with instantBookingCreateServiceModuleLoader.loadModule(container) and resolution via its token.
packages/lib/di/bookings/modules/InstantBookingCreateService.module.ts (1)

4-12: Export a moduleLoader for InstantBookingCreateService.

Mirror the standardized pattern:

-import { createModule } from "../../di";
+import { type Container, createModule } from "../../di";

 export const instantBookingCreateServiceModule = createModule();

 instantBookingCreateServiceModule
   .bind(DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE)
   .toClass(InstantBookingCreateService);
 export type { InstantBookingCreateService };
+
+const token = DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE;
+const moduleToken = DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE_MODULE;
+export const moduleLoader = {
+  token,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, instantBookingCreateServiceModule);
+  },
+};
♻️ Duplicate comments (1)
packages/prisma/prisma.module.ts (1)

13-19: Optional: dedicated loader for read-only token (repeat of earlier feedback).

If you want first-class referencing symmetry, add a separate readOnlyModuleLoader; current readOnlyToken on moduleLoader is workable, so this is optional.

 export const moduleLoader = {
   token,
   readOnlyToken,
   loadModule: (container: Container) => {
     container.load(moduleToken, prismaModule);
   },
 };
+
+export const readOnlyModuleLoader = {
+  token: readOnlyToken,
+  loadModule: (container: Container) => {
+    container.load(moduleToken, prismaModule);
+  },
+};
🧹 Nitpick comments (5)
packages/lib/di/bookings/tokens.ts (1)

1-8: Make token bag readonly to prevent accidental mutation.

Tiny safety improvement:

-export const BOOKING_DI_TOKENS = {
+export const BOOKING_DI_TOKENS = {
   REGULAR_BOOKING_SERVICE: Symbol("RegularBookingService"),
   REGULAR_BOOKING_SERVICE_MODULE: Symbol("RegularBookingServiceModule"),
   RECURRING_BOOKING_SERVICE: Symbol("RecurringBookingService"),
   RECURRING_BOOKING_SERVICE_MODULE: Symbol("RecurringBookingServiceModule"),
   INSTANT_BOOKING_CREATE_SERVICE: Symbol("InstantBookingCreateService"),
   INSTANT_BOOKING_CREATE_SERVICE_MODULE: Symbol("InstantBookingCreateServiceModule"),
-};
+} as const;
packages/lib/di/bookings/containers/InstantBookingCreateService.container.ts (2)

4-7: Align export naming with the standardized moduleLoader.

If InstantBookingCreateService.module.ts now exports moduleLoader, prefer importing that for consistency across modules.

Apply:

-import {
-  type InstantBookingCreateService,
-  instantBookingCreateServiceModule,
-} from "../modules/InstantBookingCreateService.module";
+import {
+  type InstantBookingCreateService,
+  moduleLoader as instantBookingCreateServiceModule,
+} from "../modules/InstantBookingCreateService.module";

9-14: Confirm container lifecycle is safe in your runtimes.

Module-scoped singleton container persists across imports. Verify it’s safe under SSR/serverless concurrency and won’t retain request-scoped state.

packages/lib/di/bookings/modules/RegularBookingService.module.ts (2)

30-33: Standardize export name to moduleLoader.

The PR’s pattern says each module exports { token, loadModule } as moduleLoader. Rename for consistency with other modules and imports (you’re already consuming others as moduleLoader).

Apply:

-export const regularBookingServiceModule = {
-  token,
-  loadModule,
-};
+export const moduleLoader = {
+  token,
+  loadModule,
+} as const;

And update any consumers (e.g., RegularBookingService.container) to import { moduleLoader } or alias as needed.


10-18: Optional: add a type to the exported loader for stronger guarantees.

If you have a ModuleLoader interface/type, annotate the export or use satisfies to lock shape at compile time.

Example:

export const moduleLoader = { token, loadModule } satisfies ModuleLoader;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • 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 93f51c3 and 66952a8.

📒 Files selected for processing (48)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts (0 hunks)
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts (0 hunks)
  • packages/features/redis/di/redisModule.ts (1 hunks)
  • packages/lib/di/bookings/containers/InstantBookingCreateService.container.ts (1 hunks)
  • packages/lib/di/bookings/containers/RecurringBookingService.container.ts (1 hunks)
  • packages/lib/di/bookings/containers/RegularBookingService.container.ts (1 hunks)
  • packages/lib/di/bookings/modules/InstantBookingCreateService.module.ts (1 hunks)
  • packages/lib/di/bookings/modules/RecurringBookingService.module.ts (1 hunks)
  • packages/lib/di/bookings/modules/RegularBookingService.module.ts (1 hunks)
  • packages/lib/di/bookings/tokens.ts (1 hunks)
  • packages/lib/di/containers/AvailableSlots.ts (1 hunks)
  • packages/lib/di/containers/BookingLimits.ts (1 hunks)
  • packages/lib/di/containers/BusyTimes.ts (1 hunks)
  • packages/lib/di/containers/Cache.ts (1 hunks)
  • packages/lib/di/containers/FilterHosts.ts (1 hunks)
  • packages/lib/di/containers/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/containers/InsightsBooking.ts (1 hunks)
  • packages/lib/di/containers/InsightsRouting.ts (1 hunks)
  • packages/lib/di/containers/LuckyUser.ts (1 hunks)
  • packages/lib/di/containers/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/containers/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/di.ts (1 hunks)
  • packages/lib/di/modules/Attribute.ts (1 hunks)
  • packages/lib/di/modules/AvailableSlots.ts (1 hunks)
  • packages/lib/di/modules/Booking.ts (1 hunks)
  • packages/lib/di/modules/BusyTimes.ts (1 hunks)
  • packages/lib/di/modules/Cache.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts (1 hunks)
  • packages/lib/di/modules/CheckBookingLimits.ts (1 hunks)
  • packages/lib/di/modules/EventType.ts (1 hunks)
  • packages/lib/di/modules/Features.ts (1 hunks)
  • packages/lib/di/modules/FilterHosts.ts (1 hunks)
  • packages/lib/di/modules/GetUserAvailability.ts (1 hunks)
  • packages/lib/di/modules/Host.ts (1 hunks)
  • packages/lib/di/modules/InsightsBooking.ts (1 hunks)
  • packages/lib/di/modules/InsightsRouting.ts (1 hunks)
  • packages/lib/di/modules/LuckyUser.ts (1 hunks)
  • packages/lib/di/modules/Membership.ts (1 hunks)
  • packages/lib/di/modules/NoSlotsNotification.ts (1 hunks)
  • packages/lib/di/modules/Ooo.ts (1 hunks)
  • packages/lib/di/modules/QualifiedHosts.ts (1 hunks)
  • packages/lib/di/modules/RoutingFormResponse.ts (1 hunks)
  • packages/lib/di/modules/Schedule.ts (1 hunks)
  • packages/lib/di/modules/SelectedSlots.ts (1 hunks)
  • packages/lib/di/modules/Team.ts (1 hunks)
  • packages/lib/di/modules/User.ts (1 hunks)
  • packages/lib/di/tokens.ts (2 hunks)
  • packages/prisma/prisma.module.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/features/bookings/lib/di/containers/RegularBookingServiceContainer.ts
  • packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts
🚧 Files skipped from review as they are similar to previous changes (36)
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/containers/GetUserAvailability.ts
  • packages/lib/di/modules/FilterHosts.ts
  • packages/lib/di/containers/QualifiedHosts.ts
  • packages/lib/di/containers/FilterHosts.ts
  • packages/lib/di/modules/Team.ts
  • packages/lib/di/modules/InsightsBooking.ts
  • packages/lib/di/modules/Membership.ts
  • packages/lib/di/modules/CheckBookingLimits.ts
  • packages/features/redis/di/redisModule.ts
  • packages/lib/di/modules/Features.ts
  • packages/lib/di/modules/InsightsRouting.ts
  • packages/lib/di/containers/BusyTimes.ts
  • packages/lib/di/modules/SelectedSlots.ts
  • packages/lib/di/modules/Ooo.ts
  • packages/lib/di/modules/GetUserAvailability.ts
  • packages/lib/di/modules/LuckyUser.ts
  • packages/lib/di/modules/CheckBookingAndDurationLimits.ts
  • packages/lib/di/containers/InsightsBooking.ts
  • packages/lib/di/modules/BusyTimes.ts
  • packages/lib/di/modules/QualifiedHosts.ts
  • packages/lib/di/modules/EventType.ts
  • packages/lib/di/containers/NoSlotsNotification.ts
  • packages/lib/di/containers/AvailableSlots.ts
  • packages/lib/di/modules/Cache.ts
  • packages/lib/di/containers/Cache.ts
  • packages/lib/di/containers/BookingLimits.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/modules/Booking.ts
  • packages/lib/di/modules/AvailableSlots.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/InsightsRouting.ts
  • packages/lib/di/modules/Attribute.ts
  • packages/lib/di/di.ts
  • packages/lib/di/modules/RoutingFormResponse.ts
  • packages/lib/di/modules/NoSlotsNotification.ts
🧰 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/lib/di/bookings/containers/RegularBookingService.container.ts
  • packages/lib/di/bookings/modules/InstantBookingCreateService.module.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/bookings/modules/RegularBookingService.module.ts
  • packages/lib/di/bookings/tokens.ts
  • packages/lib/di/bookings/modules/RecurringBookingService.module.ts
  • packages/lib/di/bookings/containers/InstantBookingCreateService.container.ts
  • packages/lib/di/modules/Schedule.ts
  • packages/lib/di/tokens.ts
  • packages/lib/di/bookings/containers/RecurringBookingService.container.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/lib/di/bookings/containers/RegularBookingService.container.ts
  • packages/lib/di/bookings/modules/InstantBookingCreateService.module.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/bookings/modules/RegularBookingService.module.ts
  • packages/lib/di/bookings/tokens.ts
  • packages/lib/di/bookings/modules/RecurringBookingService.module.ts
  • packages/lib/di/bookings/containers/InstantBookingCreateService.container.ts
  • packages/lib/di/modules/Schedule.ts
  • packages/lib/di/tokens.ts
  • packages/lib/di/bookings/containers/RecurringBookingService.container.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/lib/di/bookings/containers/RegularBookingService.container.ts
  • packages/lib/di/bookings/modules/InstantBookingCreateService.module.ts
  • packages/prisma/prisma.module.ts
  • packages/lib/di/bookings/modules/RegularBookingService.module.ts
  • packages/lib/di/bookings/tokens.ts
  • packages/lib/di/bookings/modules/RecurringBookingService.module.ts
  • packages/lib/di/bookings/containers/InstantBookingCreateService.container.ts
  • packages/lib/di/modules/Schedule.ts
  • packages/lib/di/tokens.ts
  • packages/lib/di/bookings/containers/RecurringBookingService.container.ts
🧠 Learnings (1)
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/lib/di/bookings/containers/RegularBookingService.container.ts
  • packages/lib/di/bookings/modules/InstantBookingCreateService.module.ts
  • packages/lib/di/bookings/modules/RegularBookingService.module.ts
  • packages/lib/di/bookings/tokens.ts
  • packages/lib/di/bookings/modules/RecurringBookingService.module.ts
  • packages/lib/di/bookings/containers/RecurringBookingService.container.ts
🧬 Code graph analysis (4)
packages/lib/di/bookings/containers/RegularBookingService.container.ts (2)
packages/lib/di/di.ts (1)
  • createContainer (38-38)
packages/lib/di/bookings/modules/RegularBookingService.module.ts (2)
  • RegularBookingService (35-35)
  • regularBookingServiceModule (30-33)
packages/prisma/prisma.module.ts (3)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/prisma/index.ts (1)
  • readonlyPrisma (67-71)
packages/lib/di/modules/Cache.ts (1)
  • moduleLoader (14-19)
packages/lib/di/bookings/modules/RegularBookingService.module.ts (2)
packages/lib/di/di.ts (1)
  • bindModuleToClassOnToken (11-37)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/lib/di/tokens.ts (1)
packages/lib/di/bookings/tokens.ts (1)
  • BOOKING_DI_TOKENS (1-8)
⏰ 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
🔇 Additional comments (5)
packages/lib/di/tokens.ts (1)

56-57: LGTM: booking tokens are now sourced from a single place.

Spreading BOOKING_DI_TOKENS into DI_TOKENS aligns with the new structure and keeps symbols centralized.

packages/lib/di/bookings/containers/RegularBookingService.container.ts (1)

1-13: LGTM: conforms to the moduleLoader contract.

Uses loadModule + resolve by module token; aligns with the new DI conventions.

packages/lib/di/bookings/containers/InstantBookingCreateService.container.ts (1)

3-7: LGTM: local DI import and module wiring look correct.

Migration to the local DI createContainer and the module import path is consistent with the new DI structure.

packages/lib/di/bookings/modules/RegularBookingService.module.ts (2)

12-28: Binding and deps map look correct.

Deps keys match the known IBookingServiceDependencies (cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, checkBookingLimitsService).


1-1: Verified: RegularBookingService shape matches DI helper requirements.

Comment on lines +9 to +13
import { createContainer } from "../../di";
import {
type RecurringBookingService,
recurringBookingServiceModule,
} from "../modules/RecurringBookingService.module";
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

Switch imports to moduleLoader variants.

Update imports to use each module’s moduleLoader, including Prisma. Example:

-import { createContainer } from "../../di";
-import {
-  type RecurringBookingService,
-  recurringBookingServiceModule,
-} from "../modules/RecurringBookingService.module";
+import { createContainer } from "../../di";
+import { moduleLoader as prismaModuleLoader } from "@calcom/prisma/prisma.module";
+import { moduleLoader as bookingModuleLoader } from "@calcom/lib/di/modules/Booking";
+import { moduleLoader as cacheModuleLoader } from "@calcom/lib/di/modules/Cache";
+import { moduleLoader as checkBookingAndDurationLimitsModuleLoader } from "@calcom/lib/di/modules/CheckBookingAndDurationLimits";
+import { moduleLoader as checkBookingLimitsModuleLoader } from "@calcom/lib/di/modules/CheckBookingLimits";
+import { moduleLoader as featuresModuleLoader } from "@calcom/lib/di/modules/Features";
+import {
+  type RecurringBookingService,
+  moduleLoader as recurringBookingServiceModule,
+} from "../modules/RecurringBookingService.module";
📝 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
import { createContainer } from "../../di";
import {
type RecurringBookingService,
recurringBookingServiceModule,
} from "../modules/RecurringBookingService.module";
import { createContainer } from "../../di";
import { moduleLoader as prismaModuleLoader } from "@calcom/prisma/prisma.module";
import { moduleLoader as bookingModuleLoader } from "@calcom/lib/di/modules/Booking";
import { moduleLoader as cacheModuleLoader } from "@calcom/lib/di/modules/Cache";
import { moduleLoader as checkBookingAndDurationLimitsModuleLoader } from "@calcom/lib/di/modules/CheckBookingAndDurationLimits";
import { moduleLoader as checkBookingLimitsModuleLoader } from "@calcom/lib/di/modules/CheckBookingLimits";
import { moduleLoader as featuresModuleLoader } from "@calcom/lib/di/modules/Features";
import {
type RecurringBookingService,
moduleLoader as recurringBookingServiceModule,
} from "../modules/RecurringBookingService.module";
🤖 Prompt for AI Agents
In packages/lib/di/bookings/containers/RecurringBookingService.container.ts
around lines 9 to 13, the file currently imports modules directly (e.g.,
recurringBookingServiceModule and Prisma) but the codebase expects the
moduleLoader variants; replace the direct module imports with their
corresponding moduleLoader exports (for example use
recurringBookingServiceModuleLoader and the prismaModuleLoader) and update the
import source paths to the modules' moduleLoader entry points so the DI
container wires the loaders instead of raw modules.

Comment on lines 6 to +11
export const prismaModule = createModule();
const token = DI_TOKENS.PRISMA_CLIENT;
const readOnlyToken = DI_TOKENS.READ_ONLY_PRISMA_CLIENT;
const moduleToken = DI_TOKENS.PRISMA_MODULE;
prismaModule.bind(token).toFactory(() => prisma, "singleton");
prismaModule.bind(readOnlyToken).toFactory(() => readonlyPrisma, "singleton");
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.

💡 Verification agent

🧩 Analysis chain

Stop exporting the raw prismaModule to enforce the loader contract.

Keeping prismaModule exported encourages direct container.load(...), which this PR aims to remove. Make it internal:

-export const prismaModule = createModule();
+const prismaModule = createModule();

Containers should import { moduleLoader as prismaModuleLoader } and call prismaModuleLoader.loadModule(container).

Run to find remaining direct usages to migrate:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Direct imports of raw prismaModule
rg -nP '\bfrom ["\']@calcom/prisma/prisma\.module["\']' -C2 | rg -nP '\bprismaModule\b' -n
# Any container.load(...) calls left in DI containers
rg -nP 'container\.load\(' packages/lib/di/containers -n

Length of output: 68


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Direct imports of raw prismaModule
rg -nP "from ['\"]@calcom/prisma/prisma\.module['\"]" -C2 packages/ | rg -nP "\bprismaModule\b" -n || true
# Any container.load(...) calls left in DI containers
rg -nP "container\.load\(" packages/lib/di/containers -n || true

Length of output: 8670


Remove the exported prismaModule and migrate all containers to use prismaModuleLoader

All DI container files under packages/lib/di/containers (e.g. RecurringBookingService.container.ts, Cache.ts, QualifiedHosts.ts, etc.) still import and pass the raw prismaModule to container.load(...). Update each to:

  • Import { moduleLoader as prismaModuleLoader } instead of prismaModule
  • Replace
    container.load(DI_TOKENS.PRISMA_MODULE, prismaModule)
    with
    prismaModuleLoader.loadModule(container)

This ensures the loader contract is enforced and removes direct use of the internal module.

🤖 Prompt for AI Agents
In packages/prisma/prisma.module.ts around lines 6 to 11, the file currently
exports prismaModule and binds tokens directly; the review asks to stop
exporting the raw prismaModule and migrate consumers to use prismaModuleLoader.
Remove the exported prismaModule from this file (keep internal creation and
bindings as needed) and export or re-export the moduleLoader instead (named
export moduleLoader or prismaModuleLoader per project convention). Then update
every DI container under packages/lib/di/containers to import { moduleLoader as
prismaModuleLoader } from the prisma module file and replace
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule) with
prismaModuleLoader.loadModule(container) so the loader contract is used and
direct module passing is eliminated.

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

Labels

core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO ready-for-e2e 💻 refactor size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants