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