Skip to content

Conversation

@oscartbeaumont
Copy link
Contributor

@oscartbeaumont oscartbeaumont commented Sep 19, 2025

Me don't like waiting for Next.js to compile. Upgrade to the latest version so we can potentially enable Turbopack in a follow up PR?

This upgrade was mostly done via the Next.js codemod.

Summary by CodeRabbit

  • Chores

    • Upgraded Next.js and React; updated Effect-related libraries and various package configs; enabled Turbopack for dev/build.
  • Performance

    • Adjusted build pipeline (Turbopack); removed SWC minification and an experimental instrumentation hook.
  • Bug Fixes

    • More reliable cookie and header handling across pages and APIs; more consistent params/search handling to reduce edge-case failures.
  • Refactor

    • Strengthened TypeScript null-safety and ref typings (strict null checks) for safer component interactions.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 19, 2025

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Walkthrough

The PR upgrades dependencies (Next/React/Effect), enables TypeScript strictNullChecks, converts many page/route props to Promise-wrapped params/searchParams and awaits cookies()/headers(), widens several RefObject types to allow null, and applies small API route export/type adjustments.

Changes

Cohort / File(s) Summary
Dependency & package bumps
apps/web/package.json, apps/desktop/package.json, apps/workflow-manager/package.json, apps/workflow-runner/package.json, packages/database/package.json, packages/ui/package.json, packages/utils/package.json, packages/web-api-contract-effect/package.json, packages/web-backend/package.json, packages/web-domain/package.json
Upgrade Next/React/@types/react, bump @effect/* and effect packages, add turbopack flags in web, and align pnpm overrides.
TS config
apps/web/tsconfig.json
Enable compilerOptions.strictNullChecks: true.
Next config
apps/web/next.config.mjs
Remove swcMinify and experimental instrumentationHook.
Cookies / headers migration
apps/web/actions/videos/password.ts, apps/web/app/(org)/dashboard/_components/actions.ts, apps/web/app/(org)/dashboard/layout.tsx, apps/web/app/(site)/page.tsx, apps/web/app/api/utils.ts, apps/web/app/api/video/comment/route.ts, apps/web/app/robots.ts, apps/web/utils/getBootstrapData.ts, packages/database/auth/auth-options.ts
Replace direct cookies()/headers() usage with awaited versions and adapt set/get/delete calls; add typing casts where needed.
Promise-wrapped params/searchParams (pages & routes)
apps/web/app/(org)/dashboard/caps/page.tsx, apps/web/app/(org)/dashboard/folder/[id]/page.tsx, apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx, apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx, apps/web/app/(org)/invite/[inviteId]/page.tsx, apps/web/app/(org)/verify-otp/page.tsx, apps/web/app/(site)/[slug]/page.tsx, apps/web/app/(site)/blog/[slug]/page.tsx, apps/web/app/(site)/docs/[slug]/page.tsx, apps/web/app/(site)/docs/[...slug]/page.tsx, apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx, apps/web/app/embed/[videoId]/page.tsx, apps/web/app/s/[videoId]/page.tsx, apps/web/app/(site)/download/[platform]/route.ts, apps/web/app/api/releases/macos/route.ts, apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts, apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
Update function/handler signatures to accept props with Promise-wrapped params/searchParams and await them internally (including generateMetadata changes).
API route export & typing changes
apps/web/app/api/erpc/route.ts, apps/web/app/api/playlist/route.ts, apps/web/app/api/video/comment/route.ts, apps/web/app/api/video/delete/route.ts
Cast exported handlers to any (e.g., handler as any), rename revalidatedynamic in playlist route, and wrap some handlers as async arrow functions.
Ref nullability & JSX type imports
apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx, .../Top.tsx, .../SpaceDialog.tsx, .../caps/components/FoldersDropdown.tsx, .../caps/components/NewFolderDialog.tsx, .../folder/[id]/components/SubfolderDialog.tsx, .../spaces/[spaceId]/components/VirtualizedVideoGrid.tsx, apps/web/components/forms/NewOrganization.tsx, apps/web/components/pages/_components/ComparePlans.tsx, apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx, .../HLSVideoPlayer.tsx, .../tabs/Activity/Comments.tsx, .../tabs/Activity/index.tsx, apps/web/components/features/FeaturePage.tsx, apps/web/components/pages/HomePage/Features.tsx, .../RecordingModes.tsx, apps/web/components/seo/types.ts, apps/web/lib/features/transform.ts
Widen many RefObject types to allow null, add type-only JSX/RefObject imports, and tighten icon prop element types to include ref/className/size shapes.
Server error handling simplification
apps/web/lib/server.ts
Await cookies() when reading password; remove special not-found conditional and throw defect for any Die-type cause in runPromise/runPromiseExit paths.
Misc pages/components tweaks
apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx, apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx, apps/web/app/(org)/dashboard/caps/components/..., apps/web/app/(org)/dashboard/settings/..., apps/web/app/(org)/dashboard/spaces/..., etc.
Small typing adjustments and explicit RefObject

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant NextApp as Next App Router
  participant Page as Page/Route Module
  participant Svc as Data/Service

  User->>NextApp: HTTP Request
  NextApp->>Page: Invoke handler/component with props (params/searchParams as Promise)
  Note right of Page: Await props.params / props.searchParams
  Page->>Svc: Fetch data using resolved params
  Svc-->>Page: Data/Result
  Page-->>NextApp: Response/JSX/Redirect
  NextApp-->>User: HTML/JSON
Loading
sequenceDiagram
  autonumber
  participant RC as Server Component/Action
  participant NH as next/headers

  RC->>NH: cookies()
  NH-->>RC: Promise<CookieStore>
  RC->>RC: await cookies() → cookieStore
  RC->>RC: cookieStore.get/set/delete(...)
  RC->>NH: headers()
  NH-->>RC: Promise<Headers>
  RC->>RC: await headers() → read header values
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Brendonovich

Poem

I nibbled code and chased a thread,
Awaited cookies, headers fed.
Params now promise what they bring,
Null refs hop in — a careful thing.
Upgraded stack, my whiskers twitch — hooray! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly identifies the primary changes in the PR—upgrading Next.js and enabling Turbopack—which directly matches the dependency bumps and build configuration updates in the diff. It is concise, specific, and avoids unnecessary detail, making it easy for teammates to understand the intent at a glance.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

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.

@vercel
Copy link
Contributor

vercel bot commented Sep 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
cap-web Ready Ready Preview Comment Sep 24, 2025 8:11am

@oscartbeaumont oscartbeaumont marked this pull request as ready for review September 24, 2025 08:09
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: 4

Caution

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

⚠️ Outside diff range comments (7)
apps/web/app/api/utils.ts (1)

11-14: Remove sensitive logs (Authorization header and full user object).

Logging bearer tokens and user objects is a security/compliance risk.

Apply:

-	console.log("auth header: ", c.req.header("authorization"));
+	// removed
@@
-	console.log("User: ", user);
+	// removed

Also applies to: 39-41

packages/database/auth/auth-options.ts (1)

98-103: Do not log verification codes or email contents

Logging identifier/token (and rendered email) is a secrets/PII leak risk in production.

-            console.log({ identifier, token });
             const { OTPEmail } = await import("../emails/otp-email");
             const email = OTPEmail({ code: token, email: identifier });
-            console.log({ email });
             await sendEmail({
               email: identifier,
               subject: `Your Cap Verification Code`,
               react: email,
             });
apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (1)

310-315: Duplicate event listener registration causes double-calls and leaks

loadedmetadata is added twice; only one remove occurs in cleanup. Remove the duplicate add.

     video.addEventListener("loadeddata", handleLoadedData);
     video.addEventListener("canplay", handleCanPlay);
     video.addEventListener("loadedmetadata", handleLoadedMetadataWithTracks);
     video.addEventListener("load", handleLoad);
     video.addEventListener("play", handlePlay);
     video.addEventListener("error", handleError as EventListener);
-    video.addEventListener("loadedmetadata", handleLoadedMetadataWithTracks);
apps/web/app/api/playlist/route.ts (2)

245-247: Remove any-casts on route handlers; type to Request -> Promise.

Avoid any per project guidelines.

-export const GET = handler as any;
-export const HEAD = handler as any;
+export const GET: (req: Request) => Promise<Response> = handler;
+export const HEAD: (req: Request) => Promise<Response> = handler;

169-180: Guard mp4 requests when source isn’t desktopMP4.

When videoType === "mp4" but the source isn’t desktopMP4, prefix remains undefined and listObjects may run on an unintended path.

Add an early guard:

   } else if (video.source.type === "desktopMP4") {
     yield* Effect.log(
       `Returning path ${`${video.ownerId}/${video.id}/result.mp4`}`,
     );
     return yield* s3
       .getSignedObjectUrl(`${video.ownerId}/${video.id}/result.mp4`)
       .pipe(Effect.map(HttpServerResponse.redirect));
   }
+  if (urlParams.videoType === "mp4") {
+    return yield* Effect.fail(new HttpApiError.NotFound());
+  }
apps/web/app/api/releases/macos/route.ts (1)

5-7: Align with API route guidelines (HttpApi + handler export).

Per repo guidelines, implement routes with @effect/platform HttpApi/HttpApiBuilder, translate errors with HttpApiError.*, and export only the handler from apiToHandler(ApiLive). This route is hand-rolled and bypasses middleware/dependency provisioning.

I can sketch an HttpApi route that wraps the Octokit call and maps failures to transport errors if you want to migrate this endpoint now.

Also applies to: 9-12

apps/web/app/(org)/invite/[inviteId]/page.tsx (1)

72-73: Type error: remove typeof on a type-only import.

userSelectProps is imported as a type; typeof userSelectProps is invalid. Cast to the type directly.

-      user={user as typeof userSelectProps | null}
+      user={user as userSelectProps | null}
🧹 Nitpick comments (34)
apps/web/app/s/[videoId]/page.tsx (4)

98-101: Narrow Props types for better safety (encode videoId, use Record for searchParams).

Avoid broad index signatures and the downstream cast. This tightens types where they’re consumed.

 type Props = {
-	params: Promise<{ [key: string]: string | string[] | undefined }>;
-	searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
+	params: Promise<{ videoId: string }>;
+	searchParams: Promise<Record<string, string | string[] | undefined>>;
 };

129-133: Prefer a single headers() call and fall back to the standard Referer header.

Reduces duplicate awaits and improves robustness when x-referrer isn’t present.

-	const referrer = (await headers()).get("x-referrer") || "";
+	const h = await headers();
+	const referrer = h.get("x-referrer") ?? h.get("referer") ?? "";

313-319: Confirm Effect.flatten semantics (Option → NoSuchElementException).

This relies on flatten converting None to a NoSuchElementException (caught below). If flatten doesn’t do this in your Effect version, this could pass an undefined video through and crash later.

If needed, replace with an explicit Option → Effect conversion for clarity and type safety (example approach):

  • Convert Option to Effect explicitly (e.g., Effect.fromOption / someOrFail)
  • Then map to the { needsPassword: false, video } shape

Would you like me to propose an exact patch tailored to your Effect version?


345-347: Don’t rethrow notFound(); return an Effect instead.

Throwing is redundant since notFound() already throws. Returning an Effect keeps the pipeline consistent.

-			NoSuchElementException: () => {
-				throw notFound();
-			},
+			NoSuchElementException: () => Effect.sync(notFound),
apps/web/components/pages/HomePage/Features.tsx (3)

105-116: Avoid shadowing component name with local alias

The inner destructuring aliases RiveComponent to CapAIArt, shadowing the component’s own identifier and inviting mistakes. Rename the alias.

-const CapAIArt = memo(() => {
-  const { RiveComponent: CapAIArt } = useRive({
+const CapAIArt = memo(() => {
+  const { RiveComponent: CapAIRive } = useRive({
     src: "/rive/bento.riv",
     artboard: "capai",
     animations: ["in"],
     autoplay: true,
     layout: new Layout({
       fit: Fit.Contain,
     }),
   });
-  return <CapAIArt className="w-full max-w-[550px] mx-auto h-[300px]" />;
+  return <CapAIRive className="w-full max-w-[550px] mx-auto h-[300px]" />;
 });

157-158: Remove inline JSX comments per repo guidelines

Inline JSX comments violate the no-comments guideline for TS/JS files. Please remove them.

Also applies to: 172-173, 186-187, 201-203


1-1: Optional: Rename file to kebab-case

File path uses PascalCase segments. The repo guideline prefers kebab-case filenames for TS/JS modules (components stay PascalCase in code). Consider features.tsx (and directory names likewise) for consistency.

apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx (1)

105-106: Ref type should not include null in the generic parameter

With strictNullChecks, React.RefObject already exposes current: T | null. Using RefObject<FolderHandle | null> makes current’s type (FolderHandle | null) | null and can break compatibility with React.Ref parameters.

-      {} as Record<
-        (typeof FolderOptions)[number]["value"],
-        React.RefObject<FolderHandle | null>
-      >,
+      {} as Record<
+        (typeof FolderOptions)[number]["value"],
+        React.RefObject<FolderHandle>
+      >,

Confirm NormalFolder/BlueFolder/RedFolder/YellowFolder forwardRef typings accept React.Ref. If any were changed to Ref<FolderHandle | null>, align them back to Ref.

apps/web/tsconfig.json (1)

17-17: strictNullChecks is redundant when strict is true

TypeScript enables strictNullChecks under "strict": true. Keeping both can be confusing.

-    "strictNullChecks": true,
packages/ui/package.json (1)

18-26: Treat React as a peerDependency in UI library

For @cap/ui, depend on the app’s React to avoid duplicate bundles and mismatched hooks. Move react and react-dom to peerDependencies (keep them in devDependencies for local builds).

Run the same workspace version audit script shared earlier to confirm single React/React‑DOM versions across the repo after this change.

packages/database/package.json (1)

29-47: Unify React/Next versions and use peerDependencies in libraries

  • Ensure React, React-DOM and Next are declared with the exact same version across all package.json (apps/web pins “19.1.1” vs “^19.1.1” elsewhere).
  • In library packages (e.g. @cap/database, @cap/ui, @cap/utils), move react/react-dom (and next if only for types) into peerDependencies —and keep them in devDependencies for local builds.
apps/web/app/api/video/delete/route.ts (1)

31-34: Map PolicyDenied to Forbidden to match declared errors.

Declared errors include Forbidden; handler currently returns Unauthorized.

Apply:

-							PolicyDenied: () => new HttpApiError.Unauthorized(),
+							PolicyDenied: () => new HttpApiError.Forbidden(),
apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx (2)

41-45: Align ref types across components (accept null)

The FolderOptions component signatures should accept React.Ref<FolderHandle | null> to match folderRefs’ type and avoid type friction.

-      (riveFile: RiveFile | undefined,
-        ref: React.Ref<FolderHandle>,
+      (riveFile: RiveFile | undefined,
+        ref: React.Ref<FolderHandle | null>,
       ) => <NormalFolder riveFile={riveFile} ref={ref} />,
...
-      (riveFile: RiveFile | undefined,
-        ref: React.Ref<FolderHandle>,
+      (riveFile: RiveFile | undefined,
+        ref: React.Ref<FolderHandle | null>,
       ) => <BlueFolder riveFile={riveFile} ref={ref} />,
...
-      (riveFile: RiveFile | undefined,
-        ref: React.Ref<FolderHandle>,
+      (riveFile: RiveFile | undefined,
+        ref: React.Ref<FolderHandle | null>,
       ) => <RedFolder riveFile={riveFile} ref={ref} />,
...
-      (riveFile: RiveFile | undefined,
-        ref: React.Ref<FolderHandle>,
+      (riveFile: RiveFile | undefined,
+        ref: React.Ref<FolderHandle | null>,
       ) => <YellowFolder riveFile={riveFile} ref={ref} />,

Also applies to: 51-53, 59-61, 67-69


172-175: Avoid unnecessary non-null cast

The option.component expects RiveFile | undefined, so casting forces a stronger type than needed.

-                  riveFile as RiveFile,
+                  riveFile,
apps/web/app/(org)/dashboard/layout.tsx (1)

66-68: Reuse a single cookie store instance

Minor perf/readability improvement: avoid multiple awaits to cookies().

-  const theme = (await cookies()).get("theme")?.value ?? "light";
-  const sidebar = (await cookies()).get("sidebarCollapsed")?.value ?? "false";
-  const referClicked = (await cookies()).get("referClicked")?.value ?? "false";
+  const cookieStore = await cookies();
+  const theme = cookieStore.get("theme")?.value ?? "light";
+  const sidebar = cookieStore.get("sidebarCollapsed")?.value ?? "false";
+  const referClicked = cookieStore.get("referClicked")?.value ?? "false";
packages/database/auth/auth-options.ts (1)

140-144: Reuse cookie store; confirm deletions take effect in this context

Consolidate cookie access, and verify that delete() here actually persists (NextAuth event handlers may not attach to a response).

           const { cookies } = await import("next/headers");
-          const dubId = (await cookies()).get("dub_id")?.value;
-          const dubPartnerData = (await cookies()).get(
-            "dub_partner_data",
-          )?.value;
+          const cookieStore = await cookies();
+          const dubId = cookieStore.get("dub_id")?.value;
+          const dubPartnerData = cookieStore.get("dub_partner_data")?.value;
...
-              (await cookies()).delete("dub_id");
+              cookieStore.delete("dub_id");
               if (dubPartnerData) {
-                (await cookies()).delete("dub_partner_data");
+                cookieStore.delete("dub_partner_data");
               }

Please verify cookie deletions persist for clients after sign-in completes (e.g., by checking Set-Cookie headers or observing cookie presence post-redirect).

Also applies to: 159-162

apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (2)

66-67: Use ReturnType for browser-safe timeout refs

Avoid NodeJS.Timeout in browser bundles.

-  const retryTimeout = useRef<NodeJS.Timeout | null>(null);
+  const retryTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);

97-114: Remove inline comments per codebase convention

The repository disallows inline comments in TS/TSX. Please remove these comment lines.

Also applies to: 198-214, 216-220, 262-267, 320-331

apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (3)

35-35: Drop unused RefObject import (and use React.Ref for icon prop)

RefObject isn’t needed if the icon prop accepts a generic React.Ref.

-import { cloneElement, RefObject, useRef, useState } from "react";
+import { cloneElement, useRef, useState } from "react";

456-460: Loosen icon ref typing to React.Ref to match useRef

This avoids friction between RefObject vs MutableRefObject from useRef.

-  icon: React.ReactElement<{
-    ref: RefObject<CogIconHandle | null>;
+  icon: React.ReactElement<{
+    ref: React.Ref<CogIconHandle | null>;
     className: string;
     size: number;
   }>;

465-465: Optional: make local ref nullable

Align with the prop type and typical forwardRef patterns.

-  const iconRef = useRef<CogIconHandle>(null);
+  const iconRef = useRef<CogIconHandle | null>(null);
apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx (2)

31-32: Remove unused RefObject import

Not needed if MenuItem icon prop uses React.Ref.

-  useRef,
-  useState,
-  RefObject,
+  useRef,
+  useState,

322-326: Loosen MenuItem icon ref typing to React.Ref

Consistent with useRef and various icon components.

- icon: React.ReactElement<{
-   ref: RefObject<DownloadIconHandle | null>;
+ icon: React.ReactElement<{
+   ref: React.Ref<DownloadIconHandle | null>;
    className: string;
    size: number;
  }>;
apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx (1)

54-58: Remove inline comments per repository rules

Inline and block comments are disallowed in TS/TSX; please remove these lines.

-  // Reset spaceName when dialog opens or space changes
...
-              // If the user removed the icon, send a removeIcon flag
...
-          {/* Space Members Input */}

Also applies to: 186-189, 235-235

apps/web/app/api/videos/[videoId]/retry-transcription/route.ts (1)

10-19: Preserve VideoId branding instead of casting.

Casting the awaited params to { videoId: Video.VideoId } sidesteps the branding check we previously had when the type flowed directly from the handler signature. We can keep the stronger type guarantees by re-branding the string returned from the params promise before proceeding.

Apply this diff to restore the branded validation:

-		const { videoId } = (await props.params) as { videoId: Video.VideoId };
+		const params = await props.params;
+		const videoId = Video.VideoId.make(params.videoId);
apps/web/components/pages/_components/ComparePlans.tsx (1)

59-61: Tighten RefObject types; adjust useRef generics to include null.

RefObject already models current: T | null. Prefer RefObject and make useRef generic include null for strictNullChecks.

-  commercialArtRef: React.RefObject<CommercialArtRef | null>;
-  proArtRef: React.RefObject<ProArtRef | null>;
+  commercialArtRef: React.RefObject<CommercialArtRef>;
+  proArtRef: React.RefObject<ProArtRef>;

Also update initial refs:

- const commercialArtRef = useRef<CommercialArtRef>(null);
- const proArtRef = useRef<ProArtRef>(null);
+ const commercialArtRef = useRef<CommercialArtRef | null>(null);
+ const proArtRef = useRef<ProArtRef | null>(null);
apps/web/app/(org)/dashboard/folder/[id]/page.tsx (1)

17-21: Signature migration to Promise-based params looks correct.

Consider branding the id once locally before use if downstream APIs expect FolderId brands.

const id = Folder.FolderId.make(params.id);
apps/web/package.json (1)

6-9: Be cautious enabling turbopack for production builds.

next build --turbopack is still evolving; confirm it’s stable for your deployment targets or gate behind an env flag.

apps/web/app/(org)/verify-otp/page.tsx (1)

16-22: Validate and constrain next redirect target to prevent open redirects.

Limit next to same-origin relative paths (e.g., starting with "/").

- redirect(searchParams.next || "/dashboard");
+ const next = (searchParams.next && searchParams.next.startsWith("/")) ? searchParams.next : "/dashboard";
+ redirect(next);
apps/web/app/api/releases/macos/route.ts (3)

21-46: Select the correct macOS asset by architecture and remove unused arch normalization.

Currently, arch is normalized but never used; the code picks the first .dmg, which can return the wrong build. Prefer deterministic selection (Apple Silicon first), then fall back.

Apply:

-    if (params.arch === "x86_64") {
-      params.arch = "x64";
-    }
+    const preferredArchOrder = ["aarch64", "arm64", "universal", "x86_64", "x64"];
@@
-    const asset = release.assets.find((asset) => asset.name.endsWith(".dmg"));
+    const asset =
+      release.assets.find(
+        (a) =>
+          a.name.endsWith(".dmg") &&
+          preferredArchOrder.some((arch) => a.name.toLowerCase().includes(arch)),
+      ) ?? release.assets.find((a) => a.name.endsWith(".dmg"));

47-50: Return a more accurate error status/message.

400 suggests a client error; this is a backend fetch failure. Use 502 and a clearer message.

-    return Response.json({ error: "Missing required fields" }, { status: 400 });
+    return Response.json(
+      { error: "Failed to fetch latest release" },
+      { status: 502 },
+    );

9-12: Remove the as any by giving GET an explicit type.

This avoids any and keeps strict TypeScript.

-export const GET = (async (
-  req: Request,
-  props: {
-    params: Promise<{
-      version: string;
-      target: string;
-      arch: string;
-    }>;
-  },
-) => {
+export async function GET(
+  req: Request,
+  props: {
+    params: Promise<{
+      version: string;
+      target: string;
+      arch: string;
+    }>;
+  },
+) {
@@
-}) as any;
+}

Also applies to: 51-51

apps/web/app/(org)/invite/[inviteId]/page.tsx (1)

14-14: Normalize import path.

Double slash is unnecessary and can confuse tooling; use a single slash.

-import { InviteAccept } from ".//InviteAccept";
+import { InviteAccept } from "./InviteAccept";
apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx (1)

142-142: Prefer ReturnType<typeof setInterval> for browser timers.

Line 142: In the browser, setInterval resolves to number, so storing it as NodeJS.Timeout can produce type friction when DOM libs take precedence. Swapping to ReturnType<typeof setInterval> keeps both Node and DOM signatures happy.

- const pollInterval = useRef<NodeJS.Timeout | undefined>(undefined);
+ const pollInterval = useRef<ReturnType<typeof setInterval> | undefined>(undefined);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0720f67 and 0dc7a5e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (61)
  • apps/desktop/package.json (1 hunks)
  • apps/web/actions/videos/password.ts (1 hunks)
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/_components/actions.ts (1 hunks)
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/caps/page.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/layout.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx (1 hunks)
  • apps/web/app/(org)/invite/[inviteId]/page.tsx (2 hunks)
  • apps/web/app/(org)/verify-otp/page.tsx (1 hunks)
  • apps/web/app/(site)/[slug]/page.tsx (2 hunks)
  • apps/web/app/(site)/blog/[slug]/page.tsx (2 hunks)
  • apps/web/app/(site)/docs/[...slug]/page.tsx (2 hunks)
  • apps/web/app/(site)/docs/[slug]/page.tsx (2 hunks)
  • apps/web/app/(site)/download/[platform]/route.ts (1 hunks)
  • apps/web/app/(site)/page.tsx (1 hunks)
  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx (2 hunks)
  • apps/web/app/api/erpc/route.ts (1 hunks)
  • apps/web/app/api/playlist/route.ts (2 hunks)
  • apps/web/app/api/releases/macos/route.ts (2 hunks)
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts (1 hunks)
  • apps/web/app/api/utils.ts (1 hunks)
  • apps/web/app/api/video/comment/route.ts (1 hunks)
  • apps/web/app/api/video/delete/route.ts (1 hunks)
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts (1 hunks)
  • apps/web/app/embed/[videoId]/page.tsx (3 hunks)
  • apps/web/app/robots.ts (1 hunks)
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (1 hunks)
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx (1 hunks)
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx (1 hunks)
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx (1 hunks)
  • apps/web/app/s/[videoId]/page.tsx (5 hunks)
  • apps/web/components/features/FeaturePage.tsx (1 hunks)
  • apps/web/components/forms/NewOrganization.tsx (1 hunks)
  • apps/web/components/pages/HomePage/Features.tsx (1 hunks)
  • apps/web/components/pages/HomePage/RecordingModes.tsx (1 hunks)
  • apps/web/components/pages/_components/ComparePlans.tsx (1 hunks)
  • apps/web/components/seo/types.ts (1 hunks)
  • apps/web/lib/features/transform.ts (1 hunks)
  • apps/web/lib/server.ts (3 hunks)
  • apps/web/next.config.mjs (0 hunks)
  • apps/web/package.json (5 hunks)
  • apps/web/tsconfig.json (1 hunks)
  • apps/web/utils/getBootstrapData.ts (1 hunks)
  • apps/workflow-manager/package.json (1 hunks)
  • apps/workflow-runner/package.json (1 hunks)
  • packages/database/auth/auth-options.ts (3 hunks)
  • packages/database/package.json (2 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/utils/package.json (1 hunks)
  • packages/web-api-contract-effect/package.json (1 hunks)
  • packages/web-backend/package.json (1 hunks)
  • packages/web-domain/package.json (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/next.config.mjs
🧰 Additional context used
📓 Path-based instructions (10)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx
  • apps/web/components/pages/HomePage/RecordingModes.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx
  • apps/web/app/(site)/download/[platform]/route.ts
  • apps/web/components/pages/HomePage/Features.tsx
  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/api/utils.ts
  • apps/web/actions/videos/password.ts
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
  • apps/web/app/(site)/blog/[slug]/page.tsx
  • apps/web/lib/features/transform.ts
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/(site)/[slug]/page.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx
  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/lib/server.ts
  • apps/web/app/robots.ts
  • apps/web/app/(org)/verify-otp/page.tsx
  • apps/web/components/seo/types.ts
  • apps/web/components/forms/NewOrganization.tsx
  • apps/web/app/(site)/docs/[...slug]/page.tsx
  • apps/web/app/(org)/dashboard/_components/actions.ts
  • apps/web/components/features/FeaturePage.tsx
  • apps/web/utils/getBootstrapData.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx
  • apps/web/app/(org)/invite/[inviteId]/page.tsx
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/(site)/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
  • apps/web/components/pages/_components/ComparePlans.tsx
  • apps/web/app/(site)/docs/[slug]/page.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx
  • apps/web/app/(site)/download/[platform]/route.ts
  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/api/utils.ts
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
  • apps/web/app/(site)/blog/[slug]/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/(site)/[slug]/page.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx
  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/robots.ts
  • apps/web/app/(org)/verify-otp/page.tsx
  • apps/web/app/(site)/docs/[...slug]/page.tsx
  • apps/web/app/(org)/dashboard/_components/actions.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx
  • apps/web/app/(org)/invite/[inviteId]/page.tsx
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/(site)/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
  • apps/web/app/(site)/docs/[slug]/page.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx
  • apps/web/components/pages/HomePage/RecordingModes.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx
  • apps/web/app/(site)/download/[platform]/route.ts
  • apps/web/components/pages/HomePage/Features.tsx
  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/api/utils.ts
  • apps/web/actions/videos/password.ts
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
  • apps/web/app/(site)/blog/[slug]/page.tsx
  • apps/web/lib/features/transform.ts
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx
  • packages/database/auth/auth-options.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/(site)/[slug]/page.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx
  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/lib/server.ts
  • apps/web/app/robots.ts
  • apps/web/app/(org)/verify-otp/page.tsx
  • apps/web/components/seo/types.ts
  • apps/web/components/forms/NewOrganization.tsx
  • apps/web/app/(site)/docs/[...slug]/page.tsx
  • apps/web/app/(org)/dashboard/_components/actions.ts
  • apps/web/components/features/FeaturePage.tsx
  • apps/web/utils/getBootstrapData.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx
  • apps/web/app/(org)/invite/[inviteId]/page.tsx
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/(site)/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
  • apps/web/components/pages/_components/ComparePlans.tsx
  • apps/web/app/(site)/docs/[slug]/page.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx
  • apps/web/components/pages/HomePage/RecordingModes.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx
  • apps/web/app/(site)/download/[platform]/route.ts
  • apps/web/components/pages/HomePage/Features.tsx
  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/api/utils.ts
  • apps/web/actions/videos/password.ts
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
  • apps/web/app/(site)/blog/[slug]/page.tsx
  • apps/web/lib/features/transform.ts
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx
  • packages/database/auth/auth-options.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/(site)/[slug]/page.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx
  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/lib/server.ts
  • apps/web/app/robots.ts
  • apps/web/app/(org)/verify-otp/page.tsx
  • apps/web/components/seo/types.ts
  • apps/web/components/forms/NewOrganization.tsx
  • apps/web/app/(site)/docs/[...slug]/page.tsx
  • apps/web/app/(org)/dashboard/_components/actions.ts
  • apps/web/components/features/FeaturePage.tsx
  • apps/web/utils/getBootstrapData.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx
  • apps/web/app/(org)/invite/[inviteId]/page.tsx
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/(site)/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
  • apps/web/components/pages/_components/ComparePlans.tsx
  • apps/web/app/(site)/docs/[slug]/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx
  • apps/web/components/pages/HomePage/RecordingModes.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx
  • apps/web/app/(site)/download/[platform]/route.ts
  • apps/web/components/pages/HomePage/Features.tsx
  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/api/utils.ts
  • apps/web/actions/videos/password.ts
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
  • apps/web/app/(site)/blog/[slug]/page.tsx
  • apps/web/lib/features/transform.ts
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx
  • packages/database/auth/auth-options.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/(site)/[slug]/page.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx
  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/lib/server.ts
  • apps/web/app/robots.ts
  • apps/web/app/(org)/verify-otp/page.tsx
  • apps/web/components/seo/types.ts
  • apps/web/components/forms/NewOrganization.tsx
  • apps/web/app/(site)/docs/[...slug]/page.tsx
  • apps/web/app/(org)/dashboard/_components/actions.ts
  • apps/web/components/features/FeaturePage.tsx
  • apps/web/utils/getBootstrapData.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx
  • apps/web/app/(org)/invite/[inviteId]/page.tsx
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/(site)/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
  • apps/web/components/pages/_components/ComparePlans.tsx
  • apps/web/app/(site)/docs/[slug]/page.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx
  • apps/web/components/pages/HomePage/RecordingModes.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/caps/components/FoldersDropdown.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/page.tsx
  • apps/web/app/(site)/download/[platform]/route.ts
  • apps/web/components/pages/HomePage/Features.tsx
  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/api/utils.ts
  • apps/web/actions/videos/password.ts
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx
  • apps/web/app/(site)/blog/[slug]/page.tsx
  • apps/web/lib/features/transform.ts
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/(site)/[slug]/page.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/CustomDomainDialog.tsx
  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/lib/server.ts
  • apps/web/app/robots.ts
  • apps/web/app/(org)/verify-otp/page.tsx
  • apps/web/components/seo/types.ts
  • apps/web/components/forms/NewOrganization.tsx
  • apps/web/app/(site)/docs/[...slug]/page.tsx
  • apps/web/app/(org)/dashboard/_components/actions.ts
  • apps/web/components/features/FeaturePage.tsx
  • apps/web/utils/getBootstrapData.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/SpaceDialog.tsx
  • apps/web/app/(org)/invite/[inviteId]/page.tsx
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/(site)/page.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
  • apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx
  • apps/web/components/pages/_components/ComparePlans.tsx
  • apps/web/app/(site)/docs/[slug]/page.tsx
apps/web/app/api/**/route.ts

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/app/api/**/route.ts: Place API routes only under apps/web/app/api and implement each route in a route.ts file
Construct API routes with @effect/platform HttpApi/HttpApiBuilder and export only the handler from apiToHandler(ApiLive)
Map domain errors to transport errors with HttpApiError.* and keep error translation exhaustive
Use HttpAuthMiddleware for required auth and provideOptionalAuth for guest routes; avoid duplicate session lookups
Provide dependencies via Layer.provide in API routes instead of manual provideService calls

Files:

  • apps/web/app/api/video/comment/route.ts
  • apps/web/app/api/releases/macos/route.ts
  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
  • apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts
  • apps/web/app/api/videos/[videoId]/retry-transcription/route.ts
apps/web/app/api/*

📄 CodeRabbit inference engine (AGENTS.md)

apps/web/app/api/*: API routes in Next.js (apps/web/app/api/*) must use @effect/platform's HttpApi builder and follow the existing class/group/endpoint pattern; avoid ad-hoc handlers.
Convert effectful APIs to Next.js handlers using apiToHandler(ApiLive) and export only the returned handler; avoid calling runPromise directly in route files.
Acquire backend services inside Effect.gen and wire them using Layer.provide/HttpApiBuilder.group, translating errors to HttpApiError as appropriate.
On the server, always run effects through EffectRuntime.runPromise after provideOptionalAuth to ensure cookies and per-request context are attached.

Files:

  • apps/web/app/api/utils.ts
apps/web/actions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

All Groq/OpenAI calls must be implemented in Next.js Server Actions under apps/web/actions; do not place AI calls elsewhere

Files:

  • apps/web/actions/videos/password.ts
packages/web-api-contract-effect/**

📄 CodeRabbit inference engine (CLAUDE.md)

Update shared HTTP contracts in packages/web-api-contract-effect alongside any API route changes to keep schemas in sync

Files:

  • packages/web-api-contract-effect/package.json
🧠 Learnings (6)
📚 Learning: 2025-09-22T14:17:47.380Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.380Z
Learning: Applies to **/*.{ts,tsx} : Use strict TypeScript and avoid any; leverage shared types from packages

Applied to files:

  • apps/web/tsconfig.json
📚 Learning: 2025-09-22T14:19:55.985Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: AGENTS.md:0-0
Timestamp: 2025-09-22T14:19:55.985Z
Learning: Applies to apps/web/app/api/* : On the server, always run effects through `EffectRuntime.runPromise` after `provideOptionalAuth` to ensure cookies and per-request context are attached.

Applied to files:

  • apps/web/lib/server.ts
📚 Learning: 2025-09-22T14:19:55.985Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: AGENTS.md:0-0
Timestamp: 2025-09-22T14:19:55.985Z
Learning: Applies to apps/web/app/api/* : API routes in Next.js (`apps/web/app/api/*`) must use `effect/platform`'s `HttpApi` builder and follow the existing class/group/endpoint pattern; avoid ad-hoc handlers.

Applied to files:

  • apps/web/lib/server.ts
📚 Learning: 2025-09-22T14:17:47.380Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.380Z
Learning: Applies to apps/web/app/api/**/route.ts : Construct API routes with effect/platform HttpApi/HttpApiBuilder and export only the handler from apiToHandler(ApiLive)

Applied to files:

  • apps/web/app/api/erpc/route.ts
  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
📚 Learning: 2025-09-22T14:19:55.985Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: AGENTS.md:0-0
Timestamp: 2025-09-22T14:19:55.985Z
Learning: Applies to apps/web/app/api/* : Convert effectful APIs to Next.js handlers using `apiToHandler(ApiLive)` and export only the returned `handler`; avoid calling `runPromise` directly in route files.

Applied to files:

  • apps/web/app/api/video/delete/route.ts
  • apps/web/app/api/playlist/route.ts
📚 Learning: 2025-09-22T14:17:47.380Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.380Z
Learning: Applies to packages/web-api-contract-effect/** : Update shared HTTP contracts in packages/web-api-contract-effect alongside any API route changes to keep schemas in sync

Applied to files:

  • packages/web-api-contract-effect/package.json
  • packages/web-backend/package.json
  • packages/web-domain/package.json
🧬 Code graph analysis (21)
apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx (5)
apps/web/app/(site)/docs/[...slug]/page.tsx (1)
  • generateMetadata (22-74)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/(site)/blog/[slug]/page.tsx (1)
  • generateMetadata (24-68)
apps/web/app/(org)/invite/[inviteId]/page.tsx (1)
  • generateMetadata (20-33)
apps/web/app/(site)/[slug]/page.tsx (1)
  • generateMetadata (10-32)
apps/web/app/(org)/dashboard/folder/[id]/page.tsx (1)
packages/web-domain/src/Folder.ts (3)
  • Folder (19-27)
  • FolderId (8-8)
  • FolderId (9-9)
apps/web/app/api/video/comment/route.ts (2)
apps/web/app/api/erpc/route.ts (1)
  • POST (18-18)
apps/web/utils/helpers.ts (1)
  • rateLimitMiddleware (30-64)
apps/web/actions/videos/password.ts (1)
packages/database/crypto.ts (1)
  • encrypt (63-96)
apps/web/app/(org)/dashboard/caps/components/NewFolderDialog.tsx (1)
apps/web/app/(org)/dashboard/caps/components/Folders.tsx (1)
  • FolderHandle (7-10)
apps/web/app/(site)/blog/[slug]/page.tsx (5)
apps/web/app/(site)/docs/[...slug]/page.tsx (1)
  • generateMetadata (22-74)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/(org)/invite/[inviteId]/page.tsx (1)
  • generateMetadata (20-33)
apps/web/app/(site)/[slug]/page.tsx (1)
  • generateMetadata (10-32)
apps/web/app/(site)/docs/[slug]/page.tsx (1)
  • generateMetadata (14-49)
apps/web/app/s/[videoId]/page.tsx (3)
apps/web/app/(site)/docs/[...slug]/page.tsx (1)
  • generateMetadata (22-74)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/(org)/invite/[inviteId]/page.tsx (1)
  • generateMetadata (20-33)
apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx (1)
packages/web-domain/src/Folder.ts (3)
  • Folder (19-27)
  • FolderId (8-8)
  • FolderId (9-9)
apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (1)
apps/web/app/(org)/dashboard/_components/AnimatedIcons/Cog.tsx (1)
  • CogIconHandle (8-11)
apps/web/app/(site)/[slug]/page.tsx (4)
apps/web/app/(site)/docs/[...slug]/page.tsx (1)
  • generateMetadata (22-74)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/(site)/blog/[slug]/page.tsx (1)
  • generateMetadata (24-68)
apps/web/app/(org)/invite/[inviteId]/page.tsx (1)
  • generateMetadata (20-33)
apps/web/app/embed/[videoId]/page.tsx (2)
apps/web/app/(site)/docs/[...slug]/page.tsx (1)
  • generateMetadata (22-74)
apps/web/app/s/[videoId]/page.tsx (1)
  • generateMetadata (125-254)
apps/web/app/robots.ts (1)
apps/web/lib/seo-pages.ts (1)
  • seoPages (31-66)
apps/web/app/(site)/docs/[...slug]/page.tsx (6)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/s/[videoId]/page.tsx (1)
  • generateMetadata (125-254)
apps/web/app/(site)/blog/[slug]/page.tsx (1)
  • generateMetadata (24-68)
apps/web/app/(org)/invite/[inviteId]/page.tsx (1)
  • generateMetadata (20-33)
apps/web/app/(site)/[slug]/page.tsx (1)
  • generateMetadata (10-32)
apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx (1)
  • generateMetadata (17-55)
apps/web/app/(org)/invite/[inviteId]/page.tsx (2)
apps/web/app/(site)/docs/[...slug]/page.tsx (1)
  • generateMetadata (22-74)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/api/releases/macos/route.ts (4)
apps/web/app/api/erpc/route.ts (1)
  • GET (17-17)
apps/web/app/api/playlist/route.ts (1)
  • GET (245-245)
apps/web/app/(site)/download/[platform]/route.ts (1)
  • GET (8-45)
apps/web/app/api/releases/tauri/[version]/[target]/[arch]/route.ts (1)
  • GET (9-71)
apps/web/app/api/erpc/route.ts (3)
apps/web/app/api/playlist/route.ts (1)
  • GET (245-245)
apps/web/app/api/releases/macos/route.ts (1)
  • GET (9-51)
apps/web/app/api/video/comment/route.ts (2)
  • GET (96-98)
  • POST (91-94)
apps/web/app/api/playlist/route.ts (4)
apps/web/app/embed/[videoId]/page.tsx (1)
  • dynamic (26-26)
apps/web/app/s/[videoId]/page.tsx (1)
  • dynamic (37-37)
apps/web/app/api/settings/billing/usage/route.ts (2)
  • dynamic (7-7)
  • GET (9-47)
apps/web/app/api/erpc/route.ts (1)
  • GET (17-17)
apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx (1)
apps/web/app/(org)/dashboard/_components/AnimatedIcons/Download.tsx (1)
  • DownloadIconHandle (9-12)
apps/web/app/(org)/dashboard/folder/[id]/components/SubfolderDialog.tsx (1)
apps/web/app/(org)/dashboard/caps/components/Folders.tsx (1)
  • FolderHandle (7-10)
apps/web/components/pages/_components/ComparePlans.tsx (2)
apps/web/components/pages/HomePage/Pricing/CommercialArt.tsx (1)
  • CommercialArtRef (5-8)
apps/web/components/pages/HomePage/Pricing/ProArt.tsx (1)
  • ProArtRef (5-8)
apps/web/app/(site)/docs/[slug]/page.tsx (7)
apps/web/app/(site)/docs/[...slug]/page.tsx (2)
  • generateMetadata (22-74)
  • DocPage (76-201)
apps/web/app/embed/[videoId]/page.tsx (1)
  • generateMetadata (35-113)
apps/web/app/s/[videoId]/page.tsx (1)
  • generateMetadata (125-254)
apps/web/app/(site)/blog/[slug]/page.tsx (1)
  • generateMetadata (24-68)
apps/web/app/(org)/invite/[inviteId]/page.tsx (1)
  • generateMetadata (20-33)
apps/web/app/(site)/[slug]/page.tsx (1)
  • generateMetadata (10-32)
apps/web/app/(site)/tools/convert/[conversionPath]/page.tsx (1)
  • generateMetadata (17-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)

@oscartbeaumont
Copy link
Contributor Author

oscartbeaumont commented Sep 25, 2025

@coderabbitai don't review this pr

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

Tip

For best results, initiate chat on the files or code changes.

@oscartbeaumont Understood! I won't review this PR. The automated review will be skipped for PR #1033.

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0dc7a5e and 17a24e8.

📒 Files selected for processing (3)
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/VirtualizedVideoGrid.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx
🧬 Code graph analysis (1)
apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx (1)
apps/web/app/(org)/dashboard/_components/AnimatedIcons/Download.tsx (1)
  • DownloadIconHandle (9-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

@oscartbeaumont I understand. I'll pause the automatic reviews for this PR as requested.

✅ Actions performed

Reviews paused.

@ameer2468 ameer2468 merged commit 666d20f into main Sep 25, 2025
16 checks passed
@oscartbeaumont oscartbeaumont deleted the upgrade-nextjs branch September 25, 2025 23:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants