export type GetPreconditionFn = () => null | { value: T } export type InitializerFn = (precondition: I) => T | Promise export interface AvailabilitySubscription { unsubscribe: () => void } export interface Availability { subscribe: (listener: (adapter: T) => void) => AvailabilitySubscription } export function createAvailability({ getPrecondition, initializer, pollIntervalMs = 300, }: { getPrecondition: GetPreconditionFn initializer: InitializerFn pollIntervalMs?: number }): Availability { let cachedAdapter: T | null = null let polling: ReturnType | null = null let creating = false const listeners = new Set<(adapter: T) => void>() const stopPolling = (): void => { if (polling != null) { clearInterval(polling) polling = null } } const emit = (adapter: T): void => { cachedAdapter = adapter for (const listener of listeners) { listener(adapter) } } const attemptCreate = async (): Promise => { if (cachedAdapter != null || creating) return const precondition = getPrecondition() if (precondition == null) return creating = true try { const adapter = await initializer(precondition.value) emit(adapter) stopPolling() } catch (error) { console.warn("[WalletAdapter] Failed to initialize adapter", error) } finally { creating = false } } const ensurePolling = (): void => { if (cachedAdapter != null) return void attemptCreate() if (cachedAdapter != null || polling != null) return polling = setInterval(() => { void attemptCreate() }, pollIntervalMs) } return { subscribe: listener => { if (cachedAdapter != null) { listener(cachedAdapter) return { unsubscribe: () => {} } } listeners.add(listener) ensurePolling() const subscription: AvailabilitySubscription = { unsubscribe: () => { listeners.delete(listener) if (listeners.size === 0) { stopPolling() } }, } return subscription }, } }