Keep health checks as data, drive their review and key backup from HomeHealthChecks, and persist the backup reminder as needsKeyBackup
This commit is contained in:
parent
f1946b9a55
commit
9254238d81
8 changed files with 180 additions and 178 deletions
|
|
@ -245,7 +245,7 @@ A derivation that every row subscribes to, or that joins large sets, is built by
|
|||
| repository, tracker, relays, relay stats, handles, zappers, plaintext, wraps | IndexedDB | yes | deleted |
|
||||
| settings (`SettingsValues`) | an encrypted app-data event, cached in IndexedDB | yes | local copy deleted |
|
||||
| `session`, `wallet` | `ss` | no | cleared |
|
||||
| `theme`, `flTheme`, `checked`, `shouldUnwrap`, `device`, `notificationSettings`, push state | `kv` | no | cleared |
|
||||
| `theme`, `flTheme`, `checked`, `shouldUnwrap`, `device`, `notificationSettings`, push state, `needsKeyBackup` | `kv` | no | cleared |
|
||||
| drafts, dictations | a module `Map`, lost on reload | no | page reloads |
|
||||
|
||||
### IndexedDB (`src/app/storage.ts`, `src/lib/indexeddb.ts`)
|
||||
|
|
@ -284,8 +284,8 @@ anything in them outlives a login and is cleared only by logout. Secrets go in `
|
|||
default first, and the stored value arrives later (`.ready`). `theme` and `flTheme`
|
||||
(`theme.ts`), `checked` (`notifications.ts`) and `shouldUnwrap` (`sync.ts`) use it.
|
||||
- `sync({key, store, storage})` binds a store that already exists. The root layout awaits it
|
||||
for `device`, `wallet`, `notificationSettings` and `pushState` before first render, so boot
|
||||
code sees the restored values. It also binds `shouldUnwrap`, which `synced` already persists.
|
||||
for `device`, `wallet`, `notificationSettings`, `pushState` and `needsKeyBackup` before first
|
||||
render, so boot code sees the restored values. It also binds `shouldUnwrap`, which `synced` already persists.
|
||||
|
||||
Raw `localStorage` holds only `theme`, `fl-theme` and `font-size`. The root layout mirrors them
|
||||
there to apply them synchronously before `kv` loads, which avoids a flash of the wrong theme.
|
||||
|
|
|
|||
|
|
@ -2,27 +2,22 @@
|
|||
import Stars from "@assets/icons/stars.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import type {HealthCheck} from "@app/healthChecks"
|
||||
import {healthChecks, reviewPlans} from "@app/healthChecks"
|
||||
|
||||
type Props = {
|
||||
healthCheck: HealthCheck
|
||||
title: string
|
||||
description: string
|
||||
onfix: () => void
|
||||
}
|
||||
|
||||
const {healthCheck}: Props = $props()
|
||||
|
||||
const start = () => reviewPlans([$healthChecks.plan(healthCheck)])
|
||||
const {title, description, onfix}: Props = $props()
|
||||
</script>
|
||||
|
||||
<div
|
||||
role="group"
|
||||
aria-label={healthCheck.title}
|
||||
class="flex items-center justify-between gap-3 px-4 py-3">
|
||||
<div role="group" aria-label={title} class="flex items-center justify-between gap-3 px-4 py-3">
|
||||
<div class="flex min-w-0 flex-col gap-1">
|
||||
<strong class="text-sm">{healthCheck.title}</strong>
|
||||
<p class="text-sm opacity-75">{healthCheck.description}</p>
|
||||
<strong class="text-sm">{title}</strong>
|
||||
<p class="text-sm opacity-75">{description}</p>
|
||||
</div>
|
||||
<Button class="button button-neutral button-sm shrink-0" onclick={start}>
|
||||
<Button class="button button-neutral button-sm shrink-0" onclick={onfix}>
|
||||
<Icon icon={Stars} size={4} />
|
||||
Fix
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts">
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import {publish} from "@welshman/app"
|
||||
import {preventDefault} from "@lib/html"
|
||||
import {errorMessage} from "@lib/util"
|
||||
import Stars from "@assets/icons/stars.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import MinusCircle from "@assets/icons/minus-circle.svg?dataurl"
|
||||
|
|
@ -16,34 +18,38 @@
|
|||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import type {HealthCheckPlan} from "@app/healthChecks"
|
||||
import {clearModals} from "@app/modal"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
||||
type Props = {
|
||||
plans: HealthCheckPlan[]
|
||||
next?: () => void
|
||||
}
|
||||
|
||||
const {plans}: Props = $props()
|
||||
|
||||
const publishing = plans.filter(plan => plan.changes.length > 0)
|
||||
const interactive = plans.filter(plan => plan.changes.length === 0)
|
||||
const {plans, next}: Props = $props()
|
||||
|
||||
let loading = $state(false)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
const save = async (plan: HealthCheckPlan) => {
|
||||
const error = await publish(await plan.apply()).waitForError()
|
||||
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: `Your relays couldn't be saved: ${errorMessage(error)}`})
|
||||
}
|
||||
}
|
||||
|
||||
const confirm = async () => {
|
||||
loading = true
|
||||
|
||||
try {
|
||||
await Promise.all(publishing.map(plan => plan.apply()))
|
||||
await Promise.all(plans.map(save))
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
|
||||
clearModals()
|
||||
|
||||
for (const plan of interactive) {
|
||||
plan.apply()
|
||||
}
|
||||
next?.()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -53,7 +59,7 @@
|
|||
<ModalTitle>Review changes</ModalTitle>
|
||||
<ModalSubtitle>Nothing changes until you confirm.</ModalSubtitle>
|
||||
</ModalHeader>
|
||||
{#each publishing as plan (plan.summary)}
|
||||
{#each plans as plan (plan.summary)}
|
||||
<div class="flex flex-col gap-2">
|
||||
<p>{plan.summary}</p>
|
||||
{#each plan.changes as change (change.label)}
|
||||
|
|
|
|||
|
|
@ -7,20 +7,51 @@
|
|||
import Button from "@lib/components/Button.svelte"
|
||||
import HomeSection from "@app/components/HomeSection.svelte"
|
||||
import HealthCheckItem from "@app/components/HealthCheckItem.svelte"
|
||||
import {healthChecks, reviewPlans} from "@app/healthChecks"
|
||||
import HealthCheckReview from "@app/components/HealthCheckReview.svelte"
|
||||
import KeyDownload from "@app/components/KeyDownload.svelte"
|
||||
import type {HealthCheck} from "@app/healthChecks"
|
||||
import {healthChecks, needsKeyBackup} from "@app/healthChecks"
|
||||
import {session} from "@app/core"
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
const pending = $healthChecks.pending.$
|
||||
|
||||
const reviewAll = () => reviewPlans($pending.map(check => $healthChecks.plan(check)))
|
||||
const count = $derived($pending.length + ($needsKeyBackup ? 1 : 0))
|
||||
|
||||
const finishKeyBackup = () => {
|
||||
needsKeyBackup.set(false)
|
||||
history.back()
|
||||
}
|
||||
|
||||
const backUpKey = () =>
|
||||
pushModal(KeyDownload, {
|
||||
secret: ($session!.data as {secret: string}).secret,
|
||||
next: finishKeyBackup,
|
||||
submitText: "Done",
|
||||
})
|
||||
|
||||
const review = (checks: HealthCheck[], next?: () => void) => {
|
||||
const plans = checks
|
||||
.map(check => $healthChecks.plan(check))
|
||||
.filter(plan => plan.changes.length > 0)
|
||||
|
||||
if (plans.length > 0) {
|
||||
pushModal(HealthCheckReview, {plans, next})
|
||||
} else {
|
||||
next?.()
|
||||
}
|
||||
}
|
||||
|
||||
const reviewAll = () => review($pending, $needsKeyBackup ? backUpKey : undefined)
|
||||
</script>
|
||||
|
||||
<HomeSection title="Health checks" icon={Stethoscope}>
|
||||
{#snippet action()}
|
||||
{#if $pending.length > 0}
|
||||
<Badge variant="warning">{$pending.length} open</Badge>
|
||||
{#if count > 0}
|
||||
<Badge variant="warning">{count} open</Badge>
|
||||
{/if}
|
||||
{/snippet}
|
||||
{#if $pending.length === 0}
|
||||
{#if count === 0}
|
||||
<p class="flex items-center gap-2 px-4 pb-4 text-sm opacity-75">
|
||||
<Icon icon={CheckCircle} size={4} />
|
||||
Your connection to the network looks healthy.
|
||||
|
|
@ -28,9 +59,18 @@
|
|||
{:else}
|
||||
<div class="flex flex-col divide-y divide-line border-t border-line">
|
||||
{#each $pending as healthCheck (healthCheck.id)}
|
||||
<HealthCheckItem {healthCheck} />
|
||||
<HealthCheckItem
|
||||
title={healthCheck.title}
|
||||
description={healthCheck.description}
|
||||
onfix={() => review([healthCheck])} />
|
||||
{/each}
|
||||
{#if $pending.length > 1}
|
||||
{#if $needsKeyBackup}
|
||||
<HealthCheckItem
|
||||
title="Back Up Your Key"
|
||||
description="Save a backup of your private key in a secure place."
|
||||
onfix={backUpKey} />
|
||||
{/if}
|
||||
{#if count > 1}
|
||||
<div class="flex justify-center p-3">
|
||||
<Button class="button button-primary button-sm" onclick={reviewAll}>
|
||||
<Icon icon={Stars} size={4} />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script lang="ts">
|
||||
import cx from "classnames"
|
||||
import type {ClientOptions} from "@pomade/core"
|
||||
import {assoc} from "@welshman/lib"
|
||||
import {makeSecret, RELAYS, MESSAGING_RELAYS, makeEvent} from "@welshman/util"
|
||||
import {Profile} from "@welshman/domain"
|
||||
import {Thunks, nip01, publish, toSession} from "@welshman/app"
|
||||
|
|
@ -26,7 +25,7 @@
|
|||
DEFAULT_MESSAGING_RELAYS,
|
||||
DEFAULT_SPACES,
|
||||
} from "@app/env"
|
||||
import {forceHealthChecks} from "@app/healthChecks"
|
||||
import {needsKeyBackup} from "@app/healthChecks"
|
||||
import {loginWithPomade} from "@app/pomade"
|
||||
import {pushModal, clearModals} from "@app/modal"
|
||||
import {app, domain, login, roomLists} from "@app/core"
|
||||
|
|
@ -93,7 +92,7 @@
|
|||
const secret = getKey<string>("signup.secret")!
|
||||
|
||||
await login(toSession(nip01, {secret}))
|
||||
forceHealthChecks.update(assoc("backup-key", true))
|
||||
needsKeyBackup.set(true)
|
||||
await completeSignup()
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,22 +1,10 @@
|
|||
import {derived, get, writable} from "svelte/store"
|
||||
import {assoc, sample} from "@welshman/lib"
|
||||
import {derived, writable} from "svelte/store"
|
||||
import {sample} from "@welshman/lib"
|
||||
import {normalizeRelayUrl} from "@welshman/util"
|
||||
import {
|
||||
MessagingRelayLists,
|
||||
RelayLists,
|
||||
Relays,
|
||||
SearchRelayLists,
|
||||
projection,
|
||||
publish,
|
||||
} from "@welshman/app"
|
||||
import {MessagingRelayLists, RelayLists, Relays, SearchRelayLists, projection} from "@welshman/app"
|
||||
import type {Command, IApp, Projection} from "@welshman/app"
|
||||
import {errorMessage} from "@lib/util"
|
||||
import KeyDownload from "@app/components/KeyDownload.svelte"
|
||||
import HealthCheckReview from "@app/components/HealthCheckReview.svelte"
|
||||
import {session, usePlugin} from "@app/core"
|
||||
import {usePlugin} from "@app/core"
|
||||
import {DEFAULT_RELAYS} from "@app/env"
|
||||
import {pushModal} from "@app/modal"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
||||
export type HealthCheckContext = {
|
||||
readRelays: string[]
|
||||
|
|
@ -34,7 +22,7 @@ export type HealthCheckChange = {
|
|||
export type HealthCheckPlan = {
|
||||
summary: string
|
||||
changes: HealthCheckChange[]
|
||||
apply: () => unknown
|
||||
apply: () => Promise<Command>
|
||||
}
|
||||
|
||||
export type HealthCheck = {
|
||||
|
|
@ -45,12 +33,14 @@ export type HealthCheck = {
|
|||
plan: (context: HealthCheckContext) => HealthCheckPlan
|
||||
}
|
||||
|
||||
const publishRelayList = async (command: Command) => {
|
||||
const error = await publish(command).waitForError()
|
||||
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: `Your relays couldn't be saved: ${errorMessage(error)}`})
|
||||
}
|
||||
type RelayListSpec = {
|
||||
id: string
|
||||
name: string
|
||||
noun: string
|
||||
// Only lists this app can fill from its own recommendations get a missing-relays check.
|
||||
missing?: {description: string; recommended: string[]}
|
||||
urls: (context: HealthCheckContext) => string[]
|
||||
save: (urls: string[]) => Promise<Command>
|
||||
}
|
||||
|
||||
const relayPlan = (
|
||||
|
|
@ -58,7 +48,7 @@ const relayPlan = (
|
|||
label: string,
|
||||
current: string[],
|
||||
next: string[],
|
||||
apply: (urls: string[]) => unknown,
|
||||
save: (urls: string[]) => Promise<Command>,
|
||||
): HealthCheckPlan => {
|
||||
const currentUrls = current.map(normalizeRelayUrl)
|
||||
const nextUrls = next.map(normalizeRelayUrl)
|
||||
|
|
@ -66,20 +56,44 @@ const relayPlan = (
|
|||
const removed = currentUrls.filter(url => !nextUrls.includes(url))
|
||||
const changes = added.length + removed.length > 0 ? [{label, added, removed}] : []
|
||||
|
||||
return {summary, changes, apply: () => apply(nextUrls)}
|
||||
return {summary, changes, apply: () => save(nextUrls)}
|
||||
}
|
||||
|
||||
export const reviewPlans = (plans: HealthCheckPlan[]) => {
|
||||
if (plans.some(plan => plan.changes.length > 0)) {
|
||||
pushModal(HealthCheckReview, {plans})
|
||||
} else {
|
||||
for (const plan of plans) {
|
||||
plan.apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
const missingRelaysCheck = (
|
||||
spec: RelayListSpec,
|
||||
{description, recommended}: NonNullable<RelayListSpec["missing"]>,
|
||||
): HealthCheck => ({
|
||||
id: `missing-${spec.id}-relays`,
|
||||
title: `Missing ${spec.name} Relays`,
|
||||
description,
|
||||
isPending: context => spec.urls(context).length <= 1,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
`Sets your ${spec.noun} relays to the ones this app recommends.`,
|
||||
`${spec.name} relays`,
|
||||
spec.urls(context),
|
||||
recommended,
|
||||
spec.save,
|
||||
),
|
||||
})
|
||||
|
||||
export const forceHealthChecks = writable<Record<string, boolean>>({})
|
||||
const tooManyRelaysCheck = (spec: RelayListSpec): HealthCheck => ({
|
||||
id: `too-many-${spec.id}-relays`,
|
||||
title: `Too Many ${spec.name} Relays`,
|
||||
description: `You have more ${spec.noun} relays than is really necessary, which can affect resource usage.`,
|
||||
isPending: context => spec.urls(context).length > 8,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
`Keeps five of your ${spec.noun} relays and drops the rest.`,
|
||||
`${spec.name} relays`,
|
||||
spec.urls(context),
|
||||
sample(5, spec.urls(context)),
|
||||
spec.save,
|
||||
),
|
||||
})
|
||||
|
||||
// Set when a key is generated in-app, and cleared once the user has saved a backup of it
|
||||
export const needsKeyBackup = writable(false)
|
||||
|
||||
export class HealthChecks {
|
||||
context: Projection<HealthCheckContext>
|
||||
|
|
@ -109,90 +123,51 @@ export class HealthChecks {
|
|||
)
|
||||
|
||||
this.pending = projection(
|
||||
derived(
|
||||
[this.context.$, forceHealthChecks, app.use(Relays).index.$],
|
||||
([$context, $forceHealthChecks]) =>
|
||||
this.checks.filter(check => $forceHealthChecks[check.id] ?? check.isPending($context)),
|
||||
derived([this.context.$, app.use(Relays).index.$], ([$context]) =>
|
||||
this.checks.filter(check => check.isPending($context)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private supportsSearch = (url: string) => this.app.use(Relays).get(url)?.hasNip(50) ?? true
|
||||
|
||||
private relayLists: RelayListSpec[] = [
|
||||
{
|
||||
id: "inbox",
|
||||
name: "Inbox",
|
||||
noun: "inbox",
|
||||
missing: {
|
||||
description: "Other people aren't currently able to reliably tag you in public notes.",
|
||||
recommended: DEFAULT_RELAYS,
|
||||
},
|
||||
urls: context => context.readRelays,
|
||||
save: urls => this.app.use(RelayLists).setReadUrls(urls),
|
||||
},
|
||||
{
|
||||
id: "outbox",
|
||||
name: "Outbox",
|
||||
noun: "outbox",
|
||||
missing: {
|
||||
description: "Other people aren't currently able to reliably find your public notes.",
|
||||
recommended: DEFAULT_RELAYS,
|
||||
},
|
||||
urls: context => context.writeRelays,
|
||||
save: urls => this.app.use(RelayLists).setWriteUrls(urls),
|
||||
},
|
||||
{
|
||||
id: "dm",
|
||||
name: "DM",
|
||||
noun: "DM",
|
||||
urls: context => context.messagingRelays,
|
||||
save: urls => this.app.use(MessagingRelayLists).setUrls(urls),
|
||||
},
|
||||
]
|
||||
|
||||
private checks: HealthCheck[] = [
|
||||
{
|
||||
id: "missing-inbox-relays",
|
||||
title: "Missing Inbox Relays",
|
||||
description: "Other people aren't currently able to reliably tag you in public notes.",
|
||||
isPending: context => context.readRelays.length <= 1,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
"Sets your inbox relays to the ones this app recommends.",
|
||||
"Inbox relays",
|
||||
context.readRelays,
|
||||
DEFAULT_RELAYS,
|
||||
urls => this.app.use(RelayLists).setReadUrls(urls).then(publishRelayList),
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "missing-outbox-relays",
|
||||
title: "Missing Outbox Relays",
|
||||
description: "Other people aren't currently able to reliably find your public notes.",
|
||||
isPending: context => context.writeRelays.length <= 1,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
"Sets your outbox relays to the ones this app recommends.",
|
||||
"Outbox relays",
|
||||
context.writeRelays,
|
||||
DEFAULT_RELAYS,
|
||||
urls => this.app.use(RelayLists).setWriteUrls(urls).then(publishRelayList),
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "too-many-inbox-relays",
|
||||
title: "Too Many Inbox Relays",
|
||||
description:
|
||||
"You have more inbox relays than is really necessary, which can affect resource usage.",
|
||||
isPending: context => context.readRelays.length > 8,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
"Keeps five of your inbox relays and drops the rest.",
|
||||
"Inbox relays",
|
||||
context.readRelays,
|
||||
sample(5, context.readRelays),
|
||||
urls => this.app.use(RelayLists).setReadUrls(urls).then(publishRelayList),
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "too-many-outbox-relays",
|
||||
title: "Too Many Outbox Relays",
|
||||
description:
|
||||
"You have more outbox relays than is really necessary, which can affect resource usage.",
|
||||
isPending: context => context.writeRelays.length > 8,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
"Keeps five of your outbox relays and drops the rest.",
|
||||
"Outbox relays",
|
||||
context.writeRelays,
|
||||
sample(5, context.writeRelays),
|
||||
urls => this.app.use(RelayLists).setWriteUrls(urls).then(publishRelayList),
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "too-many-dm-relays",
|
||||
title: "Too Many DM Relays",
|
||||
description:
|
||||
"You have more DM relays than is really necessary, which can affect resource usage.",
|
||||
isPending: context => context.messagingRelays.length > 8,
|
||||
plan: context =>
|
||||
relayPlan(
|
||||
"Keeps five of your DM relays and drops the rest.",
|
||||
"DM relays",
|
||||
context.messagingRelays,
|
||||
sample(5, context.messagingRelays),
|
||||
urls => this.app.use(MessagingRelayLists).setUrls(urls).then(publishRelayList),
|
||||
),
|
||||
},
|
||||
...this.relayLists.flatMap(spec =>
|
||||
spec.missing ? [missingRelaysCheck(spec, spec.missing)] : [],
|
||||
),
|
||||
...this.relayLists.map(tooManyRelaysCheck),
|
||||
{
|
||||
id: "invalid-search-relays",
|
||||
title: "Invalid Search Relays",
|
||||
|
|
@ -204,36 +179,11 @@ export class HealthChecks {
|
|||
"Search relays",
|
||||
context.searchRelays,
|
||||
context.searchRelays.filter(this.supportsSearch),
|
||||
urls => this.app.use(SearchRelayLists).setUrls(urls).then(publishRelayList),
|
||||
urls => this.app.use(SearchRelayLists).setUrls(urls),
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "backup-key",
|
||||
title: "Back Up Your Key",
|
||||
description: "Save a backup of your private key in a secure place.",
|
||||
isPending: () => false,
|
||||
plan: () => ({
|
||||
summary: "Opens the key backup dialog, where you choose how to save your key.",
|
||||
changes: [],
|
||||
apply: () => {
|
||||
const {secret} = session.get()!.data as {secret: string}
|
||||
|
||||
pushModal(KeyDownload, {
|
||||
secret,
|
||||
next: () => {
|
||||
forceHealthChecks.update(assoc("backup-key", false))
|
||||
history.back()
|
||||
},
|
||||
submitText: "Done",
|
||||
})
|
||||
},
|
||||
}),
|
||||
},
|
||||
]
|
||||
|
||||
isPending = (healthCheck: HealthCheck) =>
|
||||
get(forceHealthChecks)[healthCheck.id] ?? healthCheck.isPending(this.context.get())
|
||||
|
||||
plan = (healthCheck: HealthCheck) => healthCheck.plan(this.context.get())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,11 +71,15 @@ export const kv = call(() => {
|
|||
await enqueue(() => Preferences.set({key, value: JSON.stringify(value)}))
|
||||
}
|
||||
|
||||
const remove = async (key: string) => {
|
||||
await enqueue(() => Preferences.remove({key}))
|
||||
}
|
||||
|
||||
const clear = async () => {
|
||||
await enqueue(() => Preferences.clear())
|
||||
}
|
||||
|
||||
return {get, set, clear}
|
||||
return {get, set, remove, clear}
|
||||
})
|
||||
|
||||
const secretStorage =
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
import {kv, ss, storage} from "@app/storage"
|
||||
import {device} from "@app/device"
|
||||
import {userSettingsValues, notificationSettings} from "@app/settings"
|
||||
import {forceHealthChecks} from "@app/healthChecks"
|
||||
import {needsKeyBackup} from "@app/healthChecks"
|
||||
import {setupShareIntents, shareFromNative} from "@app/share"
|
||||
import {shouldUnwrap, syncApplicationData} from "@app/sync"
|
||||
import * as env from "@app/env"
|
||||
|
|
@ -190,12 +190,20 @@
|
|||
storage: kv,
|
||||
}),
|
||||
sync({
|
||||
key: "forceHealthChecks",
|
||||
store: forceHealthChecks,
|
||||
key: "needsKeyBackup",
|
||||
store: needsKeyBackup,
|
||||
storage: kv,
|
||||
}),
|
||||
])
|
||||
|
||||
// The key backup reminder used to live in a forceHealthChecks record
|
||||
const legacyHealthChecks = await kv.get<Record<string, boolean>>("forceHealthChecks")
|
||||
|
||||
if (legacyHealthChecks) {
|
||||
needsKeyBackup.set(Boolean(legacyHealthChecks["backup-key"]))
|
||||
await kv.remove("forceHealthChecks")
|
||||
}
|
||||
|
||||
// Wait for critical storage data only
|
||||
await storage.get()?.ready
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue