diff --git a/src/lib/accountKeyStore.ts b/src/lib/accountKeyStore.ts index c4baa91..ebe7dd6 100644 --- a/src/lib/accountKeyStore.ts +++ b/src/lib/accountKeyStore.ts @@ -1,7 +1,7 @@ import { BlahKeyPair, BlahPublicKey, type EncodedBlahKeyPair } from '@blah-im/core/crypto'; import { openDB, type DBSchema, type IDBPDatabase } from 'idb'; -const IDB_NAME = 'blah-accounts'; +const IDB_NAME = 'weblah-accounts'; const IDB_OBJECT_STORE_NAME = 'accounts'; type SavedObject = { diff --git a/src/lib/profileStore.ts b/src/lib/profileStore.ts new file mode 100644 index 0000000..f3e6b56 --- /dev/null +++ b/src/lib/profileStore.ts @@ -0,0 +1,56 @@ +import type { BlahProfile } from '@blah-im/core/identity'; +import { openDB, type DBSchema, type IDBPDatabase } from 'idb'; + +const IDB_NAME = 'weblah-profiles'; +const IDB_OBJECT_STORE_NAME = 'profiles'; + +const PROFILE_MAX_AGE = 1000 * 60 * 60 * 24 * 30; // 30 days + +interface ProfileStoreDB extends DBSchema { + [IDB_OBJECT_STORE_NAME]: { + key: string; + value: BlahProfile & { idKeyId: string; lastUpdatedAt: Date }; + indexes: { id_urls: string }; + }; +} + +export class ProfileStore { + private db: IDBPDatabase; + + private constructor(db: IDBPDatabase) { + this.db = db; + } + + static async open(): Promise { + const db = await openDB(IDB_NAME, 1, { + upgrade(db) { + if (!db.objectStoreNames.contains(IDB_OBJECT_STORE_NAME)) { + const store = db.createObjectStore(IDB_OBJECT_STORE_NAME, { keyPath: 'idKeyId' }); + store.createIndex('id_urls', 'id_urls', { multiEntry: true, unique: true }); + } + } + }); + + const store = new ProfileStore(db); + await store.removeOldProfiles(); + return store; + } + + async updateProfile(idKeyId: string, profile: BlahProfile): Promise { + await this.db.put(IDB_OBJECT_STORE_NAME, { idKeyId, ...profile, lastUpdatedAt: new Date() }); + } + + async getProfile(idKeyId: string): Promise { + return await this.db.get(IDB_OBJECT_STORE_NAME, idKeyId); + } + + async getProfileByIdUrl(idUrl: string): Promise { + return await this.db.getFromIndex(IDB_OBJECT_STORE_NAME, 'id_urls', idUrl); + } + + async removeOldProfiles(): Promise { + const now = new Date(); + const cutoff = new Date(now.getTime() - PROFILE_MAX_AGE); + await this.db.delete(IDB_OBJECT_STORE_NAME, IDBKeyRange.upperBound(cutoff)); + } +}