From a072b980bc5175d34c8c73c3e2c33d07425f1dc3 Mon Sep 17 00:00:00 2001 From: Renn F Date: Sun, 19 Jul 2026 10:48:05 +0200 Subject: [PATCH] fix(tg): show Open-from-Telegram wall for empty initData in production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opening /tg in a plain browser loads telegram.org's script, which defines window.Telegram.WebApp with EMPTY initData (no real launch behind it). Production posted that empty string to webapp-auth → 422 → "Couldn't sign in". The dev path already guarded this (cb55f2b9); the prod path didn't. Now a bridge with no initData that isn't the dev mock shows the "Open from Telegram" wall instead of erroring — the cockpit is a phone-from-Telegram surface, and a desktop browser gets the wall, not a failed auth. --- panel/src/app/(tg)/tg/__tests__/page.test.tsx | 14 ++++++++++++++ panel/src/app/(tg)/tg/page.tsx | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/panel/src/app/(tg)/tg/__tests__/page.test.tsx b/panel/src/app/(tg)/tg/__tests__/page.test.tsx index e23ac7cf..dce29ba8 100644 --- a/panel/src/app/(tg)/tg/__tests__/page.test.tsx +++ b/panel/src/app/(tg)/tg/__tests__/page.test.tsx @@ -83,6 +83,20 @@ describe("TelegramMiniAppPage — auth bootstrap", () => { expect(post).not.toHaveBeenCalled(); }); + it("shows the Open-from-Telegram wall in production when the CDN bridge has empty initData", async () => { + // A plain browser at /tg: the telegram.org script defines WebApp but + // with no initData. Production must not post the empty payload (422) — + // it shows the wall, same as no bridge at all. + waitForTelegramWebApp.mockResolvedValue(mockWebApp("")); + + render(); + + await waitFor(() => + expect(screen.getByText(/open from telegram/i)).toBeInTheDocument(), + ); + expect(post).not.toHaveBeenCalled(); + }); + it("calls ready/expand, posts initData, and renders the cockpit on success", async () => { const webApp = mockWebApp("real-init-data"); waitForTelegramWebApp.mockResolvedValue(webApp); diff --git a/panel/src/app/(tg)/tg/page.tsx b/panel/src/app/(tg)/tg/page.tsx index 4149e054..208ab1a6 100644 --- a/panel/src/app/(tg)/tg/page.tsx +++ b/panel/src/app/(tg)/tg/page.tsx @@ -61,7 +61,11 @@ export default function TelegramMiniAppPage() { if (!webApp?.initData && process.env.NODE_ENV === "development") { webApp = createDevMockWebApp(); } - if (!webApp) { + // No bridge, or a bridge with empty initData that didn't become the + // dev mock (a plain browser at this URL in production) — show the + // "Open from Telegram" wall instead of posting an empty payload that + // 422s into a "Couldn't sign in" error. + if (!webApp || (!webApp.initData && !isDevMockWebApp(webApp))) { setState({ kind: "not_in_telegram" }); return; }