forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {create} from '#/storage/archive/db'
2import {type DB} from '#/storage/archive/db/types'
3import {type Device} from '#/storage/archive/schema'
4
5export * from '#/storage/archive/schema'
6
7/**
8 * Generic archival storage class. DO NOT use this directly. Instead, use the
9 * exported `Archive` instances below.
10 */
11export class Archive<Scopes extends unknown[], Schema> {
12 protected sep = ':'
13 protected store: DB
14
15 constructor({id}: {id: string}) {
16 this.store = create({id})
17 }
18
19 /**
20 * Store a value in archival storage based on scopes and/or keys
21 *
22 * `set([key], value)`
23 * `set([scope, key], value)`
24 */
25 async set<Key extends keyof Schema>(
26 scopes: [...Scopes, Key],
27 data: Schema[Key],
28 ): Promise<void> {
29 // stored as `{ data: <value> }` structure to ease stringification
30 return this.store.set(scopes.join(this.sep), JSON.stringify({data}))
31 }
32
33 /**
34 * Get a value from archival storage based on scopes and/or keys
35 *
36 * `get([key])`
37 * `get([scope, key])`
38 */
39 async get<Key extends keyof Schema>(
40 scopes: [...Scopes, Key],
41 ): Promise<Schema[Key] | undefined> {
42 const res = await this.store.get(scopes.join(this.sep))
43 if (!res) return undefined
44 // parsed from storage structure `{ data: <value> }`
45 return JSON.parse(res).data
46 }
47
48 /**
49 * Remove a value from archival storage based on scopes and/or keys
50 *
51 * `remove([key])`
52 * `remove([scope, key])`
53 */
54 async remove<Key extends keyof Schema>(scopes: [...Scopes, Key]) {
55 return this.store.delete(scopes.join(this.sep))
56 }
57
58 /**
59 * Remove many values from the same archival storage scope by keys
60 *
61 * `removeMany([], [key])`
62 * `removeMany([scope], [key])`
63 */
64 async removeMany<Key extends keyof Schema>(scopes: [...Scopes], keys: Key[]) {
65 return Promise.all(keys.map(key => this.remove([...scopes, key])))
66 }
67
68 /**
69 * For debugging purposes
70 */
71 async removeAll() {
72 return this.store.clear()
73 }
74}
75
76/**
77 * Device data that's specific to the device and does not vary based on account
78 *
79 * `device.set([key], true)`
80 */
81export const deviceArchive = new Archive<[], Device>({
82 id: 'bsky_archive_device',
83})
84
85if (__DEV__ && typeof window !== 'undefined') {
86 // @ts-expect-error - dev global
87 window.bsky_archive = {
88 deviceArchive,
89 }
90}