From d711271069f0d30734c5dc5512c9520e62c5256b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ti=E1=BA=BFn=20Nguy=E1=BB=85n=20Kh=E1=BA=AFc?= Date: Mon, 4 Nov 2024 01:44:28 +1300 Subject: [PATCH] refactor: simplify wallet provider --- .changeset/fuzzy-lions-design.md | 7 ++++ .../core/src/actions/aggregate-wallets.ts | 35 ++++++------------- .../core/src/wallets/initialize-wallets.ts | 15 +------- .../core/src/wallets/injected/provider.ts | 26 +++----------- packages/core/src/wallets/provider.ts | 5 +-- packages/react/src/hooks/use-wallets.ts | 19 +--------- .../src/composables/use-wallet-connector.ts | 9 ++--- .../composables/use-wallets-initializer.ts | 7 ++-- packages/vue/src/composables/use-wallets.ts | 21 +++-------- 9 files changed, 34 insertions(+), 110 deletions(-) create mode 100644 .changeset/fuzzy-lions-design.md diff --git a/.changeset/fuzzy-lions-design.md b/.changeset/fuzzy-lions-design.md new file mode 100644 index 00000000..e2bce98e --- /dev/null +++ b/.changeset/fuzzy-lions-design.md @@ -0,0 +1,7 @@ +--- +"@reactive-dot/react": patch +"@reactive-dot/core": patch +"@reactive-dot/vue": patch +--- + +Simplified wallet provider interface. diff --git a/packages/core/src/actions/aggregate-wallets.ts b/packages/core/src/actions/aggregate-wallets.ts index 8bd41c91..7f504816 100644 --- a/packages/core/src/actions/aggregate-wallets.ts +++ b/packages/core/src/actions/aggregate-wallets.ts @@ -1,28 +1,13 @@ -import type { MaybeAsync } from "../types.js"; -import { toObservable } from "../utils/to-observable.js"; -import type { WalletProvider } from "../wallets/index.js"; -import { combineLatest, from, of } from "rxjs"; -import { map, switchMap } from "rxjs/operators"; +import { Wallet, type WalletProvider } from "../wallets/index.js"; -export function aggregateWallets(providers: MaybeAsync) { - return toObservable(providers).pipe( - switchMap((providers) => { - if (providers.length === 0) { - return of([]); - } - - return from( - Promise.all( - providers.map(async (provider) => { - await provider.scan(); - return provider; - }), - ), - ); - }), - switchMap((providers) => - combineLatest(providers.map((provider) => provider.wallets$)), +export function aggregateWallets( + providersOrWallets: ReadonlyArray, +) { + return Promise.all( + providersOrWallets.map((walletOrProvider) => + walletOrProvider instanceof Wallet + ? [walletOrProvider] + : walletOrProvider.getWallets(), ), - map((wallets) => wallets.flat()), - ); + ).then((wallets) => wallets.flat()); } diff --git a/packages/core/src/wallets/initialize-wallets.ts b/packages/core/src/wallets/initialize-wallets.ts index 33872847..3e00cc96 100644 --- a/packages/core/src/wallets/initialize-wallets.ts +++ b/packages/core/src/wallets/initialize-wallets.ts @@ -1,18 +1,5 @@ -import { WalletProvider } from "./provider.js"; import type { Wallet } from "./wallet.js"; -export async function initializeWallets( - walletsOrProviders: Array, -) { - const wallets = ( - await Promise.all( - walletsOrProviders.map((walletOrProvider) => - walletOrProvider instanceof WalletProvider - ? walletOrProvider.scan() - : [walletOrProvider], - ), - ) - ).flat(); - +export function initializeWallets(wallets: readonly Wallet[]) { return Promise.all(wallets.map((wallet) => wallet.initialize())); } diff --git a/packages/core/src/wallets/injected/provider.ts b/packages/core/src/wallets/injected/provider.ts index 1f1f95a7..c764b00d 100644 --- a/packages/core/src/wallets/injected/provider.ts +++ b/packages/core/src/wallets/injected/provider.ts @@ -1,33 +1,15 @@ import { WalletProvider } from "../provider.js"; import { InjectedWallet, type InjectedWalletOptions } from "./wallet.js"; import { getInjectedExtensions } from "polkadot-api/pjs-signer"; -import { BehaviorSubject } from "rxjs"; -import { map } from "rxjs/operators"; export class InjectedWalletProvider extends WalletProvider { constructor(private readonly options?: InjectedWalletOptions) { super(); } - readonly #walletMap$ = new BehaviorSubject(new Map()); - - readonly wallets$ = this.#walletMap$.pipe( - map((walletMap) => Array.from(walletMap.values())), - ); - - scan() { - const injectedNames = getInjectedExtensions() ?? []; - - const current = new Map(this.#walletMap$.value); - - for (const name of injectedNames) { - if (!current.has(name)) { - current.set(name, new InjectedWallet(name, this.options)); - } - } - - this.#walletMap$.next(current); - - return Array.from(current.values()); + getWallets() { + return getInjectedExtensions().map( + (name) => new InjectedWallet(name, this.options), + ); } } diff --git a/packages/core/src/wallets/provider.ts b/packages/core/src/wallets/provider.ts index 5f9effb5..d39d7d30 100644 --- a/packages/core/src/wallets/provider.ts +++ b/packages/core/src/wallets/provider.ts @@ -1,8 +1,5 @@ import type { Wallet } from "./wallet.js"; -import type { Observable } from "rxjs"; export abstract class WalletProvider { - abstract scan(): Wallet[] | Promise; - - abstract readonly wallets$: Observable; + abstract getWallets(): Wallet[] | Promise; } diff --git a/packages/react/src/hooks/use-wallets.ts b/packages/react/src/hooks/use-wallets.ts index ea4ec802..4d20ccc9 100644 --- a/packages/react/src/hooks/use-wallets.ts +++ b/packages/react/src/hooks/use-wallets.ts @@ -5,7 +5,6 @@ import { type Config, getConnectedWallets, } from "@reactive-dot/core"; -import { Wallet, WalletProvider } from "@reactive-dot/core/wallets.js"; import { atom, useAtomValue } from "jotai"; import { atomWithObservable } from "jotai/utils"; @@ -27,28 +26,12 @@ export function useConnectedWallets() { return useAtomValue(connectedWalletsAtom(useConfig())); } -const providerWalletsAtom = atomFamilyWithErrorCatcher( - (config: Config, withErrorCatcher) => - withErrorCatcher(atomWithObservable)(() => - aggregateWallets( - config.wallets?.filter( - (walletOrProvider) => walletOrProvider instanceof WalletProvider, - ) ?? [], - ), - ), -); - /** * @internal */ export const walletsAtom = atomFamilyWithErrorCatcher( (config: Config, withErrorCatcher) => - withErrorCatcher(atom)(async (get) => [ - ...(config.wallets?.filter( - (walletOrProvider) => walletOrProvider instanceof Wallet, - ) ?? []), - ...(await get(providerWalletsAtom(config))), - ]), + withErrorCatcher(atom)(() => aggregateWallets(config.wallets ?? [])), ); /** diff --git a/packages/vue/src/composables/use-wallet-connector.ts b/packages/vue/src/composables/use-wallet-connector.ts index 922d50c4..e60bae8a 100644 --- a/packages/vue/src/composables/use-wallet-connector.ts +++ b/packages/vue/src/composables/use-wallet-connector.ts @@ -1,8 +1,7 @@ import { useAsyncAction } from "./use-async-action.js"; -import { useWalletsObservable } from "./use-wallets.js"; +import { useWalletsPromise } from "./use-wallets.js"; import { connectWallet } from "@reactive-dot/core"; import type { Wallet } from "@reactive-dot/core/wallets.js"; -import { firstValueFrom } from "rxjs"; /** * Composable for connecting wallets @@ -13,13 +12,11 @@ import { firstValueFrom } from "rxjs"; export function useWalletConnector(wallets?: Wallet | Wallet[]) { const composableWallets = wallets; - const walletsObservable = useWalletsObservable(); + const walletsPromise = useWalletsPromise(); return useAsyncAction(async (wallets?: Wallet | Wallet[]) => { const walletsToConnect = - wallets ?? - composableWallets ?? - (await firstValueFrom(walletsObservable.value)); + wallets ?? composableWallets ?? (await walletsPromise.value); await connectWallet(walletsToConnect); }); diff --git a/packages/vue/src/composables/use-wallets-initializer.ts b/packages/vue/src/composables/use-wallets-initializer.ts index b2fda758..773a2678 100644 --- a/packages/vue/src/composables/use-wallets-initializer.ts +++ b/packages/vue/src/composables/use-wallets-initializer.ts @@ -1,7 +1,6 @@ import { useAsyncAction } from "./use-async-action.js"; -import { useWalletsObservable } from "./use-wallets.js"; +import { useWalletsPromise } from "./use-wallets.js"; import { initializeWallets } from "@reactive-dot/core/wallets.js"; -import { firstValueFrom } from "rxjs"; /** * Composable for initializing wallets. @@ -9,9 +8,9 @@ import { firstValueFrom } from "rxjs"; * @returns The initialization state and initialize function */ export function useWalletsInitializer() { - const walletsObservable = useWalletsObservable(); + const walletsPromise = useWalletsPromise(); return useAsyncAction(async () => - initializeWallets(await firstValueFrom(walletsObservable.value)), + initializeWallets(await walletsPromise.value), ); } diff --git a/packages/vue/src/composables/use-wallets.ts b/packages/vue/src/composables/use-wallets.ts index 3ae0008e..d22bfd57 100644 --- a/packages/vue/src/composables/use-wallets.ts +++ b/packages/vue/src/composables/use-wallets.ts @@ -2,8 +2,6 @@ import { useAsyncData } from "./use-async-data.js"; import { useConfig } from "./use-config.js"; import { useLazyValue } from "./use-lazy-value.js"; import { aggregateWallets, getConnectedWallets } from "@reactive-dot/core"; -import { Wallet, WalletProvider } from "@reactive-dot/core/wallets.js"; -import { map } from "rxjs/operators"; /** * Composable for getting all available wallets. @@ -11,28 +9,17 @@ import { map } from "rxjs/operators"; * @returns Available wallets */ export function useWallets() { - return useAsyncData(useWalletsObservable()); + return useAsyncData(useWalletsPromise()); } /** * @internal */ -export function useWalletsObservable() { +export function useWalletsPromise() { const config = useConfig(); return useLazyValue(["wallets"], () => - aggregateWallets( - config.value.wallets?.filter( - (wallet) => wallet instanceof WalletProvider, - ) ?? [], - ).pipe( - map((aggregatedWallets) => [ - ...(config.value.wallets?.filter( - (wallet) => wallet instanceof Wallet, - ) ?? []), - ...aggregatedWallets, - ]), - ), + aggregateWallets(config.value.wallets ?? []), ); } @@ -50,6 +37,6 @@ export function useConnectedWallets() { */ export function useConnectedWalletsObservable() { return useLazyValue(["connected-wallets"], () => - getConnectedWallets(useWalletsObservable().value), + getConnectedWallets(useWalletsPromise().value), ); }