fix(desktop): dedupe Nostr session deep link imports (#9918)

Signed-off-by: harrykamboj1 <singhharnoor116@gmail.com>
This commit is contained in:
Harnoor Singh
2026-07-01 02:45:48 +05:30
committed by GitHub
parent d308b13e75
commit 452ea10123
2 changed files with 91 additions and 15 deletions
+19 -6
View File
@@ -306,6 +306,8 @@ const ExtensionsRoute = () => {
export function AppInner() {
const [fatalError, setFatalError] = useState<string | null>(null);
const nostrImportInFlight = useRef<string | null>(null);
const navigate = useNavigate();
const setView = useNavigation();
@@ -397,15 +399,22 @@ export function AppInner() {
const handleOpenSessionShare = async (_event: IpcRendererEvent, ...args: unknown[]) => {
const link = args[0] as string;
window.electron.logInfo('Opening session share link');
try {
if (link.startsWith('goose://sessions/nostr')) {
await importNostrSessionFromDeepLink(link);
navigate('/sessions');
return;
}
if (!link.startsWith('goose://sessions/nostr')) {
toast.error('Unsupported session share link');
navigate('/sessions');
return;
}
if (nostrImportInFlight.current === link) {
window.electron.logInfo('Skipping duplicate Nostr deep link import');
return;
}
nostrImportInFlight.current = link;
try {
await importNostrSessionFromDeepLink(link);
navigate('/sessions');
} catch (error) {
console.error('Unexpected error opening Nostr session share:', error);
trackErrorWithContext(error, {
@@ -415,6 +424,10 @@ export function AppInner() {
});
toast.error(`Failed to import Nostr session: ${errorMessage(error, 'Unknown error')}`);
navigate('/sessions');
} finally {
if (nostrImportInFlight.current === link) {
nostrImportInFlight.current = null;
}
}
};
window.electron.on('open-shared-session', handleOpenSessionShare);
+72 -9
View File
@@ -495,7 +495,66 @@ if (process.platform !== 'darwin') {
}
}
const pendingDeepLinks = new Map<number, string>(); // windowId -> deep link URL
const pendingDeepLinks = new Map<number, string>();
function queuePendingDeepLink(windowId: number, url: string): void {
if (pendingDeepLinks.get(windowId) === url) {
return;
}
pendingDeepLinks.set(windowId, url);
}
const reactReadyWindows = new Set<number>();
const DEEPLINK_BURST_DEDUP_MS = 2000;
const recentSessionDeepLinkSends = new Map<string, number>();
function pruneExpiredSessionDeepLinkSends(now: number): void {
for (const [url, sentAt] of recentSessionDeepLinkSends) {
if (now - sentAt >= DEEPLINK_BURST_DEDUP_MS) {
recentSessionDeepLinkSends.delete(url);
}
}
}
function isBurstDuplicateSessionDeepLink(url: string): boolean {
const now = Date.now();
pruneExpiredSessionDeepLinkSends(now);
const sentAt = recentSessionDeepLinkSends.get(url);
return sentAt !== undefined && now - sentAt < DEEPLINK_BURST_DEDUP_MS;
}
function recordSessionDeepLinkSend(url: string): void {
const now = Date.now();
recentSessionDeepLinkSends.set(url, now);
pruneExpiredSessionDeepLinkSends(now);
}
function sendOpenSharedSession(window: BrowserWindow, url: string): void {
if (isBurstDuplicateSessionDeepLink(url)) {
log.info('[Main] Ignoring burst duplicate session deep link');
return;
}
recordSessionDeepLinkSend(url);
window.webContents.send('open-shared-session', url);
}
function deliverExtensionOrSessionDeepLink(
url: string,
parsedUrl: URL,
targetWindow: BrowserWindow
): void {
if (!reactReadyWindows.has(targetWindow.id) || targetWindow.webContents.isLoadingMainFrame()) {
queuePendingDeepLink(targetWindow.id, url);
return;
}
if (parsedUrl.hostname === 'extension') {
targetWindow.webContents.send('add-extension', url);
} else if (parsedUrl.hostname === 'sessions') {
sendOpenSharedSession(targetWindow, url);
}
}
function getResumeSessionId(parsedUrl: URL): string | null {
try {
@@ -555,7 +614,7 @@ async function handleProtocolUrl(url: string, parsedUrl: URL) {
}
if (targetWindow.webContents.isLoadingMainFrame()) {
pendingDeepLinks.set(targetWindow.id, url);
queuePendingDeepLink(targetWindow.id, url);
} else {
await processProtocolUrl(url, parsedUrl, targetWindow);
}
@@ -569,7 +628,7 @@ async function processProtocolUrl(url: string, parsedUrl: URL, window: BrowserWi
if (parsedUrl.hostname === 'extension') {
window.webContents.send('add-extension', url);
} else if (parsedUrl.hostname === 'sessions') {
window.webContents.send('open-shared-session', url);
sendOpenSharedSession(window, url);
} else if (parsedUrl.hostname === 'bot' || parsedUrl.hostname === 'recipe') {
const deeplinkData = parseRecipeDeeplink(url);
const scheduledJobId = parsedUrl.searchParams.get('scheduledJob');
@@ -644,15 +703,13 @@ app.on('open-url', async (_event, url) => {
const targetWindow = existingWindows[0];
if (targetWindow.isMinimized()) targetWindow.restore();
targetWindow.focus();
if (parsedUrl.hostname === 'extension') {
targetWindow.webContents.send('add-extension', url);
} else if (parsedUrl.hostname === 'sessions') {
targetWindow.webContents.send('open-shared-session', url);
if (parsedUrl.hostname === 'extension' || parsedUrl.hostname === 'sessions') {
deliverExtensionOrSessionDeepLink(url, parsedUrl, targetWindow);
}
} else {
openUrlHandledLaunch = true;
const newWindow = await createChat(app, { dir: openDir || undefined });
pendingDeepLinks.set(newWindow.id, url);
queuePendingDeepLink(newWindow.id, url);
}
}
});
@@ -1283,6 +1340,7 @@ const createChat = async (app: App, options: CreateChatOptions = {}) => {
pendingInitialMessages.delete(windowId);
pendingDeepLinks.delete(windowId);
reactReadyWindows.delete(windowId);
if (windowPowerSaveBlockers.has(windowId)) {
const blockerId = windowPowerSaveBlockers.get(windowId)!;
@@ -1358,6 +1416,7 @@ const createLauncher = () => {
activeLauncherWindow = launcherWindow;
launcherWindow.on('closed', () => {
reactReadyWindows.delete(launcherWindow.id);
activeLauncherWindow = null;
});
@@ -1642,6 +1701,10 @@ ipcMain.on('react-ready', (event) => {
const window = BrowserWindow.fromWebContents(event.sender);
const windowId = window?.id;
if (windowId !== undefined) {
reactReadyWindows.add(windowId);
}
// Send any pending initial message for this window
if (windowId && pendingInitialMessages.has(windowId)) {
const initialMessage = pendingInitialMessages.get(windowId)!;
@@ -1661,7 +1724,7 @@ ipcMain.on('react-ready', (event) => {
if (parsedUrl.hostname === 'extension') {
window.webContents.send('add-extension', deepLinkUrl);
} else if (parsedUrl.hostname === 'sessions') {
window.webContents.send('open-shared-session', deepLinkUrl);
sendOpenSharedSession(window, deepLinkUrl);
}
} catch (error) {
log.error('Error processing pending deep link:', error);