Skip to content

Comments

fix:optimized data loading in locations.ts#24271

Closed
thetanav wants to merge 2 commits intocalcom:mainfrom
thetanav:fix/faster-dev-server
Closed

fix:optimized data loading in locations.ts#24271
thetanav wants to merge 2 commits intocalcom:mainfrom
thetanav:fix/faster-dev-server

Conversation

@thetanav
Copy link

@thetanav thetanav commented Oct 4, 2025

I am still workingon this pr if you have a suggestion to me pls add a comment to this PR, as i am first time contributor of this project

What does this PR do?

  1. Lazy Metadata Loading: Modified appStoreMetaData.ts to use dynamic imports instead of static imports for all app configs
  2. Dynamic App Registry: Updated _appRegistry.ts to load app metadata on-demand rather than pre-loading everything
  3. Removed Static Imports: Eliminated static imports of the generated metadata file that was causing all config.json files to be bundled
  4. Updated Dependencies: Modified related files to work with the new lazy loading approach

/claim #23104

Visual Demo (For contributors especially)

add in future working on this pr

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.

How should this be tested?

  • npm run lint

  • Are there environment variables that should be set?

  • What are the minimal test data to have?

  • What is expected (happy path) to have (input and output)?

  • Any other important info that could help to test that PR

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Oct 4, 2025
@graphite-app graphite-app bot requested a review from a team October 4, 2025 14:46
@github-actions github-actions bot added $2K app-store area: app store, apps, calendar integrations, google calendar, outlook, lark, apple calendar High priority Created by Linear-GitHub Sync labels Oct 4, 2025
@vercel
Copy link

vercel bot commented Oct 4, 2025

@thetanav is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions bot added performance area: performance, page load, slow, slow endpoints, loading screen, unresponsive 🐛 bug Something isn't working 💎 Bounty A bounty on Algora.io labels Oct 4, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 4, 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 "fix:optimized data loading in locations.ts". 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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 4, 2025

Walkthrough

  • Introduces async metadata retrieval via getAppMetadata(dirName) with per-dir cache; replaces synchronous appStoreMetadata with a Proxy that throws on access.
  • Updates _appRegistry to use getAppMetadata; slug lookups now resolve dirName via prisma before loading metadata.
  • Switches build config to use lazyImport for app store metadata.
  • Refactors locations.ts to lazily load and cache app-derived locations and combined location data.
  • Simplifies getNormalizedAppMetadata input type to Record<string, any>.
  • Adds lazy, cached loading scaffolding in utils.ts; adjusts ALL_APPS and getAppFromSlug.
  • Updates bookingScenario.ts import source.
  • Removes appStoreMetadata import in seed-app-store script while leaving usages.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning While most changes support the lazy metadata loading goal, the update in apps/web/test/utils/bookingScenario.ts and the removal of the appStoreMetadata import in scripts/seed-app-store.ts introduce adjustments unrelated to the performance-focused objectives and leave the seed script in a broken state. Revert or confine the bookingScenario.ts import change unless it’s essential for test compatibility, and restore or update the missing appStoreMetadata reference in scripts/seed-app-store.ts to maintain a functioning seed script.
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title accurately highlights the optimization made to data loading in locations.ts but does not capture the broader lazy-loading refactor and dynamic import changes applied across multiple App Store modules.
Linked Issues Check ✅ Passed The refactor replaces static imports of the full App Store metadata with async dynamic imports via getAppMetadata, updates the app registry to load on-demand, and overhauls locations and utility modules to use lazy-loaded data, directly addressing the slow local development and bundling issues described in #23104 and CAL-6255.
Description Check ✅ Passed The pull request description outlines the key changes—lazy metadata loading, dynamic app registry updates, removal of static imports, and dependency adjustments—which directly correspond to the files modified in this PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@dosubot dosubot bot added the 🧹 Improvements Improvements to existing features. Mostly UX/UI label Oct 4, 2025
@dosubot dosubot bot added this to the v5.8 milestone Oct 4, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (2)
packages/app-store/getNormalizedAppMetadata.ts (1)

10-17: Fix unresolved AppStoreMetaData type

AppStoreMetaData was deleted in this refactor, so this cast now references an undefined type. The file currently fails to compile under TypeScript. Cast to the existing AppMeta shape instead so the build passes.

-  const metadata = {
-    appData: null,
-    dirName,
-    __template: "",
-    ...appMeta,
-  } as Omit<AppStoreMetaData[keyof AppStoreMetaData], "dirName"> & { dirName: string };
+  const metadata: AppMeta = {
+    appData: null,
+    __template: "",
+    ...appMeta,
+    dirName,
+  };
packages/app-store-cli/src/build.ts (1)

246-260: Lazy-importing metadata breaks synchronous consumers

Setting lazyImport: true here makes every entry in the generated appStoreMetadata map a Promise. Callers (see apps/web/test/utils/bookingScenario/bookingScenario.ts and many others) treat those entries as plain objects and immediately read fields like .type, so this change turns into runtime failures (undefined access / promise objects). Until the callers are refactored to await the metadata, we need to keep this export synchronous.

-      ],
-      lazyImport: true,
+      ],
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 a4be822 and 0e2856b.

📒 Files selected for processing (8)
  • apps/web/test/utils/bookingScenario/bookingScenario.ts (1 hunks)
  • packages/app-store-cli/src/build.ts (1 hunks)
  • packages/app-store/_appRegistry.ts (2 hunks)
  • packages/app-store/appStoreMetaData.ts (1 hunks)
  • packages/app-store/getNormalizedAppMetadata.ts (1 hunks)
  • packages/app-store/locations.ts (2 hunks)
  • packages/app-store/utils.ts (3 hunks)
  • scripts/seed-app-store.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • scripts/seed-app-store.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/app-store/locations.ts
  • apps/web/test/utils/bookingScenario/bookingScenario.ts
  • packages/app-store/appStoreMetaData.ts
  • packages/app-store-cli/src/build.ts
  • packages/app-store/utils.ts
  • packages/app-store/_appRegistry.ts
  • packages/app-store/getNormalizedAppMetadata.ts
**/*.{ts,tsx}

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

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

Files:

  • packages/app-store/locations.ts
  • apps/web/test/utils/bookingScenario/bookingScenario.ts
  • packages/app-store/appStoreMetaData.ts
  • packages/app-store-cli/src/build.ts
  • packages/app-store/utils.ts
  • packages/app-store/_appRegistry.ts
  • packages/app-store/getNormalizedAppMetadata.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

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

Files:

  • packages/app-store/locations.ts
  • apps/web/test/utils/bookingScenario/bookingScenario.ts
  • packages/app-store/appStoreMetaData.ts
  • packages/app-store-cli/src/build.ts
  • packages/app-store/utils.ts
  • packages/app-store/_appRegistry.ts
  • packages/app-store/getNormalizedAppMetadata.ts
🧬 Code graph analysis (2)
packages/app-store/appStoreMetaData.ts (1)
packages/app-store/getNormalizedAppMetadata.ts (1)
  • getNormalizedAppMetadata (5-21)
packages/app-store/_appRegistry.ts (1)
packages/app-store/appStoreMetaData.ts (1)
  • getAppMetadata (9-31)
⏰ 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

Comment on lines +245 to +297
// Since this is server-side and the module should be available, use require
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { appStoreMetadata } = require("@calcom/app-store/bookerAppsMetaData");
processAppMetadata(appStoreMetadata);
} catch (error) {
console.warn("Failed to load app metadata, app locations may not be available", error);
locationsFromApps = [];
}

return locationsFromApps;
};

const processAppMetadata = (appStoreMetadata: any) => {
locationsFromApps = [];

for (const [appName, meta] of Object.entries(appStoreMetadata)) {
const location = meta.appData?.location;
if (location) {
// TODO: This template variable replacement should happen once during app-store:build.
for (const [key, value] of Object.entries(location)) {
if (typeof value === "string") {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
location[key] = value.replace(/{SLUG}/g, meta.slug).replace(/{TITLE}/g, meta.name);
}
}
}
const newLocation = {
...location,
messageForOrganizer: location.messageForOrganizer || `Set ${location.label} link`,
iconUrl: meta.logo,
// For All event location apps, locationLink is where we store the input
// TODO: locationLink and link seems redundant. We can modify the code to keep just one of them.
variable: location.variable || "locationLink",
defaultValueVariable: location.defaultValueVariable || "link",
};

// Static links always require organizer to input
if (newLocation.linkType === "static") {
newLocation.organizerInputType = location.organizerInputType || "text";
if (newLocation.organizerInputPlaceholder?.match(/https?:\/\//)) {
// HACK: Translation ends up removing https? if it's in the beginning :(
newLocation.organizerInputPlaceholder = ` ${newLocation.organizerInputPlaceholder}`;
const newLocation = {
...location,
messageForOrganizer: location.messageForOrganizer || `Set ${location.label} link`,
iconUrl: meta.logo,
// For All event location apps, locationLink is where we store the input
// TODO: locationLink and link seems redundant. We can modify the code to keep just one of them.
variable: location.variable || "locationLink",
defaultValueVariable: location.defaultValueVariable || "link",
};

// Static links always require organizer to input
if (newLocation.linkType === "static") {
newLocation.organizerInputType = location.organizerInputType || "text";
if (newLocation.organizerInputPlaceholder?.match(/https?:\/\//)) {
// HACK: Translation ends up removing https? if it's in the beginning :(
newLocation.organizerInputPlaceholder = ` ${newLocation.organizerInputPlaceholder}`;
}
} else {
newLocation.organizerInputType = null;
}
} else {
newLocation.organizerInputType = null;
}

AppStoreLocationType[appName] = newLocation.type;
AppStoreLocationType[appName] = newLocation.type;

locationsFromApps.push({
...newLocation,
});
locationsFromApps.push({
...newLocation,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Blocking: lazy loader still relies on appStoreMetadata Proxy

bookerAppsMetaData no longer exposes a concrete appStoreMetadata; in this PR it’s now a Proxy that throws on property access to prevent the old eager pattern. Destructuring it here trips that guard, we fall into the catch block, and locationsFromApps is permanently set to []. Every downstream lookup (getLocationFromApp, LocationType, etc.) now loses all app-provided locations, breaking conferencing apps across the product. Please switch this loader over to the new lazy API (e.g. hydrate via getAppMetadata / the new registry) before caching so we still populate real metadata.

Comment on lines +31 to +47
// For now, return empty arrays since we can't synchronously load all apps
// This needs to be changed to load apps from database or a static list
ALL_APPS_CACHE = [];
ALL_APPS_MAP_CACHE = {};
return { apps: ALL_APPS_CACHE, appsMap: ALL_APPS_MAP_CACHE };
}

export type CredentialDataWithTeamName = CredentialForCalendarService & {
team?: {
name: string;
} | null;
};

export const ALL_APPS = Object.values(ALL_APPS_MAP);
// For backward compatibility, provide synchronous access
// But this will be empty until we implement proper loading
export const ALL_APPS: AppMeta[] = [];
const ALL_APPS_MAP: Record<string, AppMeta> = {};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Blocking regression: ALL_APPS/slug lookups now always return empty

loadAllApps currently seeds both caches with empty structures and nothing ever repopulates them, yet ALL_APPS stays the public source for getApps, hasIntegrationInstalled, location options, etc. Coupled with getAppFromSlug returning undefined, every consumer now sees “no apps installed,” wiping out integrations UI/logic. We need to keep hydrating these exports—either by reusing the generated metadata module or by wiring in the new lazy getAppMetadata/registry pipeline—before flipping the contract to async. Until the real loader is in place this change cannot ship.

Also applies to: 139-143

🤖 Prompt for AI Agents
packages/app-store/utils.ts lines 31-47 (and also address similar logic at
139-143): the current change seeds ALL_APPS/ALL_APPS_MAP (and
ALL_APPS_CACHE/ALL_APPS_MAP_CACHE) with empty values causing all slug lookups
and getApps consumers to see no integrations; restore synchronous hydration by
loading the existing generated app metadata module (or synchronously iterate the
registry/getAppMetadata results) and populate ALL_APPS, ALL_APPS_MAP,
ALL_APPS_CACHE and ALL_APPS_MAP_CACHE before exporting so getAppFromSlug and
other sync consumers continue to work; ensure the map is keyed by slug and that
getAppFromSlug reads from the populated ALL_APPS_MAP, and do not convert the
public contract to async until a full async loader is implemented.

@thetanav thetanav closed this by deleting the head repository Oct 8, 2025
@dosubot dosubot bot modified the milestone: v5.8 Oct 8, 2025
@dosubot dosubot bot modified the milestones: v5.8, v5.9 Oct 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app-store area: app store, apps, calendar integrations, google calendar, outlook, lark, apple calendar 🙋 Bounty claim 💎 Bounty A bounty on Algora.io 🐛 bug Something isn't working community Created by Linear-GitHub Sync High priority Created by Linear-GitHub Sync 🧹 Improvements Improvements to existing features. Mostly UX/UI performance area: performance, page load, slow, slow endpoints, loading screen, unresponsive size/L $2K

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local dev crazy slow

2 participants