From 7ac7db4ddb2950216334be01db37f185594bea6e Mon Sep 17 00:00:00 2001 From: c0mrade Date: Wed, 4 Feb 2026 09:45:57 +0300 Subject: [PATCH] fix: add fallback recovery for Telegram popup callback not firing Listen for popupClosed event as backup and add safety timeout to handle Telegram Desktop bug where popup_closed payload is undefined, preventing the callback from being invoked and leaving popup state permanently locked. --- src/platform/adapters/TelegramAdapter.ts | 40 ++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/platform/adapters/TelegramAdapter.ts b/src/platform/adapters/TelegramAdapter.ts index cf7f688..2a901f7 100644 --- a/src/platform/adapters/TelegramAdapter.ts +++ b/src/platform/adapters/TelegramAdapter.ts @@ -201,10 +201,46 @@ function createDialogController(): DialogController { return new Promise((resolve) => { popupOpen = true; - tg.showPopup(params, (buttonId) => { + let settled = false; + + const cleanup = () => { + if (settled) return; + settled = true; popupOpen = false; + clearTimeout(timer); + tg.offEvent?.('popupClosed', onPopupClosed); + }; + + // Fallback: listen for popupClosed event in case the callback doesn't fire + // (known Telegram Desktop bug: popup_closed payload can be undefined, + // crashing the internal handler before it invokes the callback) + const onPopupClosed = ((...args: unknown[]) => { + if (settled) return; + const event = args[0] as { button_id?: string } | undefined; + const buttonId = event?.button_id ?? ''; + cleanup(); resolve(mapResult(buttonId)); - }); + }) as (...args: unknown[]) => void; + + // Safety timeout: reset state if neither callback nor event arrives + const timer = setTimeout(() => { + if (settled) return; + cleanup(); + resolve(mapResult('')); + }, 30_000); + + tg.onEvent?.('popupClosed', onPopupClosed); + + try { + tg.showPopup(params, (buttonId) => { + if (settled) return; + cleanup(); + resolve(mapResult(buttonId)); + }); + } catch { + cleanup(); + resolve(fallback()); + } }); }