|
|
|
@ -1,5 +1,6 @@ |
|
|
|
import { ExtendedKind } from '@/constants' |
|
|
|
import { ExtendedKind } from '@/constants' |
|
|
|
import { tagNameEquals } from '@/lib/tag' |
|
|
|
import { tagNameEquals } from '@/lib/tag' |
|
|
|
|
|
|
|
import { TRelayInfo } from '@/types' |
|
|
|
import { Event, kinds } from 'nostr-tools' |
|
|
|
import { Event, kinds } from 'nostr-tools' |
|
|
|
|
|
|
|
|
|
|
|
type TValue<T = any> = { |
|
|
|
type TValue<T = any> = { |
|
|
|
@ -16,12 +17,13 @@ const StoreNames = { |
|
|
|
BOOKMARK_LIST_EVENTS: 'bookmarkListEvents', |
|
|
|
BOOKMARK_LIST_EVENTS: 'bookmarkListEvents', |
|
|
|
BLOSSOM_SERVER_LIST_EVENTS: 'blossomServerListEvents', |
|
|
|
BLOSSOM_SERVER_LIST_EVENTS: 'blossomServerListEvents', |
|
|
|
MUTE_DECRYPTED_TAGS: 'muteDecryptedTags', |
|
|
|
MUTE_DECRYPTED_TAGS: 'muteDecryptedTags', |
|
|
|
RELAY_INFO_EVENTS: 'relayInfoEvents', |
|
|
|
|
|
|
|
USER_EMOJI_LIST_EVENTS: 'userEmojiListEvents', |
|
|
|
USER_EMOJI_LIST_EVENTS: 'userEmojiListEvents', |
|
|
|
EMOJI_SET_EVENTS: 'emojiSetEvents', |
|
|
|
EMOJI_SET_EVENTS: 'emojiSetEvents', |
|
|
|
FAVORITE_RELAYS: 'favoriteRelays', |
|
|
|
FAVORITE_RELAYS: 'favoriteRelays', |
|
|
|
RELAY_SETS: 'relaySets', |
|
|
|
RELAY_SETS: 'relaySets', |
|
|
|
FOLLOWING_FAVORITE_RELAYS: 'followingFavoriteRelays' |
|
|
|
FOLLOWING_FAVORITE_RELAYS: 'followingFavoriteRelays', |
|
|
|
|
|
|
|
RELAY_INFOS: 'relayInfos', |
|
|
|
|
|
|
|
RELAY_INFO_EVENTS: 'relayInfoEvents' // deprecated
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class IndexedDbService { |
|
|
|
class IndexedDbService { |
|
|
|
@ -40,7 +42,7 @@ class IndexedDbService { |
|
|
|
init(): Promise<void> { |
|
|
|
init(): Promise<void> { |
|
|
|
if (!this.initPromise) { |
|
|
|
if (!this.initPromise) { |
|
|
|
this.initPromise = new Promise((resolve, reject) => { |
|
|
|
this.initPromise = new Promise((resolve, reject) => { |
|
|
|
const request = window.indexedDB.open('jumble', 7) |
|
|
|
const request = window.indexedDB.open('jumble', 8) |
|
|
|
|
|
|
|
|
|
|
|
request.onerror = (event) => { |
|
|
|
request.onerror = (event) => { |
|
|
|
reject(event) |
|
|
|
reject(event) |
|
|
|
@ -71,9 +73,6 @@ class IndexedDbService { |
|
|
|
if (!db.objectStoreNames.contains(StoreNames.MUTE_DECRYPTED_TAGS)) { |
|
|
|
if (!db.objectStoreNames.contains(StoreNames.MUTE_DECRYPTED_TAGS)) { |
|
|
|
db.createObjectStore(StoreNames.MUTE_DECRYPTED_TAGS, { keyPath: 'key' }) |
|
|
|
db.createObjectStore(StoreNames.MUTE_DECRYPTED_TAGS, { keyPath: 'key' }) |
|
|
|
} |
|
|
|
} |
|
|
|
if (!db.objectStoreNames.contains(StoreNames.RELAY_INFO_EVENTS)) { |
|
|
|
|
|
|
|
db.createObjectStore(StoreNames.RELAY_INFO_EVENTS, { keyPath: 'key' }) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!db.objectStoreNames.contains(StoreNames.FAVORITE_RELAYS)) { |
|
|
|
if (!db.objectStoreNames.contains(StoreNames.FAVORITE_RELAYS)) { |
|
|
|
db.createObjectStore(StoreNames.FAVORITE_RELAYS, { keyPath: 'key' }) |
|
|
|
db.createObjectStore(StoreNames.FAVORITE_RELAYS, { keyPath: 'key' }) |
|
|
|
} |
|
|
|
} |
|
|
|
@ -92,6 +91,12 @@ class IndexedDbService { |
|
|
|
if (!db.objectStoreNames.contains(StoreNames.EMOJI_SET_EVENTS)) { |
|
|
|
if (!db.objectStoreNames.contains(StoreNames.EMOJI_SET_EVENTS)) { |
|
|
|
db.createObjectStore(StoreNames.EMOJI_SET_EVENTS, { keyPath: 'key' }) |
|
|
|
db.createObjectStore(StoreNames.EMOJI_SET_EVENTS, { keyPath: 'key' }) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!db.objectStoreNames.contains(StoreNames.RELAY_INFOS)) { |
|
|
|
|
|
|
|
db.createObjectStore(StoreNames.RELAY_INFOS, { keyPath: 'key' }) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (db.objectStoreNames.contains(StoreNames.RELAY_INFO_EVENTS)) { |
|
|
|
|
|
|
|
db.deleteObjectStore(StoreNames.RELAY_INFO_EVENTS) |
|
|
|
|
|
|
|
} |
|
|
|
this.db = db |
|
|
|
this.db = db |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
@ -297,23 +302,28 @@ class IndexedDbService { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async getAllRelayInfoEvents(): Promise<Event[]> { |
|
|
|
async iterateProfileEvents(callback: (event: Event) => Promise<void>): Promise<void> { |
|
|
|
await this.initPromise |
|
|
|
await this.initPromise |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
|
|
|
if (!this.db) { |
|
|
|
if (!this.db) { |
|
|
|
return reject('database not initialized') |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
const transaction = this.db.transaction(StoreNames.RELAY_INFO_EVENTS, 'readonly') |
|
|
|
|
|
|
|
const store = transaction.objectStore(StoreNames.RELAY_INFO_EVENTS) |
|
|
|
|
|
|
|
const request = store.getAll() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
request.onsuccess = () => { |
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
|
|
|
|
const transaction = this.db!.transaction(StoreNames.PROFILE_EVENTS, 'readwrite') |
|
|
|
|
|
|
|
const store = transaction.objectStore(StoreNames.PROFILE_EVENTS) |
|
|
|
|
|
|
|
const request = store.openCursor() |
|
|
|
|
|
|
|
request.onsuccess = (event) => { |
|
|
|
|
|
|
|
const cursor = (event.target as IDBRequest).result |
|
|
|
|
|
|
|
if (cursor) { |
|
|
|
|
|
|
|
const value = (cursor.value as TValue<Event>).value |
|
|
|
|
|
|
|
if (value) { |
|
|
|
|
|
|
|
callback(value) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cursor.continue() |
|
|
|
|
|
|
|
} else { |
|
|
|
transaction.commit() |
|
|
|
transaction.commit() |
|
|
|
resolve( |
|
|
|
resolve() |
|
|
|
((request.result as TValue<Event>[]) |
|
|
|
} |
|
|
|
?.map((item) => item.value) |
|
|
|
|
|
|
|
.filter(Boolean) as Event[]) ?? [] |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
request.onerror = (event) => { |
|
|
|
request.onerror = (event) => { |
|
|
|
@ -323,20 +333,16 @@ class IndexedDbService { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async putRelayInfoEvent(event: Event): Promise<void> { |
|
|
|
async putFollowingFavoriteRelays(pubkey: string, relays: [string, string[]][]): Promise<void> { |
|
|
|
await this.initPromise |
|
|
|
await this.initPromise |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
if (!this.db) { |
|
|
|
if (!this.db) { |
|
|
|
return reject('database not initialized') |
|
|
|
return reject('database not initialized') |
|
|
|
} |
|
|
|
} |
|
|
|
const dValue = event.tags.find(tagNameEquals('d'))?.[1] |
|
|
|
const transaction = this.db.transaction(StoreNames.FOLLOWING_FAVORITE_RELAYS, 'readwrite') |
|
|
|
if (!dValue) { |
|
|
|
const store = transaction.objectStore(StoreNames.FOLLOWING_FAVORITE_RELAYS) |
|
|
|
return resolve() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const transaction = this.db.transaction(StoreNames.RELAY_INFO_EVENTS, 'readwrite') |
|
|
|
|
|
|
|
const store = transaction.objectStore(StoreNames.RELAY_INFO_EVENTS) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const putRequest = store.put(this.formatValue(dValue, event)) |
|
|
|
const putRequest = store.put(this.formatValue(pubkey, relays)) |
|
|
|
putRequest.onsuccess = () => { |
|
|
|
putRequest.onsuccess = () => { |
|
|
|
transaction.commit() |
|
|
|
transaction.commit() |
|
|
|
resolve() |
|
|
|
resolve() |
|
|
|
@ -349,28 +355,19 @@ class IndexedDbService { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async iterateProfileEvents(callback: (event: Event) => Promise<void>): Promise<void> { |
|
|
|
async getFollowingFavoriteRelays(pubkey: string): Promise<[string, string[]][] | null> { |
|
|
|
await this.initPromise |
|
|
|
await this.initPromise |
|
|
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
if (!this.db) { |
|
|
|
if (!this.db) { |
|
|
|
return |
|
|
|
return reject('database not initialized') |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const transaction = this.db.transaction(StoreNames.FOLLOWING_FAVORITE_RELAYS, 'readonly') |
|
|
|
|
|
|
|
const store = transaction.objectStore(StoreNames.FOLLOWING_FAVORITE_RELAYS) |
|
|
|
|
|
|
|
const request = store.get(pubkey) |
|
|
|
|
|
|
|
|
|
|
|
return new Promise<void>((resolve, reject) => { |
|
|
|
request.onsuccess = () => { |
|
|
|
const transaction = this.db!.transaction(StoreNames.PROFILE_EVENTS, 'readwrite') |
|
|
|
|
|
|
|
const store = transaction.objectStore(StoreNames.PROFILE_EVENTS) |
|
|
|
|
|
|
|
const request = store.openCursor() |
|
|
|
|
|
|
|
request.onsuccess = (event) => { |
|
|
|
|
|
|
|
const cursor = (event.target as IDBRequest).result |
|
|
|
|
|
|
|
if (cursor) { |
|
|
|
|
|
|
|
const value = (cursor.value as TValue<Event>).value |
|
|
|
|
|
|
|
if (value) { |
|
|
|
|
|
|
|
callback(value) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cursor.continue() |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
transaction.commit() |
|
|
|
transaction.commit() |
|
|
|
resolve() |
|
|
|
resolve((request.result as TValue<[string, string[]][]>)?.value) |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
request.onerror = (event) => { |
|
|
|
request.onerror = (event) => { |
|
|
|
@ -380,16 +377,16 @@ class IndexedDbService { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async putFollowingFavoriteRelays(pubkey: string, relays: [string, string[]][]): Promise<void> { |
|
|
|
async putRelayInfo(relayInfo: TRelayInfo): Promise<void> { |
|
|
|
await this.initPromise |
|
|
|
await this.initPromise |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
if (!this.db) { |
|
|
|
if (!this.db) { |
|
|
|
return reject('database not initialized') |
|
|
|
return reject('database not initialized') |
|
|
|
} |
|
|
|
} |
|
|
|
const transaction = this.db.transaction(StoreNames.FOLLOWING_FAVORITE_RELAYS, 'readwrite') |
|
|
|
const transaction = this.db.transaction(StoreNames.RELAY_INFOS, 'readwrite') |
|
|
|
const store = transaction.objectStore(StoreNames.FOLLOWING_FAVORITE_RELAYS) |
|
|
|
const store = transaction.objectStore(StoreNames.RELAY_INFOS) |
|
|
|
|
|
|
|
|
|
|
|
const putRequest = store.put(this.formatValue(pubkey, relays)) |
|
|
|
const putRequest = store.put(this.formatValue(relayInfo.url, relayInfo)) |
|
|
|
putRequest.onsuccess = () => { |
|
|
|
putRequest.onsuccess = () => { |
|
|
|
transaction.commit() |
|
|
|
transaction.commit() |
|
|
|
resolve() |
|
|
|
resolve() |
|
|
|
@ -402,19 +399,19 @@ class IndexedDbService { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async getFollowingFavoriteRelays(pubkey: string): Promise<[string, string[]][] | null> { |
|
|
|
async getRelayInfo(url: string): Promise<TRelayInfo | null> { |
|
|
|
await this.initPromise |
|
|
|
await this.initPromise |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
if (!this.db) { |
|
|
|
if (!this.db) { |
|
|
|
return reject('database not initialized') |
|
|
|
return reject('database not initialized') |
|
|
|
} |
|
|
|
} |
|
|
|
const transaction = this.db.transaction(StoreNames.FOLLOWING_FAVORITE_RELAYS, 'readonly') |
|
|
|
const transaction = this.db.transaction(StoreNames.RELAY_INFOS, 'readonly') |
|
|
|
const store = transaction.objectStore(StoreNames.FOLLOWING_FAVORITE_RELAYS) |
|
|
|
const store = transaction.objectStore(StoreNames.RELAY_INFOS) |
|
|
|
const request = store.get(pubkey) |
|
|
|
const request = store.get(url) |
|
|
|
|
|
|
|
|
|
|
|
request.onsuccess = () => { |
|
|
|
request.onsuccess = () => { |
|
|
|
transaction.commit() |
|
|
|
transaction.commit() |
|
|
|
resolve((request.result as TValue<[string, string[]][]>)?.value) |
|
|
|
resolve((request.result as TValue<TRelayInfo>)?.value) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
request.onerror = (event) => { |
|
|
|
request.onerror = (event) => { |
|
|
|
@ -491,6 +488,10 @@ class IndexedDbService { |
|
|
|
{ |
|
|
|
{ |
|
|
|
name: StoreNames.BLOSSOM_SERVER_LIST_EVENTS, |
|
|
|
name: StoreNames.BLOSSOM_SERVER_LIST_EVENTS, |
|
|
|
expirationTimestamp: Date.now() - 1000 * 60 * 60 * 24 // 1 days
|
|
|
|
expirationTimestamp: Date.now() - 1000 * 60 * 60 * 24 // 1 days
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: StoreNames.RELAY_INFOS, |
|
|
|
|
|
|
|
expirationTimestamp: Date.now() - 1000 * 60 * 60 * 24 // 1 days
|
|
|
|
} |
|
|
|
} |
|
|
|
] |
|
|
|
] |
|
|
|
const transaction = this.db!.transaction( |
|
|
|
const transaction = this.db!.transaction( |
|
|
|
|