Offer a way out when startup stalls on an unresponsive signer

This commit is contained in:
Coracle-Bot 2026-09-24 22:56:41 +00:00
parent b3f9df7941
commit 795819c2ad
3 changed files with 69 additions and 10 deletions

View file

@ -0,0 +1,52 @@
<script lang="ts">
import {onMount} from "svelte"
import {ms} from "@welshman/lib"
import Button from "@lib/components/Button.svelte"
import Spinner from "@lib/components/Spinner.svelte"
import {PLATFORM_NAME} from "@app/env"
import {resetSession} from "@app/session"
type Props = {
error?: unknown
}
const {error}: Props = $props()
let stalled = $state(false)
let loading = $state(false)
const logout = async () => {
loading = true
await resetSession()
}
if (error) {
console.error(error)
}
onMount(() => {
const timeout = setTimeout(() => (stalled = true), ms(10))
return () => clearTimeout(timeout)
})
</script>
{#if error || stalled}
<div class="flex h-screen flex-col items-center justify-center gap-4 p-8 text-center">
<p class="text-xl font-bold">
{#if error}
{PLATFORM_NAME} couldn't start
{:else}
{PLATFORM_NAME} is still starting
{/if}
</p>
<p class="max-w-sm">
This usually means your signer isn't responding. Logging out clears this device and takes you
back to the login screen.
</p>
<Button class="button button-primary" onclick={logout} disabled={loading}>
<Spinner {loading} reserveSpace>Log out</Spinner>
</Button>
</div>
{/if}

View file

@ -84,15 +84,19 @@ export const restoreSession = async () => {
})
}
export const logout = async () => {
await deactivateCurrentPomadeSession()
await Push.disable()
// A revoked signer can leave the app unable to start, so this clears the device without asking it anything.
export const resetSession = async () => {
await kv.clear()
await ss.clear()
await storage.get()?.clear()
app.get().cleanup()
localStorage.clear()
window.location.href = "/"
}
export const logout = async () => {
await deactivateCurrentPomadeSession()
await Push.disable()
await resetSession()
}

View file

@ -19,6 +19,7 @@
import * as plugins from "@welshman/app"
import {isMobile, documentActive} from "@lib/html"
import AppContainer from "@app/components/AppContainer.svelte"
import Startup from "@app/components/Startup.svelte"
import ModalContainer from "@app/components/ModalContainer.svelte"
import * as core from "@app/core"
import {goToChat, goToHome, setupHistory} from "@app/routes"
@ -320,15 +321,17 @@
{/if}
</svelte:head>
{#await unsubscribe}
<!-- pass -->
{:then}
<div class={isMobile ? "fl mobile" : "fl"} data-fl-theme={$flTheme}>
<div class={isMobile ? "fl mobile" : "fl"} data-fl-theme={$flTheme}>
{#await unsubscribe}
<Startup />
{:then}
<AppContainer>
{@render children()}
</AppContainer>
<ModalContainer />
<div class="tippy-target"></div>
<NewNotificationSound />
</div>
{/await}
{:catch error}
<Startup {error} />
{/await}
</div>