Add idb-keyval backed archival storage
This commit is contained in:
@@ -171,6 +171,7 @@
|
||||
"fast-text-encoding": "^1.0.6",
|
||||
"history": "^5.3.0",
|
||||
"hls.js": "^1.6.2",
|
||||
"idb-keyval": "^6.2.2",
|
||||
"js-sha256": "^0.9.0",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lande": "^1.0.10",
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import {MMKV} from '@bsky.app/react-native-mmkv'
|
||||
|
||||
import {type DB} from '#/storage/archive/db/types'
|
||||
|
||||
export function create({id}: {id: string}): DB {
|
||||
const store = new MMKV({id})
|
||||
|
||||
return {
|
||||
async get(key: string): Promise<string | undefined> {
|
||||
return store.getString(key) ?? undefined
|
||||
},
|
||||
async set(key: string, value: string): Promise<void> {
|
||||
store.set(key, value)
|
||||
},
|
||||
async delete(key: string): Promise<void> {
|
||||
store.delete(key)
|
||||
},
|
||||
async clear(): Promise<void> {
|
||||
store.clearAll()
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import {clear, createStore, del, get, set} from 'idb-keyval'
|
||||
|
||||
import {type DB} from '#/storage/archive/db/types'
|
||||
|
||||
export function create({id}: {id: string}): DB {
|
||||
const store = createStore(id, id)
|
||||
|
||||
return {
|
||||
async get(key: string): Promise<string | undefined> {
|
||||
return get(key, store) ?? undefined
|
||||
},
|
||||
async set(key: string, value: string): Promise<void> {
|
||||
await set(key, value, store)
|
||||
},
|
||||
async delete(key: string): Promise<void> {
|
||||
await del(key, store)
|
||||
},
|
||||
async clear(): Promise<void> {
|
||||
await clear(store)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export type DB = {
|
||||
get(key: string): Promise<string | undefined>
|
||||
set(key: string, value: string): Promise<void>
|
||||
delete(key: string): Promise<void>
|
||||
clear(): Promise<void>
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import {create} from '#/storage/archive/db'
|
||||
import {type DB} from '#/storage/archive/db/types'
|
||||
import {type Device} from '#/storage/archive/schema'
|
||||
|
||||
export * from '#/storage/archive/schema'
|
||||
|
||||
/**
|
||||
* Generic archival storage class. DO NOT use this directly. Instead, use the
|
||||
* exported `Archive` instances below.
|
||||
*/
|
||||
export class Archive<Scopes extends unknown[], Schema> {
|
||||
protected sep = ':'
|
||||
protected store: DB
|
||||
|
||||
constructor({id}: {id: string}) {
|
||||
this.store = create({id})
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a value in archival storage based on scopes and/or keys
|
||||
*
|
||||
* `set([key], value)`
|
||||
* `set([scope, key], value)`
|
||||
*/
|
||||
async set<Key extends keyof Schema>(
|
||||
scopes: [...Scopes, Key],
|
||||
data: Schema[Key],
|
||||
): Promise<void> {
|
||||
// stored as `{ data: <value> }` structure to ease stringification
|
||||
return this.store.set(scopes.join(this.sep), JSON.stringify({data}))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from archival storage based on scopes and/or keys
|
||||
*
|
||||
* `get([key])`
|
||||
* `get([scope, key])`
|
||||
*/
|
||||
async get<Key extends keyof Schema>(
|
||||
scopes: [...Scopes, Key],
|
||||
): Promise<Schema[Key] | undefined> {
|
||||
const res = await this.store.get(scopes.join(this.sep))
|
||||
if (!res) return undefined
|
||||
// parsed from storage structure `{ data: <value> }`
|
||||
return JSON.parse(res).data
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a value from archival storage based on scopes and/or keys
|
||||
*
|
||||
* `remove([key])`
|
||||
* `remove([scope, key])`
|
||||
*/
|
||||
async remove<Key extends keyof Schema>(scopes: [...Scopes, Key]) {
|
||||
return this.store.delete(scopes.join(this.sep))
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove many values from the same archival storage scope by keys
|
||||
*
|
||||
* `removeMany([], [key])`
|
||||
* `removeMany([scope], [key])`
|
||||
*/
|
||||
async removeMany<Key extends keyof Schema>(scopes: [...Scopes], keys: Key[]) {
|
||||
return Promise.all(keys.map(key => this.remove([...scopes, key])))
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging purposes
|
||||
*/
|
||||
async removeAll() {
|
||||
return this.store.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Device data that's specific to the device and does not vary based on account
|
||||
*
|
||||
* `device.set([key], true)`
|
||||
*/
|
||||
export const deviceArchive = new Archive<[], Device>({
|
||||
id: 'bsky_archive_device',
|
||||
})
|
||||
|
||||
if (__DEV__ && typeof window !== 'undefined') {
|
||||
// @ts-expect-error - dev global
|
||||
window.bsky_archive = {
|
||||
deviceArchive,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export type Device = {
|
||||
test?: boolean
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import {NoAccessScreen} from '#/ageAssurance/components/NoAccessScreen'
|
||||
import {RedirectOverlay} from '#/ageAssurance/components/RedirectOverlay'
|
||||
import {PassiveAnalytics} from '#/analytics/PassiveAnalytics'
|
||||
import {FlatNavigator, RoutesContainer} from '#/Navigation'
|
||||
import {deviceArchive} from '#/storage/archive'
|
||||
import {Composer} from './Composer.web'
|
||||
import {DrawerContent} from './Drawer'
|
||||
|
||||
@@ -49,6 +50,14 @@ function ShellInner() {
|
||||
useIntentHandler()
|
||||
|
||||
useEffect(() => {
|
||||
deviceArchive
|
||||
.set(['test'], true)
|
||||
.then(() => {
|
||||
console.log('stored')
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
const unsubscribe = navigator.addListener('state', () => {
|
||||
closeAllActiveElements()
|
||||
})
|
||||
|
||||
@@ -13093,6 +13093,11 @@ icss-utils@^5.0.0, icss-utils@^5.1.0:
|
||||
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
|
||||
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
|
||||
|
||||
idb-keyval@^6.2.2:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.2.tgz#b0171b5f73944854a3291a5cdba8e12768c4854a"
|
||||
integrity sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==
|
||||
|
||||
ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
|
||||
Reference in New Issue
Block a user