namespace pxt . storage { interface IStorage { removeItem ( key ) : void ; getItem ( key ) : string ; setItem ( key , value ) : void ; clear ( ) : void ; } class MemoryStorage implements IStorage { items : pxt . Map < string > = { } ; removeItem ( key ) { delete this . items [ key ] ; } getItem ( key ) { return this . items [ key ] ; } setItem ( key , value ) { this . items [ key ] = value ; } clear ( ) { this . items = { } ; } } class LocalStorage implements IStorage { constructor ( private storageId ) { } targetKey ( key ) { return this . storageId + '/' + key ; } removeItem ( key ) { window . localStorage . removeItem ( this . targetKey ( key ) ) ; } getItem ( key ) { return window . localStorage [ this . targetKey ( key ) ] ; } setItem ( key , value ) { window . localStorage [ this . targetKey ( key ) ] = value ; } clear ( ) { let prefix = this . targetKey ( '' ) ; let keys = [ ] ; for ( let i = 0 ; i < window . localStorage . length ; ++ i ) { let key = window . localStorage . key ( i ) ; if ( key . indexOf ( prefix ) == 0 ) keys . push ( key ) ; } keys . forEach ( key => window . localStorage . removeItem ( key ) ) ; } } export function storageId ( ) { if ( pxt . appTarget ) return pxt . appTarget . id ; const cfg = ( < any > window ) . pxtConfig ; if ( cfg ) return cfg . targetId ; const bndl = ( < any > window ) . pxtTargetBundle ; if ( bndl ) return bndl . id ; return '' ; } let impl ; function init ( ) { if ( impl ) return ; const sid = storageId ( ) ; let supported = false ; if ( ! pxt . shell . isSandboxMode ( ) ) { try { window . localStorage [ sid ] = '1' ; let v = window . localStorage [ sid ] ; supported = true ; } catch ( e ) { } } if ( ! supported ) { impl = new MemoryStorage ( ) ; pxt . debug ( 'storage: in memory' ) ; } else { impl = new LocalStorage ( sid ) ; pxt . debug ( `storage: local under ${ sid }` ) ; } } export function setLocal ( key , value ) { init ( ) ; impl . setItem ( key , value ) ; } export function getLocal ( key ) { init ( ) ; return impl . getItem ( key ) ; } export function removeLocal ( key ) { init ( ) ; impl . removeItem ( key ) ; } export function clearLocal ( ) { init ( ) ; impl . clear ( ) ; } } /**
 * Storage that will be shared across localhost frames when developing locally. Uses regular browser storage in production.
 * One side effect: Localhost storage will be shared between different browsers and incognito tabs as well. To disable this
 * behavior, set the `routingEnabled` switch below to `false`.
 */ namespace pxt . storage . shared { /**
     * Override switch. Setting this to `false` will stop routing calls to the pxt server, using browser storage instead.
     */ const routingEnabled = true ; const localhostStoreUrl = "http://localhost:3232/api/store/" ; function useSharedLocalStorage ( ) { return routingEnabled && pxt . BrowserUtils . isLocalHostDev ( ) && ! pxt . BrowserUtils . noSharedLocalStorage ( ) ; } function sharedStorageNamespace ( ) { if ( pxt . BrowserUtils . isChromiumEdge ( ) ) { return "chromium-edge" ; } return pxt . BrowserUtils . browser ( ) ; } export async function getAsync < T > ( container , key ) { if ( useSharedLocalStorage ( ) ) { container += '-' + sharedStorageNamespace ( ) ; const resp = await pxt . Util . requestAsync ( { url : `${ localhostStoreUrl }${ encodeURIComponent ( container ) }/${ encodeURIComponent ( key ) }` , method : "GET" , allowHttpErrors : true } ) ; if ( resp . json ) { return resp . json as T ; } else if ( resp . text ) { return resp . text as any as T ; } else { return undefined ; } } else { const sval = pxt . storage . getLocal ( `${ container }:${ key }` ) ; const val = pxt . Util . jsonTryParse ( sval ) ; return val ? val : sval ; } } export async function setAsync ( container , key , val ) { if ( typeof val == "undefined" ) { await pxt . storage . shared . delAsync ( container , key ) ; return ; } let sval = "" ; if ( typeof val === "object" ) sval = JSON . stringify ( val ) ; else sval = val . toString ( ) ; if ( useSharedLocalStorage ( ) ) { container += '-' + sharedStorageNamespace ( ) ; const data = { type : ( typeof val === "object" ) ? "json" : "text" , val : sval } ; const sdata = JSON . stringify ( data ) ; await pxt . Util . requestAsync ( { url : `${ localhostStoreUrl }${ encodeURIComponent ( container ) }/${ encodeURIComponent ( key ) }` , method : "POST" , data : sdata } ) ; } else { pxt . storage . setLocal ( `${ container }:${ key }` , sval ) ; } } export async function delAsync ( container , key ) { if ( useSharedLocalStorage ( ) ) { container += '-' + sharedStorageNamespace ( ) ; await pxt . Util . requestAsync ( { url : `${ localhostStoreUrl }${ encodeURIComponent ( container ) }/${ encodeURIComponent ( key ) }` , method : "DELETE" , allowHttpErrors : true } ) ; } else { pxt . storage . removeLocal ( `${ container }:${ key }` ) ; } } }