UNPKG

@yoroi/portfolio

Version:

The Portfolio package of Yoroi SDK

105 lines (89 loc) 2.79 kB
import {App, Portfolio} from '@yoroi/types' import { cacheManageMultiRequest, extractEntryCacheInfo, hasEntryValue, observerMaker, } from '@yoroi/common' import {freeze} from 'immer' import {createCachedUnknownTokenInfo} from './helpers/create-cached-unknown-token-info' export const portfolioTokenManagerMaker = ( { api, storage, }: { api: Portfolio.Api.Api storage: Portfolio.Storage.Token }, { observer = observerMaker<Portfolio.Event.TokenManager>(), }: {observer?: App.ObserverManager<Portfolio.Event.TokenManager>} = {}, ): Portfolio.Manager.Token => { const cachedInfosWithoutRecord: Readonly< Map<Portfolio.Token.Id, App.CacheInfo> > = new Map() const hydrate = ({sourceId}: Portfolio.Event.SourceId) => { // load only the cache info, drop the record storage.token.infos .all() .map(extractEntryCacheInfo) .filter(hasEntryValue) .forEach(([id, value]) => cachedInfosWithoutRecord.set(id, freeze(value))) observer.notify({on: Portfolio.Event.ManagerOn.Hydrate, sourceId}) } const sync = async ({ secondaryTokenIds, sourceId, }: { secondaryTokenIds: ReadonlyArray<Portfolio.Token.Id> } & Portfolio.Event.SourceId) => { const {records, unknownIds, updatedIds, isInvalidated} = await cacheManageMultiRequest<Portfolio.Token.Id, Portfolio.Token.Info>({ request: async (ids) => api.tokenInfos(ids), cachedInfosWithoutRecord: freeze(new Map(cachedInfosWithoutRecord)), ids: secondaryTokenIds, unknownRecordFactory: createCachedUnknownTokenInfo, persistance: freeze({ save: storage.token.infos.save, read: storage.token.infos.read, }), }) const recordsEntries = [...records.entries()] recordsEntries .map(extractEntryCacheInfo) .filter(hasEntryValue) .forEach(([id, record]) => cachedInfosWithoutRecord.set(id, freeze(record)), ) // if the cache was invalidated, notify if (isInvalidated) observer.notify({ on: Portfolio.Event.ManagerOn.Sync, ids: [...updatedIds, ...unknownIds], sourceId, }) // when using subscriptions, or streams, read from storage base on callback args, not from this return return records } const clear = ({sourceId}: Portfolio.Event.SourceId) => { storage.token.infos.clear() cachedInfosWithoutRecord.clear() observer.notify({on: Portfolio.Event.ManagerOn.Clear, sourceId}) } const destroy = () => { observer.destroy() } return freeze( { hydrate, sync, subscribe: observer.subscribe, unsubscribe: observer.unsubscribe, observable$: observer.observable, api, destroy, clear, }, true, ) }