1import AsyncStorage from '@react-native-async-storage/async-storage'; 2import mapValues from 'lodash/mapValues'; 3 4import * as Kernel from '../kernel/Kernel'; 5import { SessionObject } from '../redux/SessionReducer'; 6import { HistoryItem } from '../types'; 7import addListenerWithNativeCallback from '../utils/addListenerWithNativeCallback'; 8 9type Settings = Record<string, any>; 10 11const Keys = mapValues( 12 { 13 Session: 'session', 14 History: 'history', 15 Settings: 'settings', 16 }, 17 (value) => `Exponent.${value}` 18); 19 20async function getSettingsAsync(): Promise<Settings> { 21 const json = await AsyncStorage.getItem(Keys.Settings); 22 if (!json) { 23 return {}; 24 } 25 26 try { 27 return JSON.parse(json); 28 } catch { 29 return {}; 30 } 31} 32 33async function updateSettingsAsync(updatedSettings: Partial<Settings>): Promise<void> { 34 const currentSettings = await getSettingsAsync(); 35 const newSettings = { 36 ...currentSettings, 37 ...updatedSettings, 38 }; 39 40 await AsyncStorage.setItem(Keys.Settings, JSON.stringify(newSettings)); 41} 42 43async function getSessionAsync() { 44 let results = await Kernel.getSessionAsync(); 45 if (!results) { 46 // NOTE(2018-11-8): we are migrating to storing all session keys 47 // using the Kernel module instead of AsyncStorage, but we need to 48 // continue to check the old location for a little while 49 // until all clients in use have migrated over 50 const json = await AsyncStorage.getItem(Keys.Session); 51 if (json) { 52 try { 53 results = JSON.parse(json); 54 await saveSessionAsync(results as SessionObject); 55 await AsyncStorage.removeItem(Keys.Session); 56 } catch { 57 return null; 58 } 59 } 60 } 61 62 return results; 63} 64 65async function saveSessionAsync(session: SessionObject): Promise<void> { 66 await Kernel.setSessionAsync(session as any); 67} 68 69async function getHistoryAsync(): Promise<HistoryItem[]> { 70 const jsonHistory = await AsyncStorage.getItem(Keys.History); 71 if (jsonHistory) { 72 try { 73 return JSON.parse(jsonHistory); 74 } catch (e) { 75 console.error(e); 76 } 77 } 78 return []; 79} 80 81async function saveHistoryAsync(history: HistoryItem[]): Promise<void> { 82 await AsyncStorage.setItem(Keys.History, JSON.stringify(history)); 83} 84 85async function clearHistoryAsync(): Promise<void> { 86 await AsyncStorage.removeItem(Keys.History); 87} 88 89async function removeSessionAsync(): Promise<void> { 90 await Kernel.removeSessionAsync(); 91} 92 93// adds a hook for native code to query Home's history. 94// needed for routing push notifications in Home. 95addListenerWithNativeCallback('ExponentKernel.getHistoryUrlForExperienceId', async (event) => { 96 const { experienceId } = event; // scopeKey 97 let history = await getHistoryAsync(); 98 history = history.sort((item1, item2) => { 99 // date descending -- we want to pick the most recent experience with this id, 100 // in case there are multiple (e.g. somebody was developing against various URLs of the 101 // same app) 102 const item2time = item2.time ? item2.time : 0; 103 const item1time = item1.time ? item1.time : 0; 104 return item2time - item1time; 105 }); 106 // TODO(wschurman): only check for scope key in the future when most manifests contain it 107 // TODO(wschurman): update for new manifest2 format (Manifest) 108 const historyItem = history.find( 109 (item) => 110 item.manifest && 111 (item.manifest.id === experienceId || 112 ('scopeKey' in item.manifest && item.manifest.scopeKey === experienceId)) 113 ); 114 if (historyItem) { 115 return { url: historyItem.url }; 116 } 117 return {}; 118}); 119 120export default { 121 clearHistoryAsync, 122 getSessionAsync, 123 getHistoryAsync, 124 getSettingsAsync, 125 saveHistoryAsync, 126 saveSessionAsync, 127 removeSessionAsync, 128 updateSettingsAsync, 129}; 130