Declare every persisted local store with synced in its owner module and await their ready promises at boot
This commit is contained in:
parent
602ac09293
commit
5343a28e6c
20 changed files with 103 additions and 103 deletions
|
|
@ -156,7 +156,8 @@ size from `localStorage` before first paint. Then, in order:
|
||||||
|
|
||||||
1. `restoreSession()` restores the saved session, if there is one, which builds a user-scoped
|
1. `restoreSession()` restores the saved session, if there is one, which builds a user-scoped
|
||||||
`App` through `login`.
|
`App` through `login`.
|
||||||
2. The device, wallet and notification stores sync to `kv`/`ss`.
|
2. It awaits `.ready` on the `synced` stores boot reads (device, wallet, push and notification
|
||||||
|
settings, `shouldUnwrap`, `needsKeyBackup`).
|
||||||
3. It waits for storage, then `setupDeepLinks()` listens for warm-start links and handles a
|
3. It waits for storage, then `setupDeepLinks()` listens for warm-start links and handles a
|
||||||
cold-start one.
|
cold-start one.
|
||||||
4. Each long-running subscription goes onto one `unsubscribers` list: `setupHistory`,
|
4. Each long-running subscription goes onto one `unsubscribers` list: `setupHistory`,
|
||||||
|
|
|
||||||
|
|
@ -275,18 +275,27 @@ To persist another kind, add it to `kinds` in `storage.ts`. To persist a new map
|
||||||
add a `TABLES` entry and an `init*` method shaped like `initHandles`: load the rows, subscribe
|
add a `TABLES` entry and an `init*` method shaped like `initHandles`: load the rows, subscribe
|
||||||
to `onItem`, and batch the writes.
|
to `onItem`, and batch the writes.
|
||||||
|
|
||||||
### kv, ss and the two ways to bind them
|
### kv, ss and synced stores
|
||||||
|
|
||||||
`kv` wraps Capacitor `Preferences` and `ss` wraps `SecureStorage`. Both are exported from
|
`kv` wraps Capacitor `Preferences` and `ss` wraps `SecureStorage`. Both are exported from
|
||||||
`storage.ts`, queue their writes, and JSON-encode values. Neither is namespaced per user, so
|
`storage.ts`, queue their writes, and JSON-encode values. Neither is namespaced per user, so
|
||||||
anything in them outlives a login and is cleared only by logout. Secrets go in `ss`.
|
anything in them outlives a login and is cleared only by logout. Secrets go in `ss`.
|
||||||
|
|
||||||
- `synced({key, storage, defaultValue})` creates a store that persists itself. It emits the
|
Each persisted store is declared in its owner module with `synced({key, storage, defaultValue})`,
|
||||||
default first, and the stored value arrives later (`.ready`). `theme` and `flTheme`
|
or `syncedWithGetter` from `storage.ts` when callers need `.get()` (`withGetter`'s type drops
|
||||||
(`theme.ts`), `checked` (`notifications.ts`) and `shouldUnwrap` (`sync.ts`) use it.
|
`.ready`). The store emits the default first and loads the stored value in the background, so
|
||||||
- `sync({key, store, storage})` binds a store that already exists. The root layout awaits it
|
`.ready` resolves once it has arrived:
|
||||||
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.
|
- `theme`, `flTheme` (`theme.ts`), `checked` (`notifications.ts`), `shouldUnwrap` (`sync.ts`),
|
||||||
|
`device` (`device.ts`), `needsKeyBackup` (`healthChecks.ts`) in `kv`
|
||||||
|
- `pushState` (key `notificationState`) and `notificationSettings` in `kv`, both in
|
||||||
|
`push/adapters/common.ts` and re-exported from `@app/push`
|
||||||
|
- `wallet` (`lightning.ts`) in `ss`
|
||||||
|
|
||||||
|
The root layout awaits `.ready` for the stores boot code reads (`device`, `shouldUnwrap`,
|
||||||
|
`wallet`, `notificationSettings`, `pushState`, `needsKeyBackup`) before `Push.sync()` and
|
||||||
|
background sync start. A new store that boot reads joins that list. Never change a key, since
|
||||||
|
it is where existing installs keep their value.
|
||||||
|
|
||||||
Raw `localStorage` holds only `theme`, `fl-theme` and `font-size`. The root layout mirrors them
|
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.
|
there to apply them synchronously before `kv` loads, which avoids a flash of the wrong theme.
|
||||||
|
|
@ -305,7 +314,7 @@ Settings are an encrypted app-data event with d-tag `flotilla/settings`, read th
|
||||||
|
|
||||||
A preference that should follow the user across devices goes in `SettingsValues` and
|
A preference that should follow the user across devices goes in `SettingsValues` and
|
||||||
`defaultSettings`. One that belongs to a device goes in a `kv` store, as push, sound and badge do
|
`defaultSettings`. One that belongs to a device goes in a `kv` store, as push, sound and badge do
|
||||||
in `notificationSettings`. Per-space alert preferences are published (`alerts`); the device's
|
in `notificationSettings` (`@app/push`). Per-space alert preferences are published (`alerts`); the device's
|
||||||
push permission is not.
|
push permission is not.
|
||||||
|
|
||||||
`checked`, the read markers behind badges, lives in `kv`, and `syncCheckedRemote` mirrors it to
|
`checked`, the read markers behind badges, lives in `kv`, and `syncCheckedRemote` mirrors it to
|
||||||
|
|
@ -413,8 +422,8 @@ NIP-86 calls (`relayManagement.get().forUrl(url)`) are not thunks. They return
|
||||||
- **UI signals.** `toast` in `toast.ts`, and `relaysPendingTrust` in `policies.ts`.
|
- **UI signals.** `toast` in `toast.ts`, and `relaysPendingTrust` in `policies.ts`.
|
||||||
- **A controller per flow.** `Nip46Controller` (`nip46.ts`) is a class a component instantiates.
|
- **A controller per flow.** `Nip46Controller` (`nip46.ts`) is a class a component instantiates.
|
||||||
It holds the writables and actions for a multi-step flow.
|
It holds the writables and actions for a multi-step flow.
|
||||||
- **Module-owned values.** `wallet` in `lightning.ts` is a `withGetter(writable(...))` that the
|
- **Module-owned values.** `wallet` in `lightning.ts` persists itself to `ss` with
|
||||||
root layout persists.
|
`syncedWithGetter`.
|
||||||
|
|
||||||
## Runes and stores
|
## Runes and stores
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
import {messagingRelayLists, user} from "@app/core"
|
import {messagingRelayLists, user} from "@app/core"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
import {setChecked} from "@app/notifications"
|
import {setChecked} from "@app/notifications"
|
||||||
import {notificationSettings} from "@app/settings"
|
import {notificationSettings} from "@app/push"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {Capacitor} from "@capacitor/core"
|
import {Capacitor} from "@capacitor/core"
|
||||||
import {notificationSettings} from "@app/settings"
|
import {notificationSettings, onNotification} from "@app/push"
|
||||||
import {onNotification} from "@app/push"
|
|
||||||
|
|
||||||
let audioElement: HTMLAudioElement
|
let audioElement: HTMLAudioElement
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@
|
||||||
import {deriveSpacePermissions} from "@app/management"
|
import {deriveSpacePermissions} from "@app/management"
|
||||||
import {userSpaceUrls} from "@app/rooms"
|
import {userSpaceUrls} from "@app/rooms"
|
||||||
import {deriveSpaceActionItems} from "@app/actionItems"
|
import {deriveSpaceActionItems} from "@app/actionItems"
|
||||||
import {notificationSettings, deriveShouldNotify, setSpaceNotifications} from "@app/settings"
|
import {deriveShouldNotify, setSpaceNotifications} from "@app/settings"
|
||||||
|
import {notificationSettings} from "@app/push"
|
||||||
import {pushModal, popModal} from "@app/modal"
|
import {pushModal, popModal} from "@app/modal"
|
||||||
import {makeSpacePath, goToChat} from "@app/routes"
|
import {makeSpacePath, goToChat} from "@app/routes"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
import SpaceMenuActions from "@app/components/SpaceMenuActions.svelte"
|
import SpaceMenuActions from "@app/components/SpaceMenuActions.svelte"
|
||||||
import RelayName from "@app/components/RelayName.svelte"
|
import RelayName from "@app/components/RelayName.svelte"
|
||||||
import {deriveSpaceActionItems} from "@app/actionItems"
|
import {deriveSpaceActionItems} from "@app/actionItems"
|
||||||
import {notificationSettings, deriveShouldNotify} from "@app/settings"
|
import {deriveShouldNotify} from "@app/settings"
|
||||||
|
import {notificationSettings} from "@app/push"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import {withGetter} from "@welshman/store"
|
|
||||||
import {writable} from "svelte/store"
|
|
||||||
import {randomId} from "@welshman/lib"
|
import {randomId} from "@welshman/lib"
|
||||||
|
import {kv, syncedWithGetter} from "@app/storage"
|
||||||
|
|
||||||
export const device = withGetter(writable(randomId()))
|
export const device = syncedWithGetter({key: "device", storage: kv, defaultValue: randomId()})
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import {derived, writable} from "svelte/store"
|
import {derived} from "svelte/store"
|
||||||
import {sample} from "@welshman/lib"
|
import {sample} from "@welshman/lib"
|
||||||
import {normalizeRelayUrl} from "@welshman/util"
|
import {normalizeRelayUrl} from "@welshman/util"
|
||||||
|
import {synced} from "@welshman/store"
|
||||||
import {MessagingRelayLists, RelayLists, Relays, SearchRelayLists, projection} from "@welshman/app"
|
import {MessagingRelayLists, RelayLists, Relays, SearchRelayLists, projection} from "@welshman/app"
|
||||||
import type {Command, IApp, Projection} from "@welshman/app"
|
import type {Command, IApp, Projection} from "@welshman/app"
|
||||||
import {usePlugin} from "@app/core"
|
import {usePlugin} from "@app/core"
|
||||||
import {DEFAULT_RELAYS} from "@app/env"
|
import {DEFAULT_RELAYS} from "@app/env"
|
||||||
|
import {kv} from "@app/storage"
|
||||||
|
|
||||||
export type HealthCheckContext = {
|
export type HealthCheckContext = {
|
||||||
readRelays: string[]
|
readRelays: string[]
|
||||||
|
|
@ -93,7 +95,7 @@ const tooManyRelaysCheck = (spec: RelayListSpec): HealthCheck => ({
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set when a key is generated in-app, and cleared once the user has saved a backup of it
|
// 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 const needsKeyBackup = synced({key: "needsKeyBackup", storage: kv, defaultValue: false})
|
||||||
|
|
||||||
export class HealthChecks {
|
export class HealthChecks {
|
||||||
context: Projection<HealthCheckContext>
|
context: Projection<HealthCheckContext>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import {writable} from "svelte/store"
|
|
||||||
import {nwc} from "@getalby/sdk"
|
import {nwc} from "@getalby/sdk"
|
||||||
import {bech32ToHex, displayUrl, tryCatch} from "@welshman/lib"
|
import {bech32ToHex, displayUrl, tryCatch} from "@welshman/lib"
|
||||||
import type {Maybe} from "@welshman/lib"
|
import type {Maybe} from "@welshman/lib"
|
||||||
import {isNWCWallet, isWebLNWallet, toMsats} from "@welshman/util"
|
import {isNWCWallet, isWebLNWallet, toMsats} from "@welshman/util"
|
||||||
import type {Wallet} from "@welshman/util"
|
import type {Wallet} from "@welshman/util"
|
||||||
import {withGetter} from "@welshman/store"
|
import {ss, syncedWithGetter} from "@app/storage"
|
||||||
|
|
||||||
/** Both lud06 and lud16 normalize into the bech32 lnurl zapping needs, so decode it before display. */
|
/** Both lud06 and lud16 normalize into the bech32 lnurl zapping needs, so decode it before display. */
|
||||||
export const displayLnurl = (lnurl: string) => {
|
export const displayLnurl = (lnurl: string) => {
|
||||||
|
|
@ -20,7 +19,11 @@ export const displayLnurl = (lnurl: string) => {
|
||||||
return url ? displayUrl(url) : lnurl
|
return url ? displayUrl(url) : lnurl
|
||||||
}
|
}
|
||||||
|
|
||||||
export const wallet = withGetter(writable<Maybe<Wallet>>(undefined))
|
export const wallet = syncedWithGetter<Maybe<Wallet>>({
|
||||||
|
key: "wallet",
|
||||||
|
storage: ss,
|
||||||
|
defaultValue: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
export const getWebLn = () => (window as any).webln
|
export const getWebLn = () => (window as any).webln
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,26 @@ import {
|
||||||
makeHttpAuthHeader,
|
makeHttpAuthHeader,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {Comment} from "@welshman/domain"
|
import {Comment} from "@welshman/domain"
|
||||||
import {synced, throttled, withGetter} from "@welshman/store"
|
import {throttled} from "@welshman/store"
|
||||||
import {Events, Relays} from "@welshman/app"
|
import {Events, Relays} from "@welshman/app"
|
||||||
import {app, fromApp, reader} from "@app/core"
|
import {app, fromApp, reader} from "@app/core"
|
||||||
import {makeRoomPath, makeSpaceChatPath, makeChatPath, makeContentPath} from "@app/routes"
|
import {makeRoomPath, makeSpaceChatPath, makeChatPath, makeContentPath} from "@app/routes"
|
||||||
import {CONTENT_KINDS, makeCommentFilter} from "@app/content"
|
import {CONTENT_KINDS, makeCommentFilter} from "@app/content"
|
||||||
import {getIsMuted, notificationSettings, userSettingsValues} from "@app/settings"
|
import {getIsMuted, userSettingsValues} from "@app/settings"
|
||||||
import {Chats} from "@app/chats"
|
import {Chats} from "@app/chats"
|
||||||
import {dufflepud, DUFFLEPUD_URL} from "@app/env"
|
import {dufflepud, DUFFLEPUD_URL} from "@app/env"
|
||||||
import {isGroupSpace} from "@app/relays"
|
import {isGroupSpace} from "@app/relays"
|
||||||
import {activeSpaceUrls} from "@app/rooms"
|
import {activeSpaceUrls} from "@app/rooms"
|
||||||
import {kv} from "@app/storage"
|
import {kv, syncedWithGetter} from "@app/storage"
|
||||||
|
import {notificationSettings} from "@app/push/adapters/common"
|
||||||
|
|
||||||
// Checked state
|
// Checked state
|
||||||
|
|
||||||
export const checked = withGetter(
|
export const checked = syncedWithGetter<Record<string, number>>({
|
||||||
synced<Record<string, number>>({
|
|
||||||
key: "checked",
|
key: "checked",
|
||||||
defaultValue: {},
|
defaultValue: {},
|
||||||
storage: kv,
|
storage: kv,
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
|
|
||||||
export const getChecked = (key: string) => checked.get()[key]
|
export const getChecked = (key: string) => checked.get()[key]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import {writable} from "svelte/store"
|
|
||||||
import type {Subscriber, Unsubscriber} from "svelte/store"
|
import type {Subscriber, Unsubscriber} from "svelte/store"
|
||||||
import {Capacitor} from "@capacitor/core"
|
import {Capacitor} from "@capacitor/core"
|
||||||
import {call, ms, now, on, parseJson, poll, spec, throttle, uniq} from "@welshman/lib"
|
import {call, ms, now, on, parseJson, poll, spec, throttle, uniq} from "@welshman/lib"
|
||||||
|
|
@ -15,13 +14,14 @@ import {
|
||||||
type Filter,
|
type Filter,
|
||||||
type TrustedEvent,
|
type TrustedEvent,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {merged, withGetter} from "@welshman/store"
|
import {merged} from "@welshman/store"
|
||||||
import {User} from "@welshman/app"
|
import {User} from "@welshman/app"
|
||||||
import {navigate} from "@app/modal"
|
import {navigate} from "@app/modal"
|
||||||
import {app, messagingRelayLists, network, roomLists} from "@app/core"
|
import {app, messagingRelayLists, network, roomLists} from "@app/core"
|
||||||
import {DM_KINDS} from "@app/content"
|
import {DM_KINDS} from "@app/content"
|
||||||
import {getMutedRooms, notificationSettings, shouldNotify, userSettingsValues} from "@app/settings"
|
import {getMutedRooms, shouldNotify, userSettingsValues} from "@app/settings"
|
||||||
import {makeEventPath, goToChat, goToSpace} from "@app/routes"
|
import {makeEventPath, goToChat, goToSpace} from "@app/routes"
|
||||||
|
import {kv, syncedWithGetter} from "@app/storage"
|
||||||
|
|
||||||
export type PushSubscription = {
|
export type PushSubscription = {
|
||||||
key: string
|
key: string
|
||||||
|
|
@ -38,7 +38,26 @@ export type PushState = {
|
||||||
export const requiresFallback =
|
export const requiresFallback =
|
||||||
Capacitor.getPlatform() === "android" && !Capacitor.isPluginAvailable("PushNotifications")
|
Capacitor.getPlatform() === "android" && !Capacitor.isPluginAvailable("PushNotifications")
|
||||||
|
|
||||||
export const pushState = withGetter(writable<PushState>({useFallback: requiresFallback}))
|
export const pushState = syncedWithGetter<PushState>({
|
||||||
|
key: "notificationState",
|
||||||
|
storage: kv,
|
||||||
|
defaultValue: {useFallback: requiresFallback},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const notificationSettings = syncedWithGetter({
|
||||||
|
key: "notificationSettings",
|
||||||
|
storage: kv,
|
||||||
|
defaultValue: {
|
||||||
|
push: false,
|
||||||
|
sound: true,
|
||||||
|
badge: false,
|
||||||
|
spaces: true,
|
||||||
|
mentions: true,
|
||||||
|
messages: true,
|
||||||
|
events: true,
|
||||||
|
reminder_minutes: [5],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export interface IPushAdapter {
|
export interface IPushAdapter {
|
||||||
request: (prompt?: boolean) => Promise<string>
|
request: (prompt?: boolean) => Promise<string>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@ import {ellipsize, maybe} from "@welshman/lib"
|
||||||
import {hexTags, matchFilter, tagValues, type TrustedEvent} from "@welshman/util"
|
import {hexTags, matchFilter, tagValues, type TrustedEvent} from "@welshman/util"
|
||||||
import {DM_KINDS} from "@app/content"
|
import {DM_KINDS} from "@app/content"
|
||||||
import {app} from "@app/core"
|
import {app} from "@app/core"
|
||||||
import {notificationSettings} from "@app/settings"
|
|
||||||
import type {IPushAdapter} from "@app/push/adapters/common"
|
import type {IPushAdapter} from "@app/push/adapters/common"
|
||||||
import {onNotification} from "@app/push/adapters/common"
|
import {notificationSettings, onNotification} from "@app/push/adapters/common"
|
||||||
import {renderEventAsSummary} from "@app/render"
|
import {renderEventAsSummary} from "@app/render"
|
||||||
import {goToEvent} from "@app/routes"
|
import {goToEvent} from "@app/routes"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import {Capacitor} from "@capacitor/core"
|
import {Capacitor} from "@capacitor/core"
|
||||||
import {notificationSettings, setSpaceNotifications} from "@app/settings"
|
import {setSpaceNotifications} from "@app/settings"
|
||||||
import {clearBadges} from "@app/notifications"
|
import {clearBadges} from "@app/notifications"
|
||||||
import {syncEventReminders} from "@app/reminders"
|
import {syncEventReminders} from "@app/reminders"
|
||||||
import {pushState} from "@app/push/adapters/common"
|
import {notificationSettings, pushState} from "@app/push/adapters/common"
|
||||||
import {ElectronNotifications} from "@app/push/adapters/electron"
|
import {ElectronNotifications} from "@app/push/adapters/electron"
|
||||||
import {WebNotifications} from "@app/push/adapters/web"
|
import {WebNotifications} from "@app/push/adapters/web"
|
||||||
import {CapacitorNotifications} from "@app/push/adapters/capacitor"
|
import {CapacitorNotifications} from "@app/push/adapters/capacitor"
|
||||||
import {AndroidFallbackNotifications} from "@app/push/adapters/android"
|
import {AndroidFallbackNotifications} from "@app/push/adapters/android"
|
||||||
import type {IPushAdapter} from "@app/push/adapters/common"
|
import type {IPushAdapter} from "@app/push/adapters/common"
|
||||||
|
|
||||||
export {onNotification} from "@app/push/adapters/common"
|
export {notificationSettings, onNotification} from "@app/push/adapters/common"
|
||||||
|
|
||||||
export class Push {
|
export class Push {
|
||||||
static _adapter: IPushAdapter | undefined
|
static _adapter: IPushAdapter | undefined
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ import {buildUrl} from "@lib/util"
|
||||||
import {getEventStart, getEventTitle, isAttending} from "@app/calendar"
|
import {getEventStart, getEventTitle, isAttending} from "@app/calendar"
|
||||||
import {app, network, reader, roomLists} from "@app/core"
|
import {app, network, reader, roomLists} from "@app/core"
|
||||||
import {PUSH_SERVER} from "@app/env"
|
import {PUSH_SERVER} from "@app/env"
|
||||||
import {pushState} from "@app/push/adapters/common"
|
import {notificationSettings, pushState} from "@app/push/adapters/common"
|
||||||
import {notificationSettings} from "@app/settings"
|
|
||||||
|
|
||||||
type Reminder = {
|
type Reminder = {
|
||||||
at: number
|
at: number
|
||||||
|
|
|
||||||
|
|
@ -159,19 +159,6 @@ export const shouldNotify = (url: string, h?: string) =>
|
||||||
export const deriveShouldNotify = (url: string, h?: string) =>
|
export const deriveShouldNotify = (url: string, h?: string) =>
|
||||||
derived(userSettingsValues, $settings => getShouldNotify($settings, url, h))
|
derived(userSettingsValues, $settings => getShouldNotify($settings, url, h))
|
||||||
|
|
||||||
export const notificationSettings = withGetter(
|
|
||||||
writable({
|
|
||||||
push: false,
|
|
||||||
sound: true,
|
|
||||||
badge: false,
|
|
||||||
spaces: true,
|
|
||||||
mentions: true,
|
|
||||||
messages: true,
|
|
||||||
events: true,
|
|
||||||
reminder_minutes: [5],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
export const publishSettings = async (params: Partial<SettingsValues>) => {
|
export const publishSettings = async (params: Partial<SettingsValues>) => {
|
||||||
const $app = app.get()
|
const $app = app.get()
|
||||||
const reader = await settings.get().forceLoad(User.require($app).pubkey)
|
const reader = await settings.get().forceLoad(User.require($app).pubkey)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ import {
|
||||||
verifiedSymbol,
|
verifiedSymbol,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import type {Handle, TrustedEvent} from "@welshman/util"
|
import type {Handle, TrustedEvent} from "@welshman/util"
|
||||||
import {withGetter} from "@welshman/store"
|
import {synced, withGetter} from "@welshman/store"
|
||||||
|
import type {SyncedConfig} from "@welshman/store"
|
||||||
import type {RepositoryUpdate, WrapItem} from "@welshman/net"
|
import type {RepositoryUpdate, WrapItem} from "@welshman/net"
|
||||||
import {Relay, Zapper} from "@welshman/domain"
|
import {Relay, Zapper} from "@welshman/domain"
|
||||||
import type {RelayInfo, ZapperValues} from "@welshman/domain"
|
import type {RelayInfo, ZapperValues} from "@welshman/domain"
|
||||||
|
|
@ -52,6 +53,13 @@ import {IDB} from "@lib/indexeddb"
|
||||||
import {appPolicies} from "@app/core"
|
import {appPolicies} from "@app/core"
|
||||||
import {DM_KINDS} from "@app/content"
|
import {DM_KINDS} from "@app/content"
|
||||||
|
|
||||||
|
// withGetter's type drops the ready promise synced adds
|
||||||
|
export const syncedWithGetter = <T>(config: SyncedConfig<T>) => {
|
||||||
|
const store = synced(config)
|
||||||
|
|
||||||
|
return {...withGetter(store), ready: store.ready}
|
||||||
|
}
|
||||||
|
|
||||||
export const kv = call(() => {
|
export const kv = call(() => {
|
||||||
const enqueue = makeQueue()
|
const enqueue = makeQueue()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import {
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import type {Filter} from "@welshman/util"
|
import type {Filter} from "@welshman/util"
|
||||||
import type {FollowListReader} from "@welshman/domain"
|
import type {FollowListReader} from "@welshman/domain"
|
||||||
import {merged, synced, throttled, withGetter} from "@welshman/store"
|
import {merged, throttled} from "@welshman/store"
|
||||||
import {FollowLists, MessagingRelayLists, RelayLists, SearchRelayLists, Sync} from "@welshman/app"
|
import {FollowLists, MessagingRelayLists, RelayLists, SearchRelayLists, Sync} from "@welshman/app"
|
||||||
import {
|
import {
|
||||||
app,
|
app,
|
||||||
|
|
@ -57,13 +57,15 @@ import {FEATURED_CONTENT_D} from "@app/featured"
|
||||||
import {decodeRelay} from "@app/relays"
|
import {decodeRelay} from "@app/relays"
|
||||||
import {activeSpaceUrls, userSpaceUrls} from "@app/rooms"
|
import {activeSpaceUrls, userSpaceUrls} from "@app/rooms"
|
||||||
import {Settings} from "@app/settings"
|
import {Settings} from "@app/settings"
|
||||||
import {kv} from "@app/storage"
|
import {kv, syncedWithGetter} from "@app/storage"
|
||||||
import {hasBlossomSupport} from "@app/uploads"
|
import {hasBlossomSupport} from "@app/uploads"
|
||||||
|
|
||||||
// Unwrapping is unconditional, so this is what keeps a signer from decrypting the whole DM history.
|
// Unwrapping is unconditional, so this is what keeps a signer from decrypting the whole DM history.
|
||||||
export const shouldUnwrap = withGetter(
|
export const shouldUnwrap = syncedWithGetter({
|
||||||
synced({key: "shouldUnwrap", storage: kv, defaultValue: false}),
|
key: "shouldUnwrap",
|
||||||
)
|
storage: kv,
|
||||||
|
defaultValue: false,
|
||||||
|
})
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
import {dev} from "$app/environment"
|
import {dev} from "$app/environment"
|
||||||
import {page} from "$app/stores"
|
import {page} from "$app/stores"
|
||||||
import {context as pomadeContext} from "@pomade/core"
|
import {context as pomadeContext} from "@pomade/core"
|
||||||
import {sync} from "@welshman/store"
|
|
||||||
import {setNip55Plugin} from "@welshman/signer"
|
import {setNip55Plugin} from "@welshman/signer"
|
||||||
import * as util from "@welshman/util"
|
import * as util from "@welshman/util"
|
||||||
import * as lib from "@welshman/lib"
|
import * as lib from "@welshman/lib"
|
||||||
|
|
@ -28,9 +27,8 @@
|
||||||
import {restoreSession} from "@app/session"
|
import {restoreSession} from "@app/session"
|
||||||
import {syncSignerAlerts} from "@app/signer"
|
import {syncSignerAlerts} from "@app/signer"
|
||||||
import {wallet} from "@app/lightning"
|
import {wallet} from "@app/lightning"
|
||||||
import {kv, ss, storage} from "@app/storage"
|
import {kv, storage} from "@app/storage"
|
||||||
import {device} from "@app/device"
|
import {device} from "@app/device"
|
||||||
import {notificationSettings} from "@app/settings"
|
|
||||||
import {needsKeyBackup} from "@app/healthChecks"
|
import {needsKeyBackup} from "@app/healthChecks"
|
||||||
import {setupShareIntents} from "@app/share"
|
import {setupShareIntents} from "@app/share"
|
||||||
import {shouldUnwrap, syncApplicationData} from "@app/sync"
|
import {shouldUnwrap, syncApplicationData} from "@app/sync"
|
||||||
|
|
@ -38,7 +36,7 @@
|
||||||
import {applySavedTheme, flTheme, syncTheme, theme} from "@app/theme"
|
import {applySavedTheme, flTheme, syncTheme, theme} from "@app/theme"
|
||||||
import * as notifications from "@app/notifications"
|
import * as notifications from "@app/notifications"
|
||||||
import {notificationCount, backgroundNotificationCount} from "@app/notifications"
|
import {notificationCount, backgroundNotificationCount} from "@app/notifications"
|
||||||
import {Push} from "@app/push"
|
import {Push, notificationSettings} from "@app/push"
|
||||||
import {pushState} from "@app/push/adapters/common"
|
import {pushState} from "@app/push/adapters/common"
|
||||||
import {setupDeepLinks} from "@app/deepLinks"
|
import {setupDeepLinks} from "@app/deepLinks"
|
||||||
import {syncKeyboard} from "@app/keyboard"
|
import {syncKeyboard} from "@app/keyboard"
|
||||||
|
|
@ -83,38 +81,14 @@
|
||||||
// Set up logging
|
// Set up logging
|
||||||
unsubscribers.push(setupLogging())
|
unsubscribers.push(setupLogging())
|
||||||
|
|
||||||
// Sync stuff to storage
|
// Boot code reads these, e.g. Push picks its adapter from pushState, so wait for stored values
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
sync({
|
device.ready,
|
||||||
key: "device",
|
shouldUnwrap.ready,
|
||||||
store: device,
|
wallet.ready,
|
||||||
storage: kv,
|
notificationSettings.ready,
|
||||||
}),
|
pushState.ready,
|
||||||
sync({
|
needsKeyBackup.ready,
|
||||||
key: "shouldUnwrap",
|
|
||||||
store: shouldUnwrap,
|
|
||||||
storage: kv,
|
|
||||||
}),
|
|
||||||
sync({
|
|
||||||
key: "wallet",
|
|
||||||
store: wallet,
|
|
||||||
storage: ss,
|
|
||||||
}),
|
|
||||||
sync({
|
|
||||||
key: "notificationSettings",
|
|
||||||
store: notificationSettings,
|
|
||||||
storage: kv,
|
|
||||||
}),
|
|
||||||
sync({
|
|
||||||
key: "notificationState",
|
|
||||||
store: pushState,
|
|
||||||
storage: kv,
|
|
||||||
}),
|
|
||||||
sync({
|
|
||||||
key: "needsKeyBackup",
|
|
||||||
store: needsKeyBackup,
|
|
||||||
storage: kv,
|
|
||||||
}),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
// The key backup reminder used to live in a forceHealthChecks record
|
// The key backup reminder used to live in a forceHealthChecks record
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,8 @@
|
||||||
import {append, uniq} from "@welshman/lib"
|
import {append, uniq} from "@welshman/lib"
|
||||||
import Chat from "@app/components/Chat.svelte"
|
import Chat from "@app/components/Chat.svelte"
|
||||||
import {splitChatId} from "@app/chats"
|
import {splitChatId} from "@app/chats"
|
||||||
import {notificationSettings} from "@app/settings"
|
|
||||||
import {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
import {Push} from "@app/push"
|
import {Push, notificationSettings} from "@app/push"
|
||||||
import {user} from "@app/core"
|
import {user} from "@app/core"
|
||||||
import type {PageProps} from "./$types"
|
import type {PageProps} from "./$types"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import PageContent from "@lib/components/PageContent.svelte"
|
import PageContent from "@lib/components/PageContent.svelte"
|
||||||
import {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
import {saveNotificationSettings} from "@app/push"
|
import {notificationSettings, saveNotificationSettings} from "@app/push"
|
||||||
import {notificationSettings} from "@app/settings"
|
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
settings = {...notificationSettings.get()}
|
settings = {...notificationSettings.get()}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue