Skip to content

chore: [Booking Refactor - Preparation - 0]Move modules required by RegularBookingService to moduleLoader format#23740

Merged
hariombalhara merged 1 commit intomainfrom
move-modules-moduleLoader-pattern-for-RegularBookingService
Sep 16, 2025
Merged

chore: [Booking Refactor - Preparation - 0]Move modules required by RegularBookingService to moduleLoader format#23740
hariombalhara merged 1 commit intomainfrom
move-modules-moduleLoader-pattern-for-RegularBookingService

Conversation

@hariombalhara
Copy link
Copy Markdown
Member

@hariombalhara hariombalhara commented Sep 10, 2025

What does this PR do?

This PR refactors the dependency injection (DI) system for the modules that are needed to be injected in RegularBookingService.

Key Changes:

  • Enhanced bindModuleToClassOnToken function with better type safety and flexibility for single/multiple dependencies
  • Standardized all DI modules to export a consistent moduleLoader object with token and loadModule properties
  • Simplified container loading in LuckyUser.ts by leveraging the new moduleLoader pattern
  • Automatic dependency resolution when modules are loaded, reducing boilerplate code

Mandatory Tasks (DO NOT REMOVE)

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

Checklist

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

@vercel
Copy link
Copy Markdown

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 10, 2025

Walkthrough

This PR refactors DI wiring to a module loader pattern. It introduces a public ModuleLoader type and extends bindModuleToClassOnToken with overloads for single or multiple dependencies, shifting to constructor-based deps. Attribute, Host, Ooo, and User modules now export moduleLoader objects that depend on prismaModuleLoader. LuckyUser switches from static DI tokens to a depsMap of repository moduleLoaders and exports its own moduleLoader. The container’s LuckyUser retrieval loads the module via luckyUserServiceModuleLoader.loadModule(container) and resolves using luckyUserServiceModuleLoader.token.

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 50.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 accurately summarizes the primary change—migrating modules required by RegularBookingService to the moduleLoader format—and aligns with the PR objectives and raw summaries. It is specific and not generic, so it communicates the main intent to reviewers, though the bracketed prefix "[Booking Refactor - Preparation - 0]" adds internal noise and the closing bracket is not followed by a space which slightly harms readability.
Description Check ✅ Passed The description is directly related to the changeset and clearly documents the DI refactor goals, enhancements to bindModuleToClassOnToken, the shift to moduleLoader exports, and the LuckyUser container simplification, all of which match the raw_summary and PR objectives. It also includes the Mandatory Tasks checklist, which appears present but not fully completed.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch move-modules-moduleLoader-pattern-for-RegularBookingService

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

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 "Move modules to moduleLoader format". 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

Copy link
Copy Markdown
Member Author

hariombalhara commented Sep 10, 2025

@hariombalhara hariombalhara changed the title Move modules to moduleLoader format chore: [Booking Refactor - Preparation - 0]Move modules required by BookingService to moduleLoader format Sep 10, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Sep 11, 2025

E2E results are ready!

@hariombalhara hariombalhara changed the title chore: [Booking Refactor - Preparation - 0]Move modules required by BookingService to moduleLoader format chore: [Booking Refactor - Preparation - 0]Move modules required by RegularBookingService to moduleLoader format Sep 11, 2025
@hariombalhara hariombalhara force-pushed the move-modules-moduleLoader-pattern-for-RegularBookingService branch from 3122f8c to 0216266 Compare September 11, 2025 09:07
@pull-request-size pull-request-size bot added size/L and removed size/M labels Sep 11, 2025
@hariombalhara hariombalhara force-pushed the move-modules-moduleLoader-pattern-for-RegularBookingService branch from 3774f99 to a12e086 Compare September 11, 2025 09:57
Comment on lines -14 to -20
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
container.load(DI_TOKENS.HOST_REPOSITORY_MODULE, hostRepositoryModule);
container.load(DI_TOKENS.OOO_REPOSITORY_MODULE, oooRepositoryModule);
container.load(DI_TOKENS.USER_REPOSITORY_MODULE, userRepositoryModule);
container.load(DI_TOKENS.ATTRIBUTE_REPOSITORY_MODULE, attributeRepositoryModule);
container.load(DI_TOKENS.LUCKY_USER_SERVICE_MODULE, luckyUserServiceModule);
Copy link
Copy Markdown
Member Author

@hariombalhara hariombalhara Sep 11, 2025

Choose a reason for hiding this comment

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

These modules are now automatically loaded by LuckyUser modiule which needs these. Also, now container doesn't need to do import management, that is the job of the module itself

Comment on lines +30 to +38
* It assumes that there is a single dependency, passed as argument to the constructor
*
* @returns A function that can be used to load the dependencies into the container automatically.
*/
export function bindModuleToClassOnToken<TClass extends new (deps: any) => any>({
Copy link
Copy Markdown
Member Author

@hariombalhara hariombalhara Sep 11, 2025

Choose a reason for hiding this comment

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

Added two separate signatures to support dep and depsMap, in a mutually exclusive way by TypeScript

moduleToken,
token,
classs: PrismaAttributeRepository,
dep: prismaModuleLoader,
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 use dep instead of depsMap because there is only a single argument defined for PrismaAttributeRepository. So, dep is for such simplistic scenarios. If ever this repository needs to inject more values, it should start using the depsMap which would require the class to define deps as a property on the instance and that would be passed to the constructor

export const attributeRepositoryModule = createModule();
attributeRepositoryModule
.bind(DI_TOKENS.ATTRIBUTE_REPOSITORY)
.toClass(PrismaAttributeRepository, [DI_TOKENS.PRISMA_CLIENT]);
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 remove the manual TOKEN access here and instead we would just use the import from prisma.module

@hariombalhara hariombalhara force-pushed the move-modules-moduleLoader-pattern-for-RegularBookingService branch from a12e086 to 9a03dc1 Compare September 11, 2025 10:27
@hariombalhara hariombalhara marked this pull request as ready for review September 11, 2025 10:28
@graphite-app graphite-app bot requested a review from a team September 11, 2025 10:28
@hariombalhara hariombalhara requested review from ThyMinimalDev and removed request for a team September 11, 2025 10:28
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

♻️ Duplicate comments (2)
packages/lib/di/di.ts (1)

31-50: Single-dependency overload reads cleanly.

This removes ambiguity at call sites and matches the repository modules’ usage in this PR.

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

10-16: Correct use of dep path for single dependency; matches the intended API.

This mirrors the pattern discussed in prior comments—good call using dep until multiple deps are needed.

🧹 Nitpick comments (6)
packages/lib/di/di.ts (1)

57-112: Load dependencies first; small ergonomics tweaks.

  • Load deps before calling container.load to avoid order surprises.
  • Use Object.values when iterating depsMap to simplify and avoid inherited keys.
  • Optional: consider symbol-keyed deps if needed.

Apply:

@@
-  if (dep) {
-    module.bind(token).toClass(classs, [dep.token]);
-  } else if (depsMap) {
-    const depsObject = Object.fromEntries(Object.entries(depsMap).map(([key, value]) => [key, value.token]));
-    module.bind(token).toClass(classs, depsObject);
-  }
+  if (dep) {
+    module.bind(token).toClass(classs, [dep.token]);
+  } else if (depsMap) {
+    const entries = Object.entries(depsMap) as [string, ModuleLoader][];
+    const depsObject = Object.fromEntries(entries.map(([key, value]) => [key, value.token]));
+    module.bind(token).toClass(classs, depsObject);
+  }
@@
-  return function loadModule(container: Container) {
-    container.load(moduleToken, module);
-
-    if (dep) {
-      dep.loadModule(container);
-    } else if (depsMap) {
-      for (const key in depsMap) {
-        const loadModule = depsMap[key as keyof typeof depsMap].loadModule;
-        loadModule(container);
-      }
-    }
-  };
+  return function loadModule(container: Container) {
+    if (dep) {
+      dep.loadModule(container);
+    } else if (depsMap) {
+      for (const loader of Object.values(depsMap)) {
+        loader.loadModule(container);
+      }
+    }
+    container.load(moduleToken, module);
+  };

Confirmed @evyweb/ioctopus supports both array and object-map forms for toClass. (npmjs.com)

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

18-21: Minor: prevent accidental mutation of the loader object.

Optional: freeze or mark as readonly to guard against accidental reassignment.

-export const moduleLoader: ModuleLoader = {
-  token,
-  loadModule,
-};
+export const moduleLoader: ModuleLoader = Object.freeze({
+  token,
+  loadModule,
+}) as ModuleLoader;
packages/lib/di/modules/Attribute.ts (1)

18-21: Nit: make the exported loader immutable for safety.

Same small hardening as in Host.

-export const moduleLoader: ModuleLoader = {
-  token,
-  loadModule,
-};
+export const moduleLoader: ModuleLoader = Object.freeze({
+  token,
+  loadModule,
+}) as ModuleLoader;
packages/lib/di/containers/LuckyUser.ts (2)

9-10: Ensure idempotent loading to avoid duplicate bindings.

If getLuckyUserService() is called multiple times, consider guarding loadModule so the module is loaded once per container.

-  luckyUserServiceModuleLoader.loadModule(container);
-  return container.get<LuckyUserService>(luckyUserServiceModuleLoader.token);
+  // Load once per process/container
+  if (!(globalThis as any).__luckyUserLoaded) {
+    luckyUserServiceModuleLoader.loadModule(container);
+    (globalThis as any).__luckyUserLoaded = true;
+  }
+  return container.get<LuckyUserService>(luckyUserServiceModuleLoader.token);

Alternatively (outside the changed lines), introduce a local guard:

// top-level (outside the function)
let luckyUserLoaded = false;

function ensureLuckyUserLoaded() {
  if (!luckyUserLoaded) {
    luckyUserServiceModuleLoader.loadModule(container);
    luckyUserLoaded = true;
  }
}

Then inside the function:

ensureLuckyUserLoaded();
return container.get<LuckyUserService>(luckyUserServiceModuleLoader.token);

4-4: Tiny ergonomics: add an explicit return type to the getter.

Improves API clarity and refactors.

-export function getLuckyUserService() {
+export function getLuckyUserService(): LuckyUserService {
packages/lib/di/modules/LuckyUser.ts (1)

11-26: Ensure depsMap keys exactly match LuckyUserService constructor deps

Constructor uses ILuckyUserService with keys bookingRepository, hostRepository, oooRepository, userRepository, attributeRepository — add a compile-time check using satisfies:

+type LuckyUserDeps = ConstructorParameters<typeof LuckyUserService>[0];
+const depsMapTyped = {
+  bookingRepository: bookingRepositoryModuleLoader,
+  hostRepository: hostRepositoryModuleLoader,
+  oooRepository: oooRepositoryModuleLoader,
+  userRepository: userRepositoryModuleLoader,
+  attributeRepository: attributeRepositoryModuleLoader,
+} satisfies Record<keyof LuckyUserDeps, ModuleLoader>;
 
-const loadModule = bindModuleToClassOnToken({
+const loadModule = bindModuleToClassOnToken({
   module: thisModule,
   moduleToken,
   token,
   classs: LuckyUserService,
-  depsMap: {
-    bookingRepository: bookingRepositoryModuleLoader,
-    hostRepository: hostRepositoryModuleLoader,
-    oooRepository: oooRepositoryModuleLoader,
-    userRepository: userRepositoryModuleLoader,
-    attributeRepository: attributeRepositoryModuleLoader,
-  },
+  depsMap: depsMapTyped,
 });
📜 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 92005b9 and 9a03dc1.

📒 Files selected for processing (7)
  • packages/lib/di/containers/LuckyUser.ts (1 hunks)
  • packages/lib/di/di.ts (2 hunks)
  • packages/lib/di/modules/Attribute.ts (1 hunks)
  • packages/lib/di/modules/Host.ts (1 hunks)
  • packages/lib/di/modules/LuckyUser.ts (1 hunks)
  • packages/lib/di/modules/Ooo.ts (1 hunks)
  • packages/lib/di/modules/User.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/Ooo.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/modules/LuckyUser.ts
  • packages/lib/di/di.ts
  • packages/lib/di/modules/Attribute.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/Ooo.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/modules/LuckyUser.ts
  • packages/lib/di/di.ts
  • packages/lib/di/modules/Attribute.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/Ooo.ts
  • packages/lib/di/modules/Host.ts
  • packages/lib/di/modules/User.ts
  • packages/lib/di/containers/LuckyUser.ts
  • packages/lib/di/modules/LuckyUser.ts
  • packages/lib/di/di.ts
  • packages/lib/di/modules/Attribute.ts
🧠 Learnings (1)
📚 Learning: 2025-09-01T08:56:14.071Z
Learnt from: nangelina
PR: calcom/cal.com#23486
File: packages/app-store/kyzon-space/lib/tokenManager.ts:25-31
Timestamp: 2025-09-01T08:56:14.071Z
Learning: In token refresh utilities like tokenManager.ts, accessing credential.key from Prisma is legitimate and necessary for OAuth token refresh flows. These internal utilities need stored credentials to refresh tokens and don't expose them in API responses.

Applied to files:

  • packages/lib/di/modules/Attribute.ts
🧬 Code graph analysis (5)
packages/lib/di/modules/Ooo.ts (3)
packages/lib/di/di.ts (2)
  • bindModuleToClassOnToken (57-113)
  • ModuleLoader (4-4)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/prisma/prisma.module.ts (1)
  • moduleLoader (13-19)
packages/lib/di/modules/Host.ts (4)
packages/lib/di/di.ts (2)
  • bindModuleToClassOnToken (57-113)
  • ModuleLoader (4-4)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/lib/server/repository/host.ts (1)
  • HostRepository (3-40)
packages/prisma/prisma.module.ts (1)
  • moduleLoader (13-19)
packages/lib/di/modules/User.ts (3)
packages/lib/di/di.ts (2)
  • bindModuleToClassOnToken (57-113)
  • ModuleLoader (4-4)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/prisma/prisma.module.ts (1)
  • moduleLoader (13-19)
packages/lib/di/modules/LuckyUser.ts (7)
packages/lib/di/di.ts (2)
  • bindModuleToClassOnToken (57-113)
  • ModuleLoader (4-4)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/lib/di/modules/Attribute.ts (1)
  • moduleLoader (18-21)
packages/lib/di/modules/Host.ts (1)
  • moduleLoader (18-21)
packages/lib/di/modules/Ooo.ts (1)
  • moduleLoader (18-21)
packages/lib/di/modules/User.ts (1)
  • moduleLoader (18-21)
packages/lib/di/modules/Booking.ts (1)
  • moduleLoader (11-16)
packages/lib/di/modules/Attribute.ts (3)
packages/lib/di/di.ts (2)
  • bindModuleToClassOnToken (57-113)
  • ModuleLoader (4-4)
packages/lib/di/tokens.ts (1)
  • DI_TOKENS (3-58)
packages/prisma/prisma.module.ts (1)
  • moduleLoader (13-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: Detect changes
🔇 Additional comments (12)
packages/lib/di/modules/Ooo.ts (3)

3-3: LGTM on imports and adopting the moduleLoader pattern.

Using the Prisma module’s loader and pulling helpers from ../di keeps this consistent with the new DI approach.

Also applies to: 5-5


18-21: Nice, clear public surface for consumers.

Exporting { token, loadModule } as a named moduleLoader aligns with the standard used elsewhere. No default export—good.


8-16: Confirmed — PrismaOOORepository has a single-parameter constructor; no change needed.
Constructor is constructor(private prismaClient: PrismaClient) in packages/lib/server/repository/ooo.ts, so using the single-dependency overload (dep: prismaModuleLoader) is correct.

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

4-5: Good addition: minimal, reusable ModuleLoader type.

This clarifies the contract across modules and avoids leaking container specifics.


13-29: Overload for deps-map looks solid; keys inferred from ctor param.

The keyof (TClass extends new (deps: infer TDeps)...) trick gives helpful TS guidance to callers.

packages/lib/di/modules/User.ts (3)

3-3: Consistent adoption of prismaModuleLoader and DI helpers.

Matches the pattern used in Ooo.ts; good consistency and no default exports.

Also applies to: 5-5


18-21: Public moduleLoader shape is correct and minimal.

Token + loader exported as a named export; aligns with guidelines.


8-16: No change required — UserRepository takes a single PrismaClient dependency.

Signature: packages/lib/server/repository/user.ts — constructor(private prismaClient: PrismaClient) {}. Keep the single-dep binding (dep: prismaModuleLoader) as-is.

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

10-16: Solid shift to moduleLoader with single-dep; constructor wiring looks correct.

Using dep: prismaModuleLoader aligns with HostRepository’s single-arg ctor and the new bindModuleToClassOnToken API. Tokens (HOST_REPOSITORY, HOST_REPOSITORY_MODULE) are consistent.

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

28-31: moduleLoader export matches the project pattern

Consistent with other modules; good to ship.


33-33: Type-only re-export is clean

Keeps runtime lean while exposing the type. LGTM.


4-9: No DI cycle found — imports look safe. Searched packages/lib/di/modules for direct imports of "./LuckyUser" and occurrences of LuckyUserService; no matches found.

@hariombalhara hariombalhara force-pushed the move-modules-moduleLoader-pattern-for-RegularBookingService branch from bb65331 to 072d562 Compare September 16, 2025 10:38
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