-
Notifications
You must be signed in to change notification settings - Fork 53
refactor(desktop): Manage auth token in renderer instead of main thread for cleaner code / better interop with better auth #741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ad for cleaner code / better interop with better auth
📝 WalkthroughWalkthroughReworks desktop authentication to a token-centric flow (Better Auth), moves token persistence to encrypted disk in the main process, introduces an Electron-specific tRPC client/provider, and removes the legacy AuthService plus the user/tasks routers; updates ~100 renderer files to use the new electronTrpc client. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Renderer as Renderer (React)
participant Main as Electron Main
participant AuthClient as Better Auth Client
participant API as Backend API
User->>Renderer: Click "Sign in"
Renderer->>Main: electronTrpc.auth.signIn (request start)
Main->>Main: generate CSRF state, save transient state
Main->>User: open OAuth URL in external browser
User->>API: complete OAuth in browser
API->>Main: deep link callback (token, expiresAt, state)
Main->>Main: parseAuthDeepLink -> handleAuthCallback(validate state)
Main->>Main: saveToken(encrypted) & emit "token-saved"
Main->>Renderer: onTokenChanged subscription event (token)
Renderer->>AuthClient: setAuthToken(token)
Renderer->>API: authenticated requests via authClient (Bearer token)
API->>Renderer: session data
Renderer->>Renderer: update UI as signed-in
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
🚀 Preview Deployment🔗 Preview Links
Preview updates automatically with new commits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/react-query/workspaces/useCloseWorkspace.ts (1)
137-151: Add error logging for debugging.The error is silently discarded. Per coding guidelines, errors should at minimum be logged with context to aid debugging.
Proposed fix
- onError: (_err, _variables, context) => { + onError: (err, variables, context) => { // Rollback to previous state on error + console.error("[workspaces/close] Failed to close workspace:", { + error: err, + workspaceId: variables.id, + }); if (context?.previousGrouped !== undefined) {
🤖 Fix all issues with AI agents
In @apps/desktop/src/lib/trpc/routers/auth/index.ts:
- Around line 105-111: The signOut mutation currently swallows any fs.unlink
errors silently; update the try/catch in the signOut publicProcedure to catch
the error and log it (e.g., using console.error or the app's logger) with
context including TOKEN_FILE and the error object so failures (like permission
issues) are visible; keep returning { success: true } if desired but ensure the
catch does not remain empty.
- Around line 48-56: The subscription in onTokenChanged calls
loadToken().then(...) without handling rejections, causing unhandled promise
rejections; wrap the initial token load with proper error handling (e.g., add a
.catch(...) to the Promise chain or use an async IIFE with try/catch) and on
failure call emit.error(error) or emit.next(null) as appropriate so the
observable handles errors gracefully; update the loadToken call inside the
observable returned by publicProcedure.subscription to ensure any rejection is
caught and forwarded via emit.
In @apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts:
- Around line 34-36: The catch block in
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts that currently
swallows errors and returns { token: null, expiresAt: null } should capture the
caught error (e.g., catch (err)) and log it before returning; update that catch
to log the error using the project's logging utility (or console.error if none
exists) with a clear message like "Failed to load auth token" and the error
object, then continue to return { token: null, expiresAt: null } so behavior is
unchanged but failures are recorded for debugging.
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx:
- Around line 51-55: The async switchOrganization function doesn't handle
failures from authClient.organization.setActive; wrap the await call in a
try/catch inside switchOrganization, log the error with contextual details
(e.g., newOrgId and a descriptive message) using the existing logger (or
console/error logger if none), and surface the failure appropriately (rethrow or
return a rejection/boolean) so callers can react; ensure you reference
switchOrganization and authClient.organization.setActive when making the change.
- Around line 57-60: The handleSignOut handler currently calls
authClient.signOut() and signOutMutation.mutate() without any error handling;
wrap these calls in a try/catch and handle failures: call await
authClient.signOut() inside try, then execute signOutMutation.mutate() (or call
its async variant) and in catch log the error (use the existing logger or
console.error) and surface user-facing feedback (toast/error dialog) so the UI
won't silently fail; ensure to keep any necessary cleanup in finally (e.g.,
reset local auth state only on success) and reference the handleSignOut
function, authClient.signOut, and signOutMutation.mutate when making the
changes.
In @packages/auth/package.json:
- Around line 14-18: The package export "./electron-client" in package.json
points to a missing file "./src/electron-client.ts"; either add the missing
source by creating packages/auth/src/electron-client.ts implementing the
intended electron client API (matching any referenced types/exports) or remove
the "./electron-client" export entry from package.json if the feature was added
prematurely; update any imports that reference "./electron-client" (or adjust
their paths) to keep exports and source files consistent.
🧹 Nitpick comments (8)
apps/desktop/src/renderer/react-query/workspaces/useCloseWorkspace.ts (1)
152-160: Consider parallelizing independent invalidations.The two invalidation calls are independent and could run concurrently for slightly better performance.
Proposed fix
onSuccess: async (...args) => { // Invalidate to ensure consistency with backend state - await utils.workspaces.invalidate(); - // Invalidate project queries since close updates project metadata - await utils.projects.getRecents.invalidate(); + await Promise.all([ + utils.workspaces.invalidate(), + // Invalidate project queries since close updates project metadata + utils.projects.getRecents.invalidate(), + ]); // Call user's onSuccess if provided await options?.onSuccess?.(...args); },apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (1)
3-4: Inconsistent import path style.Line 3 uses the alias path (
renderer/lib/electron-trpc) while line 4 uses a relative path (../../lib/trpc-client). Per coding guidelines, prefer using aliases as defined intsconfig.jsonconsistently.Suggested fix
import { electronTrpc } from "renderer/lib/electron-trpc"; -import { electronReactClient } from "../../lib/trpc-client"; +import { electronReactClient } from "renderer/lib/trpc-client";apps/desktop/src/lib/trpc/routers/auth/index.ts (1)
80-84: Extract magic number to named constant.Per coding guidelines, magic numbers should be extracted to named constants for clarity and maintainability.
Suggested refactor
At the top of the file:
const STATE_EXPIRY_MS = 10 * 60 * 1000; // 10 minutesThen update usage:
-const tenMinutesAgo = Date.now() - 10 * 60 * 1000; +const stateExpiryThreshold = Date.now() - STATE_EXPIRY_MS; for (const [s, ts] of stateStore) { - if (ts < tenMinutesAgo) stateStore.delete(s); + if (ts < stateExpiryThreshold) stateStore.delete(s); }apps/desktop/src/renderer/routes/_authenticated/settings/keyboard/page.tsx (1)
42-89: Consider extractingHotkeyRowto a separate file.Per coding guidelines, prefer one component per file.
HotkeyRowcould be extracted to a separate file likeHotkeyRow.tsxin the same directory for better organization and reusability.apps/desktop/src/renderer/react-query/workspaces/useSetActiveWorkspace.ts (1)
58-59: Consider improving type safety on theonSuccesscallback forwarding.The
as anycast is a known workaround for TypeScript inference limitations with spread args. The biome-ignore comment documents the intent, which is acceptable.Alternative: Use explicit callback signature
If type safety becomes important here, you could define explicit parameter types instead of spreading:
- // biome-ignore lint/suspicious/noExplicitAny: spread args for compatibility - await (options?.onSuccess as any)?.(data, variables, ...rest); + await options?.onSuccess?.(data, variables, rest[0]);However, this may break if the mutation callback signature changes. The current approach with the documented cast is pragmatic.
apps/desktop/src/renderer/routes/sign-in/page.tsx (1)
29-32: Consider adding user feedback for sign-in errors.The
signInMutationdoesn't show error handling in this component. Users may not receive feedback if the sign-in flow fails.💡 Optional: Add error state feedback
const signIn = (provider: AuthProvider) => { posthog.capture("auth_started", { provider }); - signInMutation.mutate({ provider }); + signInMutation.mutate({ provider }, { + onError: (error) => { + console.error("[auth/signIn] Sign-in failed:", error); + // Optionally show a toast or inline error message + }, + }); };apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)
53-59: Consider removing redundant effect.This effect duplicates
setAuthTokencalls that are already made elsewhere:
- Line 37 & 47: during subscription and hydration
- Line 64: when clearing on session logout
Every code path that modifies
tokenalready callssetAuthToken, making this synchronization effect unnecessary.♻️ Suggested removal
- useEffect(() => { - if (token) { - setAuthToken(token); - } else { - setAuthToken(null); - } - }, [token]); -apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts (1)
14-14:stateStorelacks TTL, risking memory accumulation.If OAuth flows are abandoned (user closes browser, network failure, etc.), entries remain in
stateStoreindefinitely. Consider adding expiration timestamps and periodic cleanup.Suggested approach with TTL
-export const stateStore = new Map<string, number>(); +const STATE_TTL_MS = 10 * 60 * 1000; // 10 minutes +export const stateStore = new Map<string, number>(); + +// Cleanup expired states periodically +setInterval(() => { + const now = Date.now(); + for (const [state, timestamp] of stateStore) { + if (now - timestamp > STATE_TTL_MS) { + stateStore.delete(state); + } + } +}, 60 * 1000);Then when adding state:
stateStore.set(state, Date.now());And in
handleAuthCallback, validate the timestamp:const timestamp = stateStore.get(params.state); if (!timestamp || Date.now() - timestamp > STATE_TTL_MS) { return { success: false, error: "Invalid or expired auth session" }; }
| onTokenChanged: publicProcedure.subscription(() => { | ||
| return observable<{ token: string; expiresAt: string } | null>((emit) => { | ||
| // Emit initial token on subscription | ||
| loadToken().then((initial) => { | ||
| if (initial.token && initial.expiresAt) { | ||
| emit.next({ token: initial.token, expiresAt: initial.expiresAt }); | ||
| } | ||
| }); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential rejection from initial token load.
The loadToken().then() call has no error handler. If loadToken() rejects, it will cause an unhandled promise rejection.
Suggested fix
// Emit initial token on subscription
-loadToken().then((initial) => {
+loadToken().then((initial) => {
if (initial.token && initial.expiresAt) {
emit.next({ token: initial.token, expiresAt: initial.expiresAt });
}
+}).catch((err) => {
+ console.error("[auth/onTokenChanged] Failed to load initial token:", err);
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onTokenChanged: publicProcedure.subscription(() => { | |
| return observable<{ token: string; expiresAt: string } | null>((emit) => { | |
| // Emit initial token on subscription | |
| loadToken().then((initial) => { | |
| if (initial.token && initial.expiresAt) { | |
| emit.next({ token: initial.token, expiresAt: initial.expiresAt }); | |
| } | |
| }); | |
| onTokenChanged: publicProcedure.subscription(() => { | |
| return observable<{ token: string; expiresAt: string } | null>((emit) => { | |
| // Emit initial token on subscription | |
| loadToken().then((initial) => { | |
| if (initial.token && initial.expiresAt) { | |
| emit.next({ token: initial.token, expiresAt: initial.expiresAt }); | |
| } | |
| }).catch((err) => { | |
| console.error("[auth/onTokenChanged] Failed to load initial token:", err); | |
| }); |
🤖 Prompt for AI Agents
In @apps/desktop/src/lib/trpc/routers/auth/index.ts around lines 48 - 56, The
subscription in onTokenChanged calls loadToken().then(...) without handling
rejections, causing unhandled promise rejections; wrap the initial token load
with proper error handling (e.g., add a .catch(...) to the Promise chain or use
an async IIFE with try/catch) and on failure call emit.error(error) or
emit.next(null) as appropriate so the observable handles errors gracefully;
update the loadToken call inside the observable returned by
publicProcedure.subscription to ensure any rejection is caught and forwarded via
emit.
| signOut: publicProcedure.mutation(async () => { | ||
| await authService.signOut(); | ||
| console.log("[auth] Clearing token"); | ||
| try { | ||
| await fs.unlink(TOKEN_FILE); | ||
| } catch {} | ||
| return { success: true }; | ||
| }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty catch block silently swallows errors.
Per coding guidelines, errors should never be swallowed silently. The fs.unlink failure (e.g., permission issues) should be logged.
Suggested fix
signOut: publicProcedure.mutation(async () => {
console.log("[auth] Clearing token");
try {
await fs.unlink(TOKEN_FILE);
- } catch {}
+ } catch (err) {
+ // ENOENT is expected if token file doesn't exist
+ if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
+ console.error("[auth/signOut] Failed to clear token file:", err);
+ }
+ }
return { success: true };
}),🤖 Prompt for AI Agents
In @apps/desktop/src/lib/trpc/routers/auth/index.ts around lines 105 - 111, The
signOut mutation currently swallows any fs.unlink errors silently; update the
try/catch in the signOut publicProcedure to catch the error and log it (e.g.,
using console.error or the app's logger) with context including TOKEN_FILE and
the error object so failures (like permission issues) are visible; keep
returning { success: true } if desired but ensure the catch does not remain
empty.
| } catch { | ||
| return { token: null, expiresAt: null }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Silent error swallowing masks potential issues.
Per coding guidelines, errors should never be swallowed silently. If token loading fails due to corruption, permission issues, or decryption errors, this should be logged for debugging.
Proposed fix
- } catch {
+ } catch (error) {
+ console.log("[auth] Failed to load token from disk:", error);
return { token: null, expiresAt: null };
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch { | |
| return { token: null, expiresAt: null }; | |
| } | |
| } catch (error) { | |
| console.log("[auth] Failed to load token from disk:", error); | |
| return { token: null, expiresAt: null }; | |
| } |
🤖 Prompt for AI Agents
In @apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts around lines
34 - 36, The catch block in
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts that currently
swallows errors and returns { token: null, expiresAt: null } should capture the
caught error (e.g., catch (err)) and log it before returning; update that catch
to log the error using the project's logging utility (or console.error if none
exists) with a clear message like "Failed to load auth token" and the error
object, then continue to return { token: null, expiresAt: null } so behavior is
unchanged but failures are recorded for debugging.
| const switchOrganization = async (newOrgId: string) => { | ||
| await setActiveOrg.mutateAsync({ organizationId: newOrgId }); | ||
| await authClient.organization.setActive({ | ||
| organizationId: newOrgId, | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for organization switch.
The async operation could fail silently. Per coding guidelines, errors should be logged with context.
Suggested improvement
const switchOrganization = async (newOrgId: string) => {
- await authClient.organization.setActive({
- organizationId: newOrgId,
- });
+ try {
+ await authClient.organization.setActive({
+ organizationId: newOrgId,
+ });
+ } catch (err) {
+ console.error("[OrganizationDropdown/switchOrganization] Failed:", err);
+ }
};🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
around lines 51 - 55, The async switchOrganization function doesn't handle
failures from authClient.organization.setActive; wrap the await call in a
try/catch inside switchOrganization, log the error with contextual details
(e.g., newOrgId and a descriptive message) using the existing logger (or
console/error logger if none), and surface the failure appropriately (rethrow or
return a rejection/boolean) so callers can react; ensure you reference
switchOrganization and authClient.organization.setActive when making the change.
| const handleSignOut = async () => { | ||
| await authClient.signOut(); | ||
| signOutMutation.mutate(); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for sign-out operations.
Both authClient.signOut() and signOutMutation.mutate() can fail (network issues, IPC errors). Currently, failures are silently ignored which could leave the user in an inconsistent state.
Suggested improvement
const handleSignOut = async () => {
- await authClient.signOut();
- signOutMutation.mutate();
+ try {
+ await authClient.signOut();
+ await signOutMutation.mutateAsync();
+ } catch (err) {
+ console.error("[OrganizationDropdown/signOut] Failed to sign out:", err);
+ }
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleSignOut = async () => { | |
| await authClient.signOut(); | |
| signOutMutation.mutate(); | |
| }; | |
| const handleSignOut = async () => { | |
| try { | |
| await authClient.signOut(); | |
| await signOutMutation.mutateAsync(); | |
| } catch (err) { | |
| console.error("[OrganizationDropdown/signOut] Failed to sign out:", err); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
around lines 57 - 60, The handleSignOut handler currently calls
authClient.signOut() and signOutMutation.mutate() without any error handling;
wrap these calls in a try/catch and handle failures: call await
authClient.signOut() inside try, then execute signOutMutation.mutate() (or call
its async variant) and in catch log the error (use the existing logger or
console.error) and surface user-facing feedback (toast/error dialog) so the UI
won't silently fail; ensure to keep any necessary cleanup in finally (e.g.,
reset local auth state only on success) and reference the handleSignOut
function, authClient.signOut, and signOutMutation.mutate when making the
changes.
| }, | ||
| "./electron-client": { | ||
| "types": "./src/electron-client.ts", | ||
| "default": "./src/electron-client.ts" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
fd -t f "electron-client.ts" packages/auth/srcRepository: superset-sh/superset
Length of output: 46
🏁 Script executed:
find . -name "*electron-client*" -type fRepository: superset-sh/superset
Length of output: 46
Blocker: Referenced file does not exist.
The ./electron-client export references ./src/electron-client.ts, but this file does not exist in the repository. The export entry cannot be approved without the corresponding source file.
Create packages/auth/src/electron-client.ts or remove the export entry if it was added prematurely.
🤖 Prompt for AI Agents
In @packages/auth/package.json around lines 14 - 18, The package export
"./electron-client" in package.json points to a missing file
"./src/electron-client.ts"; either add the missing source by creating
packages/auth/src/electron-client.ts implementing the intended electron client
API (matching any referenced types/exports) or remove the "./electron-client"
export entry from package.json if the feature was added prematurely; update any
imports that reference "./electron-client" (or adjust their paths) to keep
exports and source files consistent.
There was a problem hiding this 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 (1)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (1)
24-24: Use the exported constant instead of redefining locally.
GITHUB_STATUS_STALE_TIMEis already exported fromapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/constants.tswith a value of30_000(30 seconds). This file redefines it as5 * 60 * 1000(5 minutes), creating a 10x inconsistency in cache freshness across the workspace views.Import the constant from constants.ts instead to ensure consistent GitHub status refresh behavior:
import { GITHUB_STATUS_STALE_TIME } from "../../WorkspaceSidebar/WorkspaceListItem/constants";Remove the local definition on line 24.
🤖 Fix all issues with AI agents
In @apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx:
- Around line 33-44: The subscription handler for
electronTrpc.auth.onTokenChanged.useSubscription is causing an infinite loop by
calling persistMutation.mutate (which calls saveToken and re-emits
"token-saved"); update the handler to stop re-persisting: remove the
persistMutation.mutate(...) call and only call setToken and setAuthToken when
data is received (you may keep the token/expiresAt presence check), leaving
token persistence to the original saveToken path that emits authEvents; ensure
no other code in this handler triggers saveToken/authEvents.emit.
♻️ Duplicate comments (4)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx (2)
51-55: Missing error handling for organization switch (previously flagged).The async
authClient.organization.setActive()call can fail silently. This was flagged in a previous review and remains unaddressed.
57-60: Missing error handling for sign-out (previously flagged).Both
authClient.signOut()andsignOutMutation.mutate()can fail. This was flagged in a previous review and remains unaddressed.apps/desktop/src/lib/trpc/routers/auth/index.ts (2)
48-55: Handle potential rejection from initial token load.The
loadToken().then()call lacks an error handler, which will cause an unhandled promise rejection ifloadToken()fails.Suggested fix
// Emit initial token on subscription loadToken().then((initial) => { if (initial.token && initial.expiresAt) { emit.next({ token: initial.token, expiresAt: initial.expiresAt }); } +}).catch((err) => { + console.error("[auth/onTokenChanged] Failed to load initial token:", err); });
106-112: Empty catch block silently swallows errors.Per coding guidelines, errors should never be swallowed silently. The
fs.unlinkfailure (e.g., permission issues) should be logged.Suggested fix
signOut: publicProcedure.mutation(async () => { console.log("[auth] Clearing token"); try { await fs.unlink(TOKEN_FILE); - } catch {} + } catch (err) { + // ENOENT is expected if token file doesn't exist + if ((err as NodeJS.ErrnoException).code !== "ENOENT") { + console.error("[auth/signOut] Failed to clear token file:", err); + } + } return { success: true }; }),
🧹 Nitpick comments (12)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1)
145-158: Migration looks correct; consider adding error handling for better UX.The mutation hooks are properly migrated to
electronTrpc. However, bothopenInAppandcopyPathmutations lack error handling. If these operations fail silently, users won't know why their action didn't work.💡 Optional: Add error handlers for user feedback
- const openInApp = electronTrpc.external.openInApp.useMutation(); + const openInApp = electronTrpc.external.openInApp.useMutation({ + onError: (error) => { + console.error("[WorkspaceView/openInApp]", error.message); + // Optionally show toast notification to user + }, + });Similar pattern could be applied to
copyPathmutation.apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx (1)
42-47: Consider adding console logging for debugging.The mutation works correctly and errors are shown to users via
toast.promiseon line 107. However, for consistency with patterns likeuseSetActiveWorkspace.tsand per coding guidelines about prefixed console logging, adding anonErrorhandler with console logging would aid debugging.♻️ Optional: Add console logging
const switchBranch = electronTrpc.workspaces.switchBranchWorkspace.useMutation({ onSuccess: () => { utils.workspaces.invalidate(); }, + onError: (error, variables) => { + console.error("[workspace/switchBranch] Failed to switch branch:", { + projectId: variables.projectId, + branch: variables.branch, + error: error.message, + }); + }, });apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts (2)
45-50: Add error handling to fire-and-forget mutation.
createOrAttach.mutate()is called without error handling. If terminal session creation fails, the user will see a broken terminal with no indication of the cause. Per coding guidelines, errors should not be swallowed silently.♻️ Suggested fix
// Pre-create terminal session (with initial commands if present) // Terminal component will attach to this session when it mounts createOrAttach.mutate({ paneId, tabId, workspaceId: data.workspace.id, initialCommands, + }, { + onError: (error) => { + console.error("[workspaces/openWorktree] Failed to create terminal session:", error); + }, });
60-62: Consider adding error handling todismissConfigToastmutation.Similar to the above, this mutation could fail silently. While less critical than terminal creation, logging the error would aid debugging.
♻️ Suggested fix
onDismiss: () => { - dismissConfigToast.mutate({ projectId: data.projectId }); + dismissConfigToast.mutate({ projectId: data.projectId }, { + onError: (error) => { + console.error("[workspaces/openWorktree] Failed to dismiss config toast:", error); + }, + }); },apps/desktop/src/renderer/react-query/presets/index.ts (1)
60-63: Consider parallelizing independent cache invalidations.The two invalidation calls are independent and could be executed in parallel for a minor performance improvement.
♻️ Optional refactor
onSuccess: async (...args) => { - await utils.settings.getTerminalPresets.invalidate(); - await utils.settings.getDefaultPreset.invalidate(); + await Promise.all([ + utils.settings.getTerminalPresets.invalidate(), + utils.settings.getDefaultPreset.invalidate(), + ]); await options?.onSuccess?.(...args); },apps/desktop/src/renderer/routes/sign-in/page.tsx (1)
16-31: Consider handling mutation errors.The
signInMutationhas no error handling. If the sign-in fails, users won't receive feedback. Consider addingonErrorhandling or displaying the mutation's error state.Suggested improvement
function SignInPage() { const { data: session } = authClient.useSession(); - const signInMutation = electronTrpc.auth.signIn.useMutation(); + const signInMutation = electronTrpc.auth.signIn.useMutation({ + onError: (error) => { + console.error("[sign-in/mutation] Sign-in failed:", error.message); + // Consider showing a toast or error message to the user + }, + });apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx (1)
23-30: Loading state may persist indefinitely on auth failure.If authentication fails or the user logs out while on an authenticated route, this spinner will display forever with no way to recover. Consider adding a timeout or redirect to sign-in when auth state is clearly unavailable.
Suggested improvement
+ // Redirect to sign-in if no token after mount + if (!token) { + return <Navigate to="/sign-in" replace />; + } + // Show loading only on initial mount if (!collections) { return (apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (3)
3-4: Inconsistent import path styles.Line 3 uses the
renderer/alias while line 4 uses a relative path. Per coding guidelines, prefer using aliases defined intsconfig.jsonwhen possible.Suggested fix
import { electronTrpc } from "renderer/lib/electron-trpc"; -import { electronReactClient } from "../../lib/trpc-client"; +import { electronReactClient } from "renderer/lib/trpc-client";
15-29: QueryClient configuration is duplicated.The
QueryClientinstantiation with identicaldefaultOptionsappears in bothTRPCProviderandElectronTRPCProvider. Consider extracting a shared factory function to avoid duplication per DRY principle.Suggested approach
Create a shared utility:
// renderer/lib/query-client.ts export function createDefaultQueryClient() { return new QueryClient({ defaultOptions: { queries: { networkMode: "always", retry: false }, mutations: { networkMode: "always", retry: false }, }, }); }Then use in both providers:
-const [queryClient] = useState( - () => - new QueryClient({ - defaultOptions: { - queries: { - networkMode: "always", - retry: false, - }, - mutations: { - networkMode: "always", - retry: false, - }, - }, - }), -); +const [queryClient] = useState(createDefaultQueryClient);
10-14: Minor: Prefer importingReactNodetype.For consistency with
TRPCProvider.tsxwhich importsReactNodefromreact, consider using the same pattern here instead ofReact.ReactNode.Suggested fix
-import { useState } from "react"; +import { useState, type ReactNode } from "react"; import { electronTrpc } from "renderer/lib/electron-trpc"; import { electronReactClient } from "renderer/lib/trpc-client"; export function ElectronTRPCProvider({ children, }: { - children: React.ReactNode; + children: ReactNode; }) {apps/desktop/src/lib/trpc/routers/auth/index.ts (1)
80-84: Extract magic number to a named constant.Per coding guidelines, hardcoded values should be extracted to named constants for clarity.
Suggested refactor
+const STATE_EXPIRY_MS = 10 * 60 * 1000; // 10 minutes + // Clean up old states (older than 10 minutes) -const tenMinutesAgo = Date.now() - 10 * 60 * 1000; +const tenMinutesAgo = Date.now() - STATE_EXPIRY_MS; for (const [s, ts] of stateStore) { if (ts < tenMinutesAgo) stateStore.delete(s); }apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)
56-62: RedundantsetAuthTokencall in effect.This effect duplicates logic already present in:
- Line 37 (subscription handler)
- Line 50 (hydration effect)
The effect will re-run on every
tokenchange, butsetAuthTokenis already called at the source of token updates. Consider removing this effect to avoid redundant calls and simplify the flow.Suggested removal
- useEffect(() => { - if (token) { - setAuthToken(token); - } else { - setAuthToken(null); - } - }, [token]);
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (43)
apps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/main/index.tsapps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsxapps/desktop/src/renderer/components/SetupConfigModal/SetupConfigModal.tsxapps/desktop/src/renderer/hooks/useWorkspaceShortcuts.tsapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/routes/_authenticated/settings/components/SettingsSidebar/components/ProjectsSettings/ProjectsSettings.tsxapps/desktop/src/renderer/routes/_authenticated/settings/project/$projectId/page.tsxapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/routes/_authenticated/settings/team/page.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/StartView/StartTopBar.tsxapps/desktop/src/renderer/screens/main/components/StartView/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/DeleteWorkspaceDialog/DeleteWorkspaceDialog.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
🚧 Files skipped from review as they are similar to previous changes (19)
- apps/desktop/src/renderer/screens/main/components/StartView/StartTopBar.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
- apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
- apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
- apps/desktop/src/renderer/screens/main/components/StartView/index.tsx
- apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
- apps/desktop/src/main/index.ts
- apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/index.tsx
- apps/desktop/src/renderer/hooks/useWorkspaceShortcuts.ts
- apps/desktop/src/renderer/components/SetupConfigModal/SetupConfigModal.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
- apps/desktop/src/renderer/routes/_authenticated/settings/project/$projectId/page.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/DeleteWorkspaceDialog/DeleteWorkspaceDialog.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx
- apps/desktop/src/renderer/routes/_authenticated/settings/team/page.tsx
- apps/desktop/src/renderer/routes/_authenticated/settings/components/SettingsSidebar/components/ProjectsSettings/ProjectsSettings.tsx
- apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
🧰 Additional context used
📓 Path-based instructions (7)
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from@trpc/server/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid usinganytype - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
One component per file - do not create multi-component files
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
apps/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Drizzle ORM for all database operations - never use raw SQL
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome for formatting and linting - run at root level with
bun run lint:fixorbiome check --write
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Co-locate tests with implementation files using .test.ts or .test.tsx suffix
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/routes/sign-in/page.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsxapps/desktop/src/renderer/routes/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from `trpc/server/observable` instead of async generators, as the library explicitly checks `isObservable(result)` and throws an error otherwise
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/react-query/presets/index.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.tsapps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/*.ts : Never import Node.js modules in shared code like electron-router-dom.ts - it runs in both main and renderer processes
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/electron-router-dom.ts : Do not import Node.js modules like node:path or dotenv in electron-router-dom.ts and similar shared files - they run in both main and renderer processes
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/desktop/src/renderer/routes/_authenticated/layout.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/*/src/components/{ui,ai-elements,react-flow}/*.tsx : Use kebab-case single files for shadcn/ui components (e.g., button.tsx, base-node.tsx) in src/components/ui/, src/components/ai-elements, and src/components/react-flow/
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Extract business logic from tRPC procedures into utility functions when logic exceeds ~50 lines, is used by multiple procedures, or needs independent testing
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/renderer/**/*.{ts,tsx} : Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.tsapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Use TRPCError with appropriate error codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsxapps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to **/*.{ts,tsx} : Never swallow errors silently - at minimum log them with context
Applied to files:
apps/desktop/src/lib/trpc/routers/auth/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
Applied to files:
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : tRPC procedures and API route handlers should validate and delegate; keep orchestrators thin
Applied to files:
apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
🧬 Code graph analysis (19)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx (2)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)apps/desktop/src/renderer/react-query/workspaces/useSetActiveWorkspace.ts (1)
useSetActiveWorkspace(9-62)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx (3)
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/collections.ts (1)
getCollections(189-213)apps/api/src/trpc/context.ts (1)
createContext(4-14)apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)
useAuthToken(86-92)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/lib/trpc/routers/auth/index.ts (1)
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts (5)
loadToken(25-37)saveToken(42-55)authEvents(20-20)stateStore(14-14)TOKEN_FILE(13-13)
apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (4)
apps/api/src/trpc/context.ts (1)
createContext(4-14)apps/desktop/src/renderer/providers/AuthProvider/index.ts (2)
AuthProvider(1-1)useAuthToken(1-1)apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)apps/desktop/src/renderer/lib/auth-client.ts (1)
setAuthToken(7-9)
apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts (3)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)apps/desktop/src/main/lib/terminal/manager.ts (1)
createOrAttach(24-60)apps/desktop/src/renderer/stores/config-modal.ts (1)
useOpenConfigModal(34-35)
apps/desktop/src/renderer/routes/sign-in/page.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (2)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/constants.ts (1)
GITHUB_STATUS_STALE_TIME(9-9)
apps/desktop/src/renderer/react-query/presets/index.ts (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (2)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)apps/desktop/src/renderer/lib/trpc-client.ts (1)
electronReactClient(9-11)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx (2)
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx (1)
useCollections(39-45)apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)
apps/desktop/src/renderer/routes/layout.tsx (5)
apps/desktop/src/renderer/providers/PostHogProvider/PostHogProvider.tsx (1)
PostHogProvider(10-24)apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (1)
ElectronTRPCProvider(10-39)apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)
AuthProvider(17-84)apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx (1)
TRPCProvider(10-47)apps/desktop/src/renderer/providers/MonacoProvider/MonacoProvider.tsx (1)
MonacoProvider(73-105)
apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx (3)
apps/desktop/src/main/lib/terminal/manager.ts (1)
createOrAttach(24-60)apps/desktop/src/renderer/lib/electron-trpc.ts (1)
electronTrpc(9-9)apps/desktop/src/renderer/stores/config-modal.ts (1)
useOpenConfigModal(34-35)
⏰ 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). (6)
- GitHub Check: Deploy API
- GitHub Check: Deploy Admin
- GitHub Check: Deploy Docs
- GitHub Check: Deploy Web
- GitHub Check: Deploy Marketing
- GitHub Check: Build
| electronTrpc.auth.onTokenChanged.useSubscription(undefined, { | ||
| onData: (data) => { | ||
| if (data?.token && data?.expiresAt) { | ||
| setToken(data.token); | ||
| setAuthToken(data.token); | ||
| persistMutation.mutate({ | ||
| token: data.token, | ||
| expiresAt: data.expiresAt, | ||
| }); | ||
| } | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Infinite mutation loop: subscription handler should not re-persist the token.
The onTokenChanged subscription fires when a token is saved (via authEvents.emit("token-saved")). The handler then calls persistMutation.mutate(), which invokes saveToken(), which emits "token-saved" again—creating an infinite loop.
The subscription exists to notify the renderer when OAuth callback (in main process) saves a new token. At that point the token is already persisted; the renderer only needs to update local state.
Suggested fix
electronTrpc.auth.onTokenChanged.useSubscription(undefined, {
onData: (data) => {
if (data?.token && data?.expiresAt) {
setToken(data.token);
setAuthToken(data.token);
- persistMutation.mutate({
- token: data.token,
- expiresAt: data.expiresAt,
- });
}
},
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| electronTrpc.auth.onTokenChanged.useSubscription(undefined, { | |
| onData: (data) => { | |
| if (data?.token && data?.expiresAt) { | |
| setToken(data.token); | |
| setAuthToken(data.token); | |
| persistMutation.mutate({ | |
| token: data.token, | |
| expiresAt: data.expiresAt, | |
| }); | |
| } | |
| }, | |
| }); | |
| electronTrpc.auth.onTokenChanged.useSubscription(undefined, { | |
| onData: (data) => { | |
| if (data?.token && data?.expiresAt) { | |
| setToken(data.token); | |
| setAuthToken(data.token); | |
| } | |
| }, | |
| }); |
🤖 Prompt for AI Agents
In @apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx around
lines 33 - 44, The subscription handler for
electronTrpc.auth.onTokenChanged.useSubscription is causing an infinite loop by
calling persistMutation.mutate (which calls saveToken and re-emits
"token-saved"); update the handler to stop re-persisting: remove the
persistMutation.mutate(...) call and only call setToken and setAuthToken when
data is received (you may keep the token/expiresAt presence check), leaving
token persistence to the original saveToken path that emits authEvents; ensure
no other code in this handler triggers saveToken/authEvents.emit.
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Summary by CodeRabbit
New Features
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.