This commit is contained in:
Eric Bailey
2023-11-06 13:38:16 -06:00
parent bdb9082e7e
commit 4dd425fdec
4 changed files with 32 additions and 7 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ export const LOCAL_DEV_SERVICE =
export const STAGING_SERVICE = 'https://staging.bsky.dev' export const STAGING_SERVICE = 'https://staging.bsky.dev'
export const PROD_SERVICE = 'https://bsky.social' export const PROD_SERVICE = 'https://bsky.social'
export const DEFAULT_SERVICE = PROD_SERVICE export const DEFAULT_SERVICE = PROD_SERVICE
const ROOT_STATE_STORAGE_KEY = 'root' export const ROOT_STATE_STORAGE_KEY = 'root'
const STATE_FETCH_INTERVAL = 15e3 const STATE_FETCH_INTERVAL = 15e3
export async function setupState(serviceUri = DEFAULT_SERVICE) { export async function setupState(serviceUri = DEFAULT_SERVICE) {
+3 -1
View File
@@ -16,13 +16,14 @@ afterEach(() => {
test(`gets and sets data synchronously`, async () => { test(`gets and sets data synchronously`, async () => {
storage.set('shell', {colorMode: 'light'}) storage.set('shell', {colorMode: 'light'})
expect(AsyncStorage.setItem).toHaveBeenCalledWith( expect(AsyncStorage.setItem).toHaveBeenCalledWith(
storage.STORAGE_ROOT_KEY, storage.ROOT_STATE_STORAGE_KEY,
JSON.stringify({shell: {colorMode: 'light'}}), JSON.stringify({shell: {colorMode: 'light'}}),
) )
storage.set('shell', {colorMode: 'light'}) storage.set('shell', {colorMode: 'light'})
expect(AsyncStorage.getItem).not.toHaveBeenCalled() expect(AsyncStorage.getItem).not.toHaveBeenCalled()
storage.set('shell', {colorMode: 'dark'}) storage.set('shell', {colorMode: 'dark'})
// @ts-expect-error
expect(storage.get('shell').colorMode).toBe('dark') expect(storage.get('shell').colorMode).toBe('dark')
}) })
@@ -35,5 +36,6 @@ test(`set ignores error and continues in memory`, async () => {
await storage.set('shell', {colorMode: 'system'}) await storage.set('shell', {colorMode: 'system'})
// @ts-expect-error
expect(storage.get('shell').colorMode).toBe('system') expect(storage.get('shell').colorMode).toBe('system')
}) })
+22 -4
View File
@@ -3,7 +3,13 @@ import AsyncStorage from '@react-native-async-storage/async-storage'
import {logger} from '#/logger' import {logger} from '#/logger'
import {Schema, defaultData} from '#/storage/schema' import {Schema, defaultData} from '#/storage/schema'
export const STORAGE_ROOT_KEY = 'root' /**
* The key we use to store our data in local storage.
*
* This value exists in `src/state/index.ts` also, but that file loads every mobx
* store too, so it's duplicated here so that tests run faster.
*/
export const ROOT_STATE_STORAGE_KEY = 'root'
/** /**
* In memory cache of local storage data. Never export or reference this * In memory cache of local storage data. Never export or reference this
@@ -14,22 +20,34 @@ export const STORAGE_ROOT_KEY = 'root'
*/ */
let data: Schema = defaultData let data: Schema = defaultData
/**
* Loads data from local storage into memory for synchronous access. This
* should be called once at the root of the application.
*/
export async function init() { export async function init() {
logger.debug(`storage initializing`) logger.debug(`storage initializing`)
try { try {
const raw = await AsyncStorage.getItem(STORAGE_ROOT_KEY) const raw = await AsyncStorage.getItem(ROOT_STATE_STORAGE_KEY)
data = (raw ? JSON.parse(raw) : {}) as Schema data = (raw ? JSON.parse(raw) : {}) as Schema
} catch (e) { } catch (e) {
logger.error(`storage init() failed`) logger.error(`storage init() failed`)
} }
} }
export function get<T extends keyof Schema>(key: T): Schema[T] { /**
* Get a value from local storage. Returns `unknown` type to force us to
* validate and cast to the types we expect.
*/
export function get<T extends keyof Schema>(key: T): unknown {
logger.debug(`storage get(${key})`) logger.debug(`storage get(${key})`)
return data[key] return data[key]
} }
/**
* Set a value on local storage. When setting objects, you need to manually
* merge in new values.
*/
export async function set<T extends keyof Schema>(key: T, value: Schema[T]) { export async function set<T extends keyof Schema>(key: T, value: Schema[T]) {
logger.debug(`storage set(${key}, value)`) logger.debug(`storage set(${key}, value)`)
@@ -37,7 +55,7 @@ export async function set<T extends keyof Schema>(key: T, value: Schema[T]) {
try { try {
// TODO maybe debounce this in the future // TODO maybe debounce this in the future
await AsyncStorage.setItem(STORAGE_ROOT_KEY, JSON.stringify(data)) await AsyncStorage.setItem(ROOT_STATE_STORAGE_KEY, JSON.stringify(data))
return true return true
} catch (err) { } catch (err) {
logger.error(`storage set(${key}, value) failed`) logger.error(`storage set(${key}, value) failed`)
+6 -1
View File
@@ -1,5 +1,5 @@
/** /**
* The shape of the object we store in local storage * The shape of the object we store in local storage.
*/ */
export type Schema = { export type Schema = {
shell: { shell: {
@@ -7,6 +7,11 @@ export type Schema = {
} }
} }
/**
* The default values for the schema. This is used to initialize the store, and
* is used in case AsyncStorage is unavailable. This should be kept in sync
* with the Schema type above.
*/
export const defaultData: Schema = { export const defaultData: Schema = {
shell: { shell: {
colorMode: 'system', colorMode: 'system',