import { safeJsonParse , safeJsonStringify } from "@connext/utils" ; import { storeDefaults , storeKeys } from "../constants" ; import { IAsyncStorage , KeyValueStorage } from "../types" ; interface AsyncStorageData { [ key ] : any ; } type InitCallback = ( data : AsyncStorageData ) => void ; export class WrappedAsyncStorage implements KeyValueStorage { private data : AsyncStorageData = { } ; private initializing : boolean = false ; private initCallbacks : InitCallback [ ] = [ ] ; constructor ( private readonly asyncStorage , private readonly prefix = storeDefaults . PREFIX , private readonly separator = storeDefaults . SEPARATOR , private readonly asyncStorageKey = storeKeys . STORE ) { this . loadData ( ) ; } init ( ) { return Promise . resolve ( ) ; } close ( ) { return Promise . resolve ( ) ; } loadData ( ) { return new Promise ( async ( resolve , reject ) : Promise < void > => { if ( this . initializing ) { this . onInit ( ( data ) => resolve ( data ) ) ; } else { try { this . initializing = true ; this . data = await this . fetch ( ) ; this . initializing = false ; resolve ( this . data ) ; this . triggerInit ( this . data ) ; } catch ( e ) { this . initializing = false ; reject ( e ) ; } } } ) ; } onInit ( callback ) { this . initCallbacks . push ( callback ) ; } triggerInit ( data ) { if ( this . initCallbacks && this . initCallbacks . length ) { this . initCallbacks . forEach ( ( callback ) => callback ( data ) ) ; } } async getItem < T > ( key ) { await this . loadData ( ) ; const result = this . data [ `${ this . prefix }${ this . separator }${ key }` ] || undefined ; return safeJsonParse ( result ) ; } async setItem < T > ( key , value ) { await this . loadData ( ) ; this . data [ `${ this . prefix }${ this . separator }${ key }` ] = value ; await this . persist ( ) ; } async removeItem ( key ) { await this . loadData ( ) ; delete this . data [ `${ this . prefix }${ this . separator }${ key }` ] ; await this . persist ( ) ; } async persist ( ) { await this . asyncStorage . setItem ( this . asyncStorageKey , safeJsonStringify ( this . data ) ) ; } async fetch ( ) { const data = await this . asyncStorage . getItem ( this . asyncStorageKey ) ; return safeJsonParse ( data ) || { } ; } async getKeys ( ) { const relevantKeys = Object . keys ( this . data ) . filter ( ( key ) => key . startsWith ( this . prefix ) ) ; return relevantKeys . map ( ( key ) => key . replace ( `${ this . prefix }${ this . separator }` , "" ) ) ; } async getEntries ( ) { return Object . entries ( this . data ) . filter ( ( [ name , _ ] ) => name . startsWith ( this . prefix ) ) . map ( ( [ name , _ ] ) => [ name . replace ( `${ this . prefix }${ this . separator }` , "" ) , _ ] ) ; } getKey ( ... args ) { let str = "" ; args . forEach ( ( arg ) => { str = str . concat ( arg , args . indexOf ( arg ) === args . length - 1 ? "" : this . separator ) ; } ) ; return str ; } }