feat(export): server-rendered artifacts behind one signed download URL #160

Merged
developer merged 7 commits from feature/export-server-render into development 2026-07-02 21:58:07 +00:00
Showing only changes of commit a9376c20a2 - Show all commits
+9 -9
View File
@@ -1,11 +1,11 @@
import { Buffer } from 'node:buffer';
import { expect, test, type Page } from './fixtures';
// The finished-game export: the history header's 📤 button opens the app's own format
// chooser (never Telegram's native popup — its callback carries no user activation),
// and BOTH formats travel the same unified route on every platform: the client mints a
// signed relative URL (game.export_url), resolves it against its own origin and hands
// it to the platform's native download — Telegram downloadFile / VKWebAppDownloadFile —
// or a plain anchor download in a browser. g3 ("vs Rick") is the seeded finished game.
// The finished-game export: one signed relative URL (game.export_url) resolved against
// the app's own origin, delivered by the most native affordance per platform — Telegram's
// showPopup chooser + downloadFile dialog (all bridge calls, activation-safe), VK's
// native viewer/download, the OS share sheet with the fetched file on a mobile browser,
// a plain anchor download on desktop. g3 ("vs Rick") is the seeded finished game.
// The mock gateway returns a shape-faithful /dl/... path; the tests intercept that
// route and serve bytes, so the download itself is exercised end to end.
@@ -13,9 +13,9 @@ import { expect, test, type Page } from './fixtures';
const PNG_HEX =
'89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c489' +
'0000000a49444154789c6360000000020001e221bc330000000049454e44ae426082';
const PNG_BYTES = Uint8Array.from({ length: PNG_HEX.length / 2 }, (_, i) =>
parseInt(PNG_HEX.slice(i * 2, i * 2 + 2), 16),
);
// Buffer, not Uint8Array: route.fulfill silently hangs a FETCH interception on a
// Uint8Array body (a navigation download tolerates it) — the share test deadlocked.
const PNG_BYTES = Buffer.from(PNG_HEX, 'hex');
async function routeDl(page: Page): Promise<void> {
await page.route('**/dl/**', (route) => {