Skip to content

refactor: Remove App Store's Type Dependency on Trpc Package #23640

Merged
hbjORbj merged 5 commits intomainfrom
refactor/why-is-app-store-trpc-package-aware
Sep 8, 2025
Merged

refactor: Remove App Store's Type Dependency on Trpc Package #23640
hbjORbj merged 5 commits intomainfrom
refactor/why-is-app-store-trpc-package-aware

Conversation

@hbjORbj
Copy link
Copy Markdown
Contributor

@hbjORbj hbjORbj commented Sep 6, 2025

What does this PR do?

  • Remove all statements of import type { RouterOutputs } from "@calcom/trpc/react"; in App Store package. App Store package must not depend on Trpc's interfaces

Result

Screenshot 2025-09-07 at 8 02 12 PM

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A - 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?

  • CI jobs are enough

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 6, 2025

Warning

Rate limit exceeded

@hbjORbj has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b758a68 and 8cc166e.

📒 Files selected for processing (2)
  • packages/app-store/AppDependencyComponent.tsx (1 hunks)
  • packages/features/apps/components/AppList.tsx (2 hunks)

Walkthrough

This PR replaces TRPC/RouterOutputs-derived prop types across the app-store packages with a new public AppCardApp type (based on ConnectedApps[number]) and small related type aliases. Files updated include AppCard, EventTypeAppCardInterface, tests, AppList, AppDependencyComponent (dependencyData shape changed), route-builder pages (using EventTypesByViewer), and a minor typing refinement in useIsAppEnabled. Changes are type-level only; runtime logic and control flow remain unchanged.

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/why-is-app-store-trpc-package-aware

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.

@hbjORbj hbjORbj marked this pull request as draft September 6, 2025 07:34
@graphite-app graphite-app bot requested review from a team September 6, 2025 07:34
@keithwillcode keithwillcode added core area: core, team members only foundation labels Sep 6, 2025
@hbjORbj hbjORbj changed the title refactor: why is app store trpc package aware refactor: Remove App Store's Type Dependency on Trpc Package Sep 6, 2025
@dosubot dosubot bot added app-store area: app store, apps, calendar integrations, google calendar, outlook, lark, apple calendar 💻 refactor labels Sep 6, 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

Caution

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

⚠️ Outside diff range comments (8)
packages/app-store/_components/AppCard.tsx (2)

55-58: Guard against empty/undefined categories

app?.categories[0] can be undefined; calling charAt/slice would throw.

Apply:

-              {!app?.isInstalled && (
+              {!app?.isInstalled && app?.categories?.[0] && (
                 <span className="bg-emphasis ml-1 rounded px-1 py-0.5 text-xs font-medium leading-3 tracking-[0.01em]">
-                  {app?.categories[0].charAt(0).toUpperCase() + app?.categories[0].slice(1)}
+                  {app.categories[0].charAt(0).toUpperCase() + app.categories[0].slice(1)}
                 </span>
               )}

66-72: Optional chaining on logo usage

app.logo might be undefined; .includes without ? can throw.

-              className={classNames(
-                app?.logo.includes("-dark") && "dark:invert",
+              className={classNames(
+                app?.logo?.includes("-dark") && "dark:invert",
                 "max-h-full max-w-full object-contain"
               )}
packages/app-store/_components/EventTypeAppCardInterface.tsx (1)

26-27: Localize ErrorBoundary message

Frontend strings must use t(). Add useLocale and parametrize app name.

+import { useLocale } from "@calcom/lib/hooks/useLocale";
@@
 export const EventTypeAppCard = (props: {
@@
 }) => {
-  const { app, getAppData, setAppData, LockedIcon, disabled } = props;
+  const { app, getAppData, setAppData, LockedIcon, disabled } = props;
+  const { t } = useLocale();
   return (
-    <ErrorBoundary message={`There is some problem with ${app.name} App`}>
+    <ErrorBoundary message={t("problem_with_app", { app: app.name })}>
packages/app-store/_components/eventTypeAppCardInterface.test.tsx (3)

40-45: Fix brittle mock arg assertions

Function components receive props as the first arg; don’t assume a second arg. Use expect.anything or assert on first call arg only.

-    expect(DynamicComponent).toHaveBeenCalledWith(
-      expect.objectContaining({
-        slug: mockProps.app.slug,
-      }),
-      {}
-    );
+    expect(DynamicComponent).toHaveBeenCalledWith(
+      expect.objectContaining({ slug: mockProps.app.slug }),
+      expect.anything()
+    );
@@
-    expect(DynamicComponent).toHaveBeenCalledWith(
-      expect.objectContaining({
-        slug: "stripepayment",
-      }),
-      {}
-    );
+    expect(DynamicComponent).toHaveBeenCalledWith(
+      expect.objectContaining({ slug: "stripepayment" }),
+      expect.anything()
+    );

Also applies to: 76-81


50-59: Invalid prop ‘value’ on EventTypeAppCard

EventTypeAppCard doesn’t accept a value prop; this won’t type-check and is not how context is injected.

Use the existing pass-through to DynamicComponent to assert the functions are provided:

-  test("Should invoke getAppData and setAppData from context on render", () => {
-    render(
-      <EventTypeAppCard
-        {...mockProps}
-        value={{
-          getAppData: getAppDataMock(),
-          setAppData: setAppDataMock(),
-        }}
-      />
-    );
-
-    expect(getAppDataMock).toHaveBeenCalled();
-    expect(setAppDataMock).toHaveBeenCalled();
-  });
+  test("Should pass getAppData and setAppData to child via props/context", () => {
+    render(<EventTypeAppCard {...mockProps} />);
+    expect(DynamicComponent).toHaveBeenCalledWith(
+      expect.objectContaining({
+        getAppData: getAppDataMock,
+        setAppData: setAppDataMock,
+      }),
+      expect.anything()
+    );
+  });

86-93: Throw the error and use Vitest types

Return Error(...) doesn’t trigger ErrorBoundary. Also, use vi.Mock instead of jest.Mock.

-  (DynamicComponent as jest.Mock).mockImplementation(() => {
-      return Error("Mocked error from DynamicComponent");
-  });
+  import type { Mock } from "vitest";
+  (DynamicComponent as unknown as Mock).mockImplementation(() => {
+    throw new Error("Mocked error from DynamicComponent");
+  });
packages/features/apps/components/AppList.tsx (2)

64-71: Localize toast message and hoist t() before use

Replace hardcoded string and move t() above onSuccessCallback.

@@
-  const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
+  const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
+  const { t } = useLocale();
@@
-  const onSuccessCallback = useCallback(() => {
+  const onSuccessCallback = useCallback(() => {
     setBulkUpdateModal(true);
-    showToast("Default app updated successfully", "success");
+    showToast(t("default_app_updated_successfully"), "success");
   }, []);
@@
-  const { t } = useLocale();
+  // (moved above)

Also applies to: 172-172


144-170: Add stable React keys for generated lists

Keys are missing for many ChildAppCard instances and an index key is used. Use stable keys to avoid reconciliation bugs.

-  const cardsForAppsWithTeams = appsWithTeamCredentials.map((app) => {
+  const cardsForAppsWithTeams = appsWithTeamCredentials.map((app) => {
     const appCards = [];
 
     if (app.userCredentialIds.length) {
-      appCards.push(<ChildAppCard item={app} />);
+      appCards.push(<ChildAppCard key={`${app.slug}-user`} item={app} />);
     }
-    for (const team of app.teams) {
+    for (const team of app.teams) {
       if (team) {
         appCards.push(
-          <ChildAppCard
+          <ChildAppCard
+            key={`${app.slug}-team-${team.teamId ?? team.credentialId ?? Math.random()}`}
             item={{
               ...app,
               credentialOwner: {
                 name: team.name,
                 avatar: team.logoUrl,
                 teamId: team.teamId,
                 credentialId: team.credentialId,
                 readOnly: !team.isAdmin,
               },
             }}
           />
         );
       }
     }
     return appCards;
   });
@@
-        {data.items
+        {data.items
           .filter((item) => item.invalidCredentialIds)
           .map((item, i) => {
-            if (!item.teams.length) return <ChildAppCard key={i} item={item} />;
+            if (!item.teams.length) return <ChildAppCard key={`${item.slug}-invalid`} item={item} />;
           })}

Also applies to: 175-181

🧹 Nitpick comments (6)
packages/app-store/_components/AppCard.tsx (1)

16-28: Prefer named export (repo guideline)

If this module doesn’t need a default export, prefer a named export for better tree-shaking and refactors.

-export default function AppCard({
+export function AppCard({

(Remember to update imports.)

packages/app-store/_components/EventTypeAppCardInterface.tsx (1)

29-31: Avoid hardcoded slug exceptions

Encode slug overrides in a map for scalability.

-          slug={app.slug === "stripe" ? "stripepayment" : app.slug}
+          slug={{ stripe: "stripepayment" }[app.slug] ?? app.slug}
packages/features/apps/components/AppList.tsx (2)

97-117: Shadowed identifier: locationType

Local const locationType shadows state variable locationType; rename to avoid confusion.

-                          const locationType = getLocationFromApp(item?.locationOption?.value ?? "");
-                          if (locationType?.linkType === "static") {
-                            setLocationType({ ...locationType, slug: appSlug });
+                          const locType = getLocationFromApp(item?.locationOption?.value ?? "");
+                          if (locType?.linkType === "static") {
+                            setLocationType({ ...locType, slug: appSlug });
                           } else {

176-177: Flatten nested arrays directly

Minor readability: Array of arrays can be rendered via .flat().

-        {cardsForAppsWithTeams.map((apps) => apps.map((cards) => cards))}
+        {cardsForAppsWithTeams.flat()}
packages/app-store/types.d.ts (2)

64-72: Prefer unknown over any for JSON blobs

Use unknown for safer typing; callers can narrow.

-  recurringEvent?: any; // Keep as any since this is JSON
+  recurringEvent?: unknown; // JSON blob

70-71: Consider narrowing schedulingType

If this maps to a known union (e.g., "round_robin" | "collective" | "one_on_one"), declare it to improve DX.

📜 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 550f34c and 77168a5.

📒 Files selected for processing (5)
  • packages/app-store/_components/AppCard.tsx (2 hunks)
  • packages/app-store/_components/EventTypeAppCardInterface.tsx (1 hunks)
  • packages/app-store/_components/eventTypeAppCardInterface.test.tsx (2 hunks)
  • packages/app-store/types.d.ts (3 hunks)
  • packages/features/apps/components/AppList.tsx (4 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx

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

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • packages/app-store/_components/eventTypeAppCardInterface.test.tsx
  • packages/app-store/_components/AppCard.tsx
  • packages/app-store/_components/EventTypeAppCardInterface.tsx
  • packages/features/apps/components/AppList.tsx
**/*.{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/_components/eventTypeAppCardInterface.test.tsx
  • packages/app-store/_components/AppCard.tsx
  • packages/app-store/_components/EventTypeAppCardInterface.tsx
  • packages/features/apps/components/AppList.tsx
  • packages/app-store/types.d.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/_components/eventTypeAppCardInterface.test.tsx
  • packages/app-store/_components/AppCard.tsx
  • packages/app-store/_components/EventTypeAppCardInterface.tsx
  • packages/features/apps/components/AppList.tsx
  • packages/app-store/types.d.ts
**/*.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/types.d.ts
🧠 Learnings (1)
📚 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/app-store/types.d.ts
🧬 Code graph analysis (5)
packages/app-store/_components/eventTypeAppCardInterface.test.tsx (1)
packages/app-store/types.d.ts (1)
  • EventTypeAppCardApp (35-35)
packages/app-store/_components/AppCard.tsx (1)
packages/app-store/types.d.ts (1)
  • AppCardApp (30-30)
packages/app-store/_components/EventTypeAppCardInterface.tsx (1)
packages/app-store/types.d.ts (2)
  • EventTypeAppCardComponentProps (74-81)
  • EventTypeAppCardApp (35-35)
packages/features/apps/components/AppList.tsx (2)
packages/lib/getConnectedApps.ts (1)
  • ConnectedApps (18-18)
packages/app-store/types.d.ts (1)
  • AppCardApp (30-30)
packages/app-store/types.d.ts (1)
packages/lib/getConnectedApps.ts (1)
  • ConnectedApps (18-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). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (5)
packages/app-store/_components/AppCard.tsx (1)

13-13: Type decoupling LGTM

Switching to AppCardApp removes tRPC coupling and clarifies the public prop surface.

Also applies to: 29-29

packages/app-store/_components/EventTypeAppCardInterface.tsx (1)

9-16: Type alignment LGTM

Using EventTypeAppCardApp from domain types removes RouterOutputs leakage. No runtime change.

packages/features/apps/components/AppList.tsx (2)

6-6: Type surface alignment LGTM

Moving to ConnectedApps and AppCardApp is consistent with the app-store refactor.

Also applies to: 16-16, 37-48, 73-73


121-134: Possible undefined credentialId passed as required prop

credentialId is required in props but source could be undefined. Confirm invariant or make prop optional and guard usage.

Would you confirm ConnectedApps guarantees either credentialOwner.credentialId or userCredentialIds[0] is always present? If not, make credentialId?: number and adjust checks accordingly.

Also applies to: 208-255

packages/app-store/types.d.ts (1)

74-81: Type surface LGTM

EventType domain type and component prop refactors look consistent; MetaDataSchema swap is correct.

Also applies to: 83-90

@vercel
Copy link
Copy Markdown

vercel bot commented Sep 7, 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 7, 2025 0:00am
cal-eu Ignored Ignored Sep 7, 2025 0:00am

@hbjORbj hbjORbj force-pushed the refactor/why-is-app-store-trpc-package-aware branch from bc1c5c9 to 3215f9f Compare September 7, 2025 10:59
@pull-request-size pull-request-size bot added size/XS and removed size/L labels Sep 7, 2025
@pull-request-size pull-request-size bot added size/M and removed size/XS labels Sep 7, 2025
@hbjORbj hbjORbj marked this pull request as ready for review September 7, 2025 11:02
@hbjORbj hbjORbj enabled auto-merge (squash) September 7, 2025 11: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: 0

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/AppDependencyComponent.tsx (1)

26-84: Add stable React keys to mapped children.

List items returned from dependencyData.map(...) lack a key prop, which triggers React warnings and can cause incorrect reconciliation.

Apply:

-        dependencyData.map((dependency) => {
+        dependencyData.map((dependency) => {
           return dependency.installed ? (
-            <div className="items-start space-x-2.5">
+            <div key={dependency.slug} className="items-start space-x-2.5">
               <div className="flex items-start">
...
           ) : (
-            <div className="items-start space-x-2.5">
+            <div key={dependency.slug} className="items-start space-x-2.5">
               <div className="text-info flex items-start">
packages/app-store/_components/eventTypeAppCardInterface.test.tsx (1)

86-93: Fix Vitest mock typing and actually trigger the error boundary.

Use vi.Mock (not jest.Mock) and throw an error in render; returning an Error object won’t trigger the boundary.

-  (DynamicComponent as jest.Mock).mockImplementation(() => {
-    return Error("Mocked error from DynamicComponent");
-  });
+  (DynamicComponent as unknown as vi.Mock).mockImplementation(() => {
+    throw new Error("Mocked error from DynamicComponent");
+  });
🧹 Nitpick comments (6)
packages/app-store/AppDependencyComponent.tsx (1)

13-16: Type says dependencyData is required but code guards for undefined. Pick one.

Either make dependencyData optional with a default value, or drop the null checks. Prefer defaulting to an empty array.

 export const AppDependencyComponent = ({
   appName,
-  dependencyData,
+  dependencyData = [],
 }: {
   appName: string;
-  dependencyData: { name: string; slug: string; installed: boolean }[];
+  dependencyData?: { name: string; slug: string; installed: boolean }[];
 }) => {
-        dependencyData && dependencyData.some((dependency) => !dependency.installed) ? "bg-info" : "bg-subtle"
+        dependencyData.some((dependency) => !dependency.installed) ? "bg-info" : "bg-subtle"
       )}>
-      {dependencyData &&
-        dependencyData.map((dependency) => {
+      {dependencyData.map((dependency) => {

Also applies to: 23-26

packages/app-store/_components/eventTypeAppCardInterface.test.tsx (2)

40-45: Loosen argument assertion for mocked component calls.

Passing a second argument {} is brittle and not required; assert only on the props object.

-    expect(DynamicComponent).toHaveBeenCalledWith(
-      expect.objectContaining({
-        slug: mockProps.app.slug,
-      }),
-      {}
-    );
+    expect(DynamicComponent).toHaveBeenCalledWith(
+      expect.objectContaining({ slug: mockProps.app.slug })
+    );
-    expect(DynamicComponent).toHaveBeenCalledWith(
-      expect.objectContaining({
-        slug: "stripepayment",
-      }),
-      {}
-    );
+    expect(DynamicComponent).toHaveBeenCalledWith(
+      expect.objectContaining({ slug: "stripepayment" })
+    );

Also applies to: 76-81


23-34: Prefer realistic fixture over empty object for credentialOwner.

If credentialOwner has a known shape, provide a minimal valid object to avoid masking type issues in tests.

packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx (3)

109-112: Return a boolean from hasRules for clarity.

Current implementation returns number | undefined. Make it explicit boolean for readability and type-safety.

-const hasRules = (route: EditFormRoute) => {
-  if (isRouter(route)) return false;
-  route.queryValue.children1 && Object.keys(route.queryValue.children1).length;
-};
+const hasRules = (route: EditFormRoute) => {
+  if (isRouter(route)) return false;
+  const count = route.queryValue.children1
+    ? Object.keys(route.queryValue.children1).length
+    : 0;
+  return count > 0;
+};

86-107: Avoid any-cast in useEffect dependencies.

(route as unknown as any).action?.value defeats type-safety and can hide bugs. Prefer narrowing or deriving the value before the effect, then depend on it.

-  }, [eventOptions, setRoute, route.id, (route as unknown as any).action?.value]);
+  }, [eventOptions, setRoute, route.id, !isRouter(route) ? route.action.value : undefined]);

Alternatively, derive actionValue via a memo and reference that.


488-488: Localize all user-visible strings.

Several literals bypass t(), which breaks i18n consistency.

Suggested examples to wrap with t():

  • label={route.name ?? t("route_n", { n: index + 1 })}
  • "Conditions", "And connect with specific team members", "Fallback", "Send booker to"
  • "We are not ready for you yet :(" (both occurrences)
  • placeholders: "https://example.com", "event-url"
  • EmptyState: header/text and the "Create your first route" copy

If you’d like, I can generate a diff adding t() keys.

Also applies to: 531-531, 581-581, 609-609, 798-798, 682-683, 817-818, 721-721, 857-857, 773-773, 909-909, 1324-1327, 1339-1340

📜 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 77168a5 and 3e0303b.

📒 Files selected for processing (7)
  • packages/app-store/AppDependencyComponent.tsx (1 hunks)
  • packages/app-store/_components/AppCard.tsx (2 hunks)
  • packages/app-store/_components/EventTypeAppCardInterface.tsx (1 hunks)
  • packages/app-store/_components/eventTypeAppCardInterface.test.tsx (2 hunks)
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx (4 hunks)
  • packages/app-store/types.d.ts (2 hunks)
  • packages/features/apps/components/AppList.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/app-store/_components/EventTypeAppCardInterface.tsx
  • packages/features/apps/components/AppList.tsx
  • packages/app-store/_components/AppCard.tsx
  • packages/app-store/types.d.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.tsx

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

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • packages/app-store/AppDependencyComponent.tsx
  • packages/app-store/_components/eventTypeAppCardInterface.test.tsx
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx
**/*.{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/AppDependencyComponent.tsx
  • packages/app-store/_components/eventTypeAppCardInterface.test.tsx
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx
**/*.{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/AppDependencyComponent.tsx
  • packages/app-store/_components/eventTypeAppCardInterface.test.tsx
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx
⏰ 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). (6)
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Tests / Unit
  • GitHub Check: Type check / check-types
🔇 Additional comments (6)
packages/app-store/AppDependencyComponent.tsx (1)

15-15: Good decoupling: prop now uses a plain shape (no TRPC types).

This aligns with the PR goal of removing RouterOutputs from app-store. No runtime impact here.

packages/app-store/_components/eventTypeAppCardInterface.test.tsx (1)

2-2: Type-only import switch looks good.

Switching to AppCardApp keeps tests aligned with the new public type.

packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx (4)

16-16: Nice: replaced RouterOutputs alias with EventTypesByViewer.

This removes app-store’s type dependency on TRPC while preserving type safety.


142-145: Type plumb-through is consistent.

buildEventsData, Route, and Routes now consistently use EventTypesByViewer.

Also applies to: 373-374, 1130-1131


1414-1421: Default export is acceptable here.

This module is a Next.js page; default export exemption applies per guidelines.

Also applies to: 1426-1444


1384-1391: Sanity-check: inferred type of eventTypesByGroup matches EventTypesByViewer.

Given the trpc.viewer.eventTypes.getByViewer.useQuery typing, this should align. Consider adding a type annotation if inference ever regresses.

Run to ensure there are no remaining imports of RouterOutputs in app-store:

#!/bin/bash
rg -nP --glob 'packages/app-store/**' $'import\\s+type\\s*\\{\\s*RouterOutputs\\s*\\}\\s*from\\s*"@calcom/trpc/react"'

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Sep 7, 2025

E2E results are ready!

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 (3)
packages/app-store/_utils/useIsAppEnabled.ts (3)

29-31: Use nullish coalescing to preserve 0 IDs and guard indexing.

Avoid treating 0 as falsy; also protect optional array access.

-    if (newValue && (app.userCredentialIds?.length || app.credentialOwner?.credentialId)) {
-      setAppData("credentialId", app.credentialOwner?.credentialId || app.userCredentialIds[0]);
+    if (
+      newValue &&
+      ((app.userCredentialIds?.length ?? 0) > 0 || app.credentialOwner?.credentialId != null)
+    ) {
+      setAppData("credentialId", app.credentialOwner?.credentialId ?? app.userCredentialIds?.[0]);
     }

7-7: Prefer named export over default (repo guideline).

Convert to a named export for better tree-shaking and refactors.

-function useIsAppEnabled(app: EventTypeAppCardApp) {
+export function useIsAppEnabled(app: EventTypeAppCardApp) {
@@
-export default useIsAppEnabled;
+// no default export

Also applies to: 38-38


5-5: Type upstream so the arrow param annotation isn’t needed.

If EventTypeAppCardApp.userCredentialIds is number[], TS infers id automatically; otherwise, keep the local check and make userCredentialIds optional-safe as suggested above.

Run to confirm the type shape and optionality:

#!/bin/bash
# Find the EventTypeAppCardApp definition and its userCredentialIds field
rg -nP -C3 --type=ts '(type|interface)\s+EventTypeAppCardApp\b'
rg -nP --type=ts -C2 '\buserCredentialIds\??:\s*number\[\]'
# Also check for alternative naming to ensure consistency
rg -nP --type=ts -C2 '\bcredentialIds\??:\s*number\[\]'
📜 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 3e0303b and b758a68.

📒 Files selected for processing (1)
  • packages/app-store/_utils/useIsAppEnabled.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/app-store/_utils/useIsAppEnabled.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/_utils/useIsAppEnabled.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/_utils/useIsAppEnabled.ts
⏰ 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). (7)
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Linters / lint
  • GitHub Check: Type check / check-types

}: {
appName: string;
dependencyData: RouterOutputs["viewer"]["apps"]["queryForDependencies"];
dependencyData?: { name: string; slug: string; installed: boolean }[];
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

makes sense for this to be optional since the business logic below checks whether it's truthy or not

Copy link
Copy Markdown
Contributor

@keithwillcode keithwillcode left a comment

Choose a reason for hiding this comment

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

Nice work, @hbjORbj. Can you also add linting rules to make sure this violation never happens again?

@hbjORbj hbjORbj merged commit a1fca56 into main Sep 8, 2025
66 of 68 checks passed
@hbjORbj hbjORbj deleted the refactor/why-is-app-store-trpc-package-aware branch September 8, 2025 00:59
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 core area: core, team members only foundation ready-for-e2e 💻 refactor size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants