feat(vk): show a launch diagnostic on a direct /vk/ open instead of a guest
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m13s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m7s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m13s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m7s
Opening the dedicated /vk/ entry directly in an ordinary browser (no signed VK
launch) fell through to the web flow and silently started a throwaway guest,
which is wrong for a VK-only entry. Mirror the existing /telegram/ launch-error
behaviour: render a compact, shareable, privacy-safe diagnostic screen instead.
- Boot: a new branch `onVKPath() && !insideVK()` sets app.launchError and stops
the fall-through, the VK counterpart of the /telegram/ diagnostic guard.
- Diagnostic (passive, no VK Bridge round-trip): reads the URL launch-parameter
NAMES (never the `sign` value — auth material), whether the URL was signed,
`vk_platform`, the iframe/referrer context, plus the shared client-environment
lines. VK signs the launch URL at load, so — unlike Telegram's initData — the
parameters never arrive late; hence the VK screen offers Share only, no Retry.
- Generalise the screen: TelegramLaunchError.svelte -> LaunchError.svelte, which
renders a neutral pre-formatted report and a per-platform title, with Retry
gated on a `retry` flag (Telegram true, VK false). app.launchError is now a
neutral LaunchDiag { platform, report, retry }.
- New lib/launchdiag.ts holds the shared pieces both platforms reuse: the
LaunchDiag shape, the client-environment lines, and the query field-NAME
reader (moved out of telegram.ts so VK does not duplicate them).
Tests: pure vkDiagLines units, incl. a guard that the `sign` value never leaks
into the report. i18n: launch.errorTitleVk (en/ru). Docs: FUNCTIONAL (+ru) user
story and ARCHITECTURE entry-path note.
This commit is contained in:
@@ -1,34 +1,20 @@
|
||||
<script lang="ts">
|
||||
// Shown on the dedicated /telegram/ entry when a Mini App launch carried no sign-in data (empty
|
||||
// initData) — instead of bouncing the visitor to the marketing landing. It states the problem
|
||||
// plainly and renders a compact, privacy-safe diagnostic snapshot (taken at the moment of
|
||||
// failure, app.launchError) sized to fit one screenshot, with a Share button (the OS share sheet,
|
||||
// or a clipboard copy on desktop) so a stuck user can send it to the developer to pinpoint why
|
||||
// Telegram provided no initData — notably on some Android clients. The snapshot carries only
|
||||
// presence / identification signals and field NAMES, never the signed initData itself, nor an IP.
|
||||
// Shown on a dedicated Mini App entry (/telegram/ or /vk/) opened without a valid launch — instead of
|
||||
// bouncing to the marketing landing (Telegram) or silently proceeding as a guest (VK). It states the
|
||||
// problem plainly and renders a compact, privacy-safe diagnostic snapshot (app.launchError, taken at
|
||||
// the moment of failure) sized to fit one screenshot, with a Share button (the OS share sheet, or a
|
||||
// clipboard copy on desktop) so a stuck user can send it to the developer to pinpoint why the launch
|
||||
// carried no sign-in data. The snapshot carries only presence / identification signals and field
|
||||
// NAMES, never the signed launch data itself, nor an IP. Retry is shown only where a late-arriving
|
||||
// launch can still succeed (Telegram initData); VK delivers its signed parameters in the URL at load,
|
||||
// so it offers Share only.
|
||||
import { app, retryTelegramLaunch } from '../lib/app.svelte';
|
||||
import { shareText } from '../lib/share';
|
||||
import { t } from '../lib/i18n/index.svelte';
|
||||
|
||||
const diag = $derived(app.launchError);
|
||||
|
||||
// One compact "key: value" line per fact; the field labels are fixed diagnostic tokens (not UI
|
||||
// prose), so the developer reads the same report in any locale. Kept terse to fit one screenshot.
|
||||
const report = $derived(
|
||||
diag
|
||||
? [
|
||||
`sdk-load: ${diag.sdkLoad}`,
|
||||
`sdk: ${diag.hasSDK ? 'yes' : 'no'} webapp: ${diag.hasWebApp ? 'yes' : 'no'}`,
|
||||
`tg-platform: ${diag.platform || '—'} tg-version: ${diag.version || '—'}`,
|
||||
`initData: ${diag.initDataLen > 0 ? diag.initDataLen : 'empty'} tgdata-in-url: ${diag.hashHadTgData ? 'yes' : 'no'}`,
|
||||
`fields: ${diag.fieldsPresent.join(',') || '—'}`,
|
||||
`missing: ${diag.fieldsMissing.join(',') || '—'}`,
|
||||
`os: ${diag.osPlatform || '—'} mobile: ${diag.mobile || '—'}`,
|
||||
`browser: ${diag.browser || '—'}`,
|
||||
`ua: ${diag.userAgent || '—'}`,
|
||||
].join('\n')
|
||||
: '',
|
||||
);
|
||||
// The title names the platform the entry belongs to; the body and the report are platform-neutral.
|
||||
const title = $derived(t(diag?.platform === 'vk' ? 'launch.errorTitleVk' : 'launch.errorTitle'));
|
||||
|
||||
let retrying = $state(false);
|
||||
async function retry(): Promise<void> {
|
||||
@@ -44,7 +30,8 @@
|
||||
let copied = $state(false);
|
||||
let copyTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
async function share(): Promise<void> {
|
||||
const r = await shareText(report, t('launch.errorTitle'));
|
||||
if (!diag) return;
|
||||
const r = await shareText(diag.report, title);
|
||||
// The OS share sheet is its own feedback; a desktop clipboard copy is silent, so confirm it.
|
||||
if (r === 'copied') {
|
||||
copied = true;
|
||||
@@ -57,12 +44,14 @@
|
||||
{#if diag}
|
||||
<div class="boot">
|
||||
<div class="card">
|
||||
<h1>{t('launch.errorTitle')}</h1>
|
||||
<h1>{title}</h1>
|
||||
<p class="msg">{t('launch.errorBody')}</p>
|
||||
<pre class="diag">{report}</pre>
|
||||
<pre class="diag">{diag.report}</pre>
|
||||
<div class="actions">
|
||||
<button class="share" onclick={share}>{copied ? t('launch.copied') : t('launch.share')}</button>
|
||||
<button class="retry" onclick={retry} disabled={retrying}>{t('common.retry')}</button>
|
||||
{#if diag.retry}
|
||||
<button class="retry" onclick={retry} disabled={retrying}>{t('common.retry')}</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user