Compare commits

..

34 Commits

Author SHA1 Message Date
developer 30c6590ac1 Merge pull request 'release: promote development → master (v1.24.0)' (#280) from development into master 2026-07-16 19:23:04 +00:00
developer d94d56b461 Merge pull request 'release: promote development → master (v1.23.0)' (#276) from development into master 2026-07-15 00:32:54 +00:00
developer 904e92aac8 Merge pull request 'release: promote development → master (v1.22.0)' (#274) from development into master 2026-07-14 23:13:25 +00:00
developer e836dfefba Merge pull request 'release: promote development → master (v1.21.0)' (#272) from development into master 2026-07-14 20:29:04 +00:00
developer 39e03d22e4 Merge pull request 'release: v1.20.1 — real client IP to backend (last-login fix) + host UTC' (#265) from development into master 2026-07-14 09:44:43 +00:00
developer aaf162de40 Merge pull request 'release: v1.20.0 — offline-UX, catalog order + admin toggles, reward-config admin' (#263) from development into master 2026-07-14 09:02:54 +00:00
developer 5ce9f7e9b4 Merge pull request 'chore(release): promote development to master' (#258) from development into master 2026-07-13 22:21:59 +00:00
developer 3456a0b3ff Merge pull request 'release: v1.18.0 — /support command in the Telegram bot' (#252) from development into master 2026-07-13 07:39:06 +00:00
developer a41281c495 Merge pull request 'release: v1.17.0 — implicit offline model + two-tier client-version gate + unified lobby' (#250) from development into master 2026-07-13 01:06:35 +00:00
developer 516ffbe5f0 Merge pull request 'release: v1.16.0 — offer live pricing, bot health telemetry, edge blocklist' (#247) from development into master 2026-07-11 11:56:09 +00:00
developer 6badc20078 Merge pull request 'Release v1.15.0 — in-game UX + wallet redesign + WAL-alert fix' (#243) from development into master 2026-07-10 16:15:20 +00:00
developer 0ca01133b5 Merge pull request 'Release v1.14.1 — ansible certs-dir fix + Robokassa go-live' (#239) from development into master 2026-07-10 10:58:38 +00:00
developer 45f0b34881 Merge pull request 'Release v1.14.0 — monetization launch (E5-E8)' (#237) from development into master 2026-07-10 10:11:02 +00:00
developer 18785efc8c Merge pull request 'release v1.13.0: payments wallet mechanics + database point-in-time recovery' (#220) from development into master 2026-07-08 23:42:15 +00:00
developer 780ff68ec2 Merge pull request 'release: offline mode + local pass-and-play (hotseat) — proposed v1.12.0' (#212) from development into master 2026-07-07 14:40:43 +00:00
developer 57ff2d03f8 Merge pull request 'Release v1.11.0: PWA install + code-only PWA login + email/metrics fixes' (#187) from development into master 2026-07-05 21:02:08 +00:00
developer a9d0986e74 Merge pull request 'Release v1.10.0: banner colours + urgent, and 3 UI fixes' (#183) from development into master 2026-07-05 14:10:25 +00:00
developer 45957bdcd6 Merge pull request 'Release: promote development → master (old Android WebView support + unsupported-engine telemetry)' (#178) from development into master 2026-07-04 21:23:29 +00:00
developer 829e29a726 Merge pull request 'Release v1.8.0: prod build fix (re-promote)' (#175) from development into master 2026-07-03 21:48:13 +00:00
developer 399508f2f0 Merge pull request 'Release v1.8.0: promote development → master' (#173) from development into master 2026-07-03 21:31:25 +00:00
developer 3a18e683ca Merge pull request 'release: VK Mini App + landscape UI + dict v1.3.1 seed (development→master)' (#144) from development into master 2026-06-30 05:37:43 +00:00
developer 93d086a8a3 Merge pull request 'release: v1.7.0 — Telegram Mini App embedding enhancements' (#138) from development into master 2026-06-24 11:49:44 +00:00
developer 8fe1bdba6b Merge pull request 'release: v1.6.0 — promo deep-link seeds EN variant (+ UI nits)' (#135) from development into master 2026-06-23 21:02:19 +00:00
developer 7923b3cc09 Merge pull request 'release v1.5.1: support-relay card + topic-reopen fixes' (#133) from development into master 2026-06-23 16:54:01 +00:00
developer 4891216749 Merge pull request 'release v1.5.0: Telegram bot support relay' (#131) from development into master 2026-06-23 16:16:04 +00:00
developer f1b8769c89 Merge pull request 'release: v1.4.1 — Telegram nav (windowed, own back button, debug panel)' (#129) from development into master 2026-06-23 13:27:31 +00:00
developer b6f28a2423 Merge pull request 'release: v1.4.0 — Telegram launch diagnostic + dynamic SDK load' (#127) from development into master 2026-06-23 08:40:09 +00:00
developer e32ee9ce68 Merge pull request 'Release: development → master' (#125) from development into master 2026-06-22 22:36:42 +00:00
developer dc946a1faf Merge pull request 'release v1.2.2: edge HTTP/3 stall fix + db-size dashboard threshold' (#121) from development into master 2026-06-22 19:50:58 +00:00
developer 384bd143d0 Merge pull request 'Promote development → master: banner tip set + banner/push language fix' (#114) from development into master 2026-06-22 18:28:00 +00:00
developer c5d22fceca Merge pull request 'Promote development → master: Erudit blank star + dictionary v1.3.0 pin' (#111) from development into master 2026-06-22 13:12:01 +00:00
developer deaa7a29c5 Merge pull request 'Promote development → master (docs finalize + UI tweaks + Telegram name fallback)' (#108) from development into master 2026-06-22 07:27:40 +00:00
developer 24017bcb7f Merge pull request 'Promote development → master (deploy v2: versioning + visible jobs + rollback)' (#106) from development into master 2026-06-22 06:01:03 +00:00
developer 2c4f4b10dc Merge pull request 'Promote development → master (initial production release: pre-release line + Stage 18)' (#104) from development into master 2026-06-22 05:05:48 +00:00
3 changed files with 4 additions and 66 deletions
+1 -48
View File
@@ -1,14 +1,5 @@
import { afterEach, describe, expect, it, vi } from 'vitest'; import { afterEach, describe, expect, it, vi } from 'vitest';
import { onInAppPageLinkClick, openExternalUrl } from './links'; import { openExternalUrl } from './links';
// clickInAppPage fires onInAppPageLinkClick on a fake anchor whose (already absolute) href is the
// same-origin /offer/ page, and reports whether the click's default navigation was suppressed.
function clickInAppPage(href = 'https://app.example/offer/') {
const preventDefault = vi.fn();
const a = { href, target: '_blank' };
onInAppPageLinkClick({ target: { closest: () => a }, preventDefault } as unknown as MouseEvent);
return preventDefault;
}
describe('openExternalUrl', () => { describe('openExternalUrl', () => {
afterEach(() => vi.unstubAllGlobals()); afterEach(() => vi.unstubAllGlobals());
@@ -36,41 +27,3 @@ describe('openExternalUrl', () => {
expect(open).toHaveBeenCalledWith('https://telegram.me/some_bot', '_blank'); expect(open).toHaveBeenCalledWith('https://telegram.me/some_bot', '_blank');
}); });
}); });
describe('onInAppPageLinkClick', () => {
afterEach(() => vi.unstubAllGlobals());
it('routes the same-origin offer page out through the VK away redirect', () => {
const open = vi.fn();
vi.stubGlobal('location', {
pathname: '/vk/',
search: '?vk_user_id=1&vk_platform=mobile_android&sign=x',
href: 'https://app.example/vk/',
origin: 'https://app.example',
});
vi.stubGlobal('window', { open });
const preventDefault = clickInAppPage();
// Same-origin, yet still escaped: the cross-origin gate is bypassed for a non-SPA page.
expect(open).toHaveBeenCalledWith(
`https://vk.com/away.php?to=${encodeURIComponent('https://app.example/offer/')}`,
'_blank',
);
expect(preventDefault).toHaveBeenCalled();
});
it('routes the offer page through the Telegram in-app browser', () => {
const openLink = vi.fn();
vi.stubGlobal('window', { Telegram: { WebApp: { openLink } } });
const preventDefault = clickInAppPage();
expect(openLink).toHaveBeenCalledWith('https://app.example/offer/');
expect(preventDefault).toHaveBeenCalled();
});
it('leaves the anchor to its own navigation outside a Mini App host', () => {
const open = vi.fn();
vi.stubGlobal('window', { open });
const preventDefault = clickInAppPage();
expect(open).not.toHaveBeenCalled();
expect(preventDefault).not.toHaveBeenCalled();
});
});
+1 -16
View File
@@ -4,7 +4,7 @@
// below route an external URL through the platform's escape hatch (Telegram's openLink, VK's // below route an external URL through the platform's escape hatch (Telegram's openLink, VK's
// away.php redirect) and leave the anchor's own navigation / window.open in effect elsewhere. // away.php redirect) and leave the anchor's own navigation / window.open in effect elsewhere.
import { routeExternalLinkInTelegram, telegramOpenExternalLink } from './telegram'; import { routeExternalLinkInTelegram } from './telegram';
import { routeExternalLinkInVK, vkOpenExternalUrl } from './vk'; import { routeExternalLinkInVK, vkOpenExternalUrl } from './vk';
/** /**
@@ -20,21 +20,6 @@ export function onExternalLinkClick(e: MouseEvent): void {
if (routeExternalLinkInTelegram(a) || routeExternalLinkInVK(a)) e.preventDefault(); if (routeExternalLinkInTelegram(a) || routeExternalLinkInVK(a)) e.preventDefault();
} }
/**
* onInAppPageLinkClick is the anchor click handler for a link to a standalone, same-origin page
* that is not part of the SPA — the static legal /offer/ page. Such a page shares the app's origin
* yet must still leave the Mini App WebView: opened in place it replaces the game, and the Android
* VK client then strands the user there with no way back. Unlike onExternalLinkClick it therefore
* skips the cross-origin test (the page is same-origin by design) and routes the click straight
* through the Telegram in-app browser (openLink) or VK's away.php redirect. Outside those hosts it
* is a no-op and the anchor's own target=_blank opens the page in a new tab / child browser.
*/
export function onInAppPageLinkClick(e: MouseEvent): void {
const a = (e.target as HTMLElement | null)?.closest('a');
if (!a) return;
if (telegramOpenExternalLink(a.href) || vkOpenExternalUrl(a.href)) e.preventDefault();
}
/** /**
* openExternalUrl opens an external URL from code (no anchor to click): through VK's external * openExternalUrl opens an external URL from code (no anchor to click): through VK's external
* redirect inside the Android VK client, else a plain new tab. Telegram callers try their native * redirect inside the Android VK client, else a plain new tab. Telegram callers try their native
+2 -2
View File
@@ -7,7 +7,7 @@
import { t, i18n, type MessageKey } from '../lib/i18n/index.svelte'; import { t, i18n, type MessageKey } from '../lib/i18n/index.svelte';
import { executionContext, formatAmount, needsWebSpendWarning, spendableChips, type SpendContext } from '../lib/wallet'; import { executionContext, formatAmount, needsWebSpendWarning, spendableChips, type SpendContext } from '../lib/wallet';
import { isGooglePlayBuild, purchasesHidden } from '../lib/distribution'; import { isGooglePlayBuild, purchasesHidden } from '../lib/distribution';
import { onExternalLinkClick, onInAppPageLinkClick, openExternalUrl } from '../lib/links'; import { onExternalLinkClick, openExternalUrl } from '../lib/links';
import { gatewayOrigin } from '../lib/origin'; import { gatewayOrigin } from '../lib/origin';
import { vkPlatform, vkShowOrderBox } from '../lib/vk'; import { vkPlatform, vkShowOrderBox } from '../lib/vk';
import { telegramOpenInvoice } from '../lib/telegram'; import { telegramOpenInvoice } from '../lib/telegram';
@@ -274,7 +274,7 @@
{/each} {/each}
{#if packs.length > 0} {#if packs.length > 0}
<p class="offer" data-testid="offer"> <p class="offer" data-testid="offer">
<a href="/offer/" target="_blank" rel="noopener noreferrer" onclick={onInAppPageLinkClick}>{t('wallet.offer')}</a> <a href="/offer/" target="_blank" rel="noopener noreferrer">{t('wallet.offer')}</a>
</p> </p>
{:else if !loading} {:else if !loading}
<p class="empty">{t('wallet.empty')}</p> <p class="empty">{t('wallet.empty')}</p>