Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit 5bf406f

Browse files
authored
feat: Add "Invalidate OAuth token" developer menu item (#1063)
Used to test oauth bugs
1 parent b6f4605 commit 5bf406f

5 files changed

Lines changed: 40 additions & 0 deletions

File tree

‎apps/twig/src/main/menu.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ function buildFileMenu(): MenuItemConstructorOptions {
169169
container.get<UIService>(MAIN_TOKENS.UIService).clearStorage();
170170
},
171171
},
172+
{
173+
label: "Invalidate OAuth token",
174+
click: () => {
175+
container.get<UIService>(MAIN_TOKENS.UIService).invalidateToken();
176+
},
177+
},
172178
{
173179
label: "Mark all agent sessions for recreation",
174180
click: () => {

‎apps/twig/src/main/services/ui/schemas.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export const UIServiceEvent = {
44
NewTask: "new-task",
55
ResetLayout: "reset-layout",
66
ClearStorage: "clear-storage",
7+
InvalidateToken: "invalidate-token",
78
} as const;
89

910
// UI events are simple signals - payload is just a marker that the event fired
@@ -12,4 +13,5 @@ export interface UIServiceEvents {
1213
[UIServiceEvent.NewTask]: true;
1314
[UIServiceEvent.ResetLayout]: true;
1415
[UIServiceEvent.ClearStorage]: true;
16+
[UIServiceEvent.InvalidateToken]: true;
1517
}

‎apps/twig/src/main/services/ui/service.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,8 @@ export class UIService extends TypedEventEmitter<UIServiceEvents> {
1919
clearStorage(): void {
2020
this.emit(UIServiceEvent.ClearStorage, true);
2121
}
22+
23+
invalidateToken(): void {
24+
this.emit(UIServiceEvent.InvalidateToken, true);
25+
}
2226
}

‎apps/twig/src/main/trpc/routers/ui.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ export const uiRouter = router({
2424
onNewTask: subscribeToUIEvent(UIServiceEvent.NewTask),
2525
onResetLayout: subscribeToUIEvent(UIServiceEvent.ResetLayout),
2626
onClearStorage: subscribeToUIEvent(UIServiceEvent.ClearStorage),
27+
onInvalidateToken: subscribeToUIEvent(UIServiceEvent.InvalidateToken),
2728
});

‎apps/twig/src/renderer/components/GlobalEventHandlers.tsx‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useAuthStore } from "@features/auth/stores/authStore";
12
import { usePanelLayoutStore } from "@features/panels/store/panelLayoutStore";
23
import { useRightSidebarStore } from "@features/right-sidebar";
34
import { useSettingsDialogStore } from "@features/settings/stores/settingsDialogStore";
@@ -9,8 +10,10 @@ import { useFocusWorkspace } from "@features/workspace/hooks/useFocusWorkspace";
910
import { useWorkspaceStore } from "@features/workspace/stores/workspaceStore";
1011
import { SHORTCUTS } from "@renderer/constants/keyboard-shortcuts";
1112
import { clearApplicationStorage } from "@renderer/lib/clearStorage";
13+
import { logger } from "@renderer/lib/logger";
1214
import { useRegisteredFoldersStore } from "@renderer/stores/registeredFoldersStore";
1315
import { trpcReact } from "@renderer/trpc";
16+
import { trpcVanilla } from "@renderer/trpc/client";
1417
import type { Task } from "@shared/types";
1518
import { useNavigationStore } from "@stores/navigationStore";
1619
import { useCallback, useEffect, useMemo } from "react";
@@ -139,6 +142,26 @@ export function GlobalEventHandlers({
139142
clearApplicationStorage();
140143
}, []);
141144

145+
const handleInvalidateToken = useCallback((data?: unknown) => {
146+
if (!data) return;
147+
const log = logger.scope("global-event-handlers");
148+
const state = useAuthStore.getState();
149+
const currentToken = state.oauthAccessToken;
150+
if (!currentToken) {
151+
log.warn("No access token to invalidate");
152+
return;
153+
}
154+
const invalidToken = `${currentToken}_invalid`;
155+
useAuthStore.setState({ oauthAccessToken: invalidToken });
156+
trpcVanilla.agent.updateToken
157+
.mutate({ token: invalidToken })
158+
.catch((err) => log.warn("Failed to update agent token", err));
159+
trpcVanilla.cloudTask.updateToken
160+
.mutate({ token: invalidToken })
161+
.catch((err) => log.warn("Failed to update cloud task token", err));
162+
log.info("OAuth access token invalidated for testing");
163+
}, []);
164+
142165
const globalOptions = {
143166
enableOnFormTags: true,
144167
enableOnContentEditable: true,
@@ -244,5 +267,9 @@ export function GlobalEventHandlers({
244267
onData: handleClearStorage,
245268
});
246269

270+
trpcReact.ui.onInvalidateToken.useSubscription(undefined, {
271+
onData: handleInvalidateToken,
272+
});
273+
247274
return null;
248275
}

0 commit comments

Comments
 (0)