fix(demo): companion app skips the demo intro — lands straight on /login

When the demo build runs inside the Android companion WebView
(window.ArchipelagoNative bridge, detected via the existing
isCompanionApp()), all four IS_DEMO intro branch sites now skip the
typing splash and /onboarding/intro and route directly to /login, as if
the intro was already seen:
- App.vue root-boot replay request (companion never requests the splash)
- App.vue post-splash demo routing
- RootRedirect proceedToApp() and the server-up onMounted demo branch

The skip paths write nothing to localStorage/sessionStorage (RootRedirect
skips even its boot log() there), so the browser/PWA demo intro — which
replays on every fresh root boot — is byte-identical to before, and
non-demo builds short-circuit on IS_DEMO before isCompanionApp() runs.
Adds a small isCompanionApp() bridge-detection unit test (700 tests green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-29 14:11:12 -04:00
co-authored by Claude Fable 5
parent b80e7c3487
commit d54517cf0b
3 changed files with 52 additions and 1 deletions
+9 -1
View File
@@ -110,6 +110,7 @@ import { useScreensaverStore } from '@/stores/screensaver'
import { useUIModeStore } from '@/stores/uiMode'
import { startRemoteRelay, stopRemoteRelay } from '@/api/remote-relay'
import { shouldShowIntroSplash } from '@/utils/introSplash'
import { isCompanionApp } from '@/utils/openExternal'
const router = useRouter()
const screensaverStore = useScreensaverStore()
@@ -430,7 +431,8 @@ onMounted(async () => {
// refresh) starts with the typing splash for the full effect. In-session SPA
// navigation never remounts App, and deep-route refreshes keep their place.
const { IS_DEMO } = await import('@/composables/useDemoIntro')
if (IS_DEMO && bootPath === '/') replayRequested = true
// Companion in-app demo never requests the splash replay; browser demo unaffected.
if (IS_DEMO && bootPath === '/' && !isCompanionApp()) replayRequested = true
let onboardingComplete: boolean | null = localStorage.getItem('neode_onboarding_complete') === '1' ? true : null
// Root boots always ask the backend — even when this browser thinks it has
// seen the intro. Both `neode_intro_seen` and `neode_onboarding_complete`
@@ -586,6 +588,12 @@ async function handleSplashComplete() {
{
const { IS_DEMO } = await import('@/composables/useDemoIntro')
if (IS_DEMO) {
// Companion in-app demo skips the intro and lands on /login; browser demo unaffected.
if (isCompanionApp()) {
await router.push('/login').catch(() => {})
reveal()
return
}
await router.push('/onboarding/intro').catch(() => {})
reveal()
return