lint fix wip
This commit is contained in:
parent
e0c025908b
commit
b69dfc96e9
175
docs/patterns/caching-patterns.md
Normal file
175
docs/patterns/caching-patterns.md
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
# Patterns de cache d'événements
|
||||||
|
|
||||||
|
**Date** : 2024-12-19
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Ce document décrit les patterns à utiliser pour cacher des événements Nostr dans IndexedDB.
|
||||||
|
|
||||||
|
## Pattern recommandé : Utilisation des helpers de cache
|
||||||
|
|
||||||
|
### Cache d'événements groupés par hash
|
||||||
|
|
||||||
|
Pour les objets qui ont plusieurs versions (publications, series), utiliser `groupAndCacheEventsByHash` :
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { groupAndCacheEventsByHash } from '@/lib/helpers/eventCacheHelper'
|
||||||
|
import { extractPublicationFromEvent } from '@/lib/metadataExtractor'
|
||||||
|
import { parseObjectId } from '@/lib/urlGenerator'
|
||||||
|
import { extractTagsFromEvent } from '@/lib/nostrTagSystem'
|
||||||
|
|
||||||
|
await groupAndCacheEventsByHash(events, {
|
||||||
|
objectType: 'publication',
|
||||||
|
extractor: extractPublicationFromEvent,
|
||||||
|
getHash: (extracted: unknown): string | null => {
|
||||||
|
const id = (extracted as { id?: string })?.id
|
||||||
|
if (!id) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const parsed = parseObjectId(id)
|
||||||
|
return parsed.hash ?? id
|
||||||
|
},
|
||||||
|
getIndex: (extracted: unknown): number => {
|
||||||
|
return (extracted as { index?: number })?.index ?? 0
|
||||||
|
},
|
||||||
|
getVersion: (event: Event): number => {
|
||||||
|
return extractTagsFromEvent(event).version ?? 0
|
||||||
|
},
|
||||||
|
getHidden: (event: Event): boolean => {
|
||||||
|
return extractTagsFromEvent(event).hidden ?? false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache d'événements simples
|
||||||
|
|
||||||
|
Pour les objets sans versioning (purchases, sponsoring, review tips), utiliser `writeObjectToCache` :
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { writeObjectToCache } from '@/lib/helpers/writeObjectHelper'
|
||||||
|
|
||||||
|
await writeObjectToCache({
|
||||||
|
objectType: 'purchase',
|
||||||
|
hash: purchase.hash,
|
||||||
|
event,
|
||||||
|
parsed: purchase,
|
||||||
|
index: purchase.index,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache avec extraction automatique
|
||||||
|
|
||||||
|
Pour combiner extraction et cache en une seule opération :
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { extractAndWriteObject } from '@/lib/helpers/writeObjectHelper'
|
||||||
|
import { extractPurchaseFromEvent } from '@/lib/metadataExtractor'
|
||||||
|
|
||||||
|
const cached = await extractAndWriteObject(
|
||||||
|
event,
|
||||||
|
'purchase',
|
||||||
|
extractPurchaseFromEvent
|
||||||
|
)
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
console.log('Event cached successfully')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pattern de cache dans les boucles
|
||||||
|
|
||||||
|
### Optimisation : Cache l'import de writeService
|
||||||
|
|
||||||
|
Le helper `writeObjectToCache` cache automatiquement l'import de `writeService`, donc pas besoin d'optimiser manuellement :
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// ✅ Bon : writeObjectToCache gère le cache automatiquement
|
||||||
|
for (const event of events) {
|
||||||
|
await writeObjectToCache({
|
||||||
|
objectType: 'purchase',
|
||||||
|
hash: purchase.hash,
|
||||||
|
event,
|
||||||
|
parsed: purchase,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ❌ Éviter : Import répété dans la boucle
|
||||||
|
for (const event of events) {
|
||||||
|
const { writeService } = await import('./writeService')
|
||||||
|
await writeService.writeObject(...)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gestion des versions
|
||||||
|
|
||||||
|
Pour les objets avec versioning, `groupAndCacheEventsByHash` :
|
||||||
|
1. Groupe les événements par hash
|
||||||
|
2. Sélectionne la dernière version avec `getLatestVersion`
|
||||||
|
3. Cache uniquement la dernière version
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Les événements sont automatiquement groupés par hash
|
||||||
|
// Seule la dernière version est cachée
|
||||||
|
await groupAndCacheEventsByHash(events, {
|
||||||
|
objectType: 'publication',
|
||||||
|
extractor: extractPublicationFromEvent,
|
||||||
|
// ... config
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bonnes pratiques
|
||||||
|
|
||||||
|
1. **Utiliser les helpers appropriés** :
|
||||||
|
- `groupAndCacheEventsByHash` pour objets avec versioning
|
||||||
|
- `writeObjectToCache` pour objets simples
|
||||||
|
- `extractAndWriteObject` pour combiner extraction et cache
|
||||||
|
|
||||||
|
2. **Ne pas dupliquer la logique de cache** : Toujours utiliser les helpers centralisés
|
||||||
|
|
||||||
|
3. **Gérer les erreurs** : Les helpers propagent les erreurs, les gérer en amont
|
||||||
|
|
||||||
|
4. **Typage strict** : Utiliser les types TypeScript pour `parsed`
|
||||||
|
|
||||||
|
5. **Performance** : Les helpers optimisent automatiquement les imports
|
||||||
|
|
||||||
|
## Exemples complets
|
||||||
|
|
||||||
|
### Cache de publications avec groupement
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { groupAndCacheEventsByHash } from '@/lib/helpers/eventCacheHelper'
|
||||||
|
import { cachePublicationsByHash } from '@/lib/helpers/syncContentCacheHelpers'
|
||||||
|
|
||||||
|
// Utiliser le helper spécialisé
|
||||||
|
await cachePublicationsByHash(events)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache de purchases
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { cachePurchases } from '@/lib/helpers/syncCacheHelpers'
|
||||||
|
|
||||||
|
await cachePurchases(events)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache personnalisé
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { writeObjectToCache } from '@/lib/helpers/writeObjectHelper'
|
||||||
|
|
||||||
|
for (const event of events) {
|
||||||
|
const extracted = await extractMyObjectFromEvent(event)
|
||||||
|
if (extracted?.hash) {
|
||||||
|
await writeObjectToCache({
|
||||||
|
objectType: 'my_object',
|
||||||
|
hash: extracted.hash,
|
||||||
|
event,
|
||||||
|
parsed: extracted,
|
||||||
|
version: extractTagsFromEvent(event).version,
|
||||||
|
hidden: extractTagsFromEvent(event).hidden,
|
||||||
|
index: extracted.index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
181
docs/patterns/indexedDB-patterns.md
Normal file
181
docs/patterns/indexedDB-patterns.md
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
# Patterns d'utilisation IndexedDB
|
||||||
|
|
||||||
|
**Date** : 2024-12-19
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Ce document décrit les patterns à utiliser pour interagir avec IndexedDB dans le projet. Tous les services IndexedDB doivent utiliser `IndexedDBHelper` pour garantir la cohérence et réduire la duplication.
|
||||||
|
|
||||||
|
## Pattern recommandé : Utilisation de IndexedDBHelper
|
||||||
|
|
||||||
|
### Création d'un service IndexedDB
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createIndexedDBHelper } from '@/lib/helpers/indexedDBHelper'
|
||||||
|
|
||||||
|
const dbHelper = createIndexedDBHelper({
|
||||||
|
dbName: 'my_database',
|
||||||
|
version: 1,
|
||||||
|
storeName: 'my_store',
|
||||||
|
keyPath: 'id',
|
||||||
|
indexes: [
|
||||||
|
{ name: 'timestamp', keyPath: 'timestamp', unique: false },
|
||||||
|
{ name: 'type', keyPath: 'type', unique: false },
|
||||||
|
],
|
||||||
|
onUpgrade: (db, event) => {
|
||||||
|
// Migration logic if needed
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Utilisation
|
||||||
|
await dbHelper.init()
|
||||||
|
const store = await dbHelper.getStore('readwrite')
|
||||||
|
await dbHelper.add({ id: '1', data: 'value' })
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opérations courantes
|
||||||
|
|
||||||
|
#### Ajouter un objet
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await dbHelper.add(object)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Récupérer un objet par clé
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const obj = await dbHelper.get<MyType>(key)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Récupérer par index
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const obj = await dbHelper.getByIndex<MyType>('indexName', value)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Récupérer tous les objets
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const all = await dbHelper.getAll<MyType>()
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Compter par index
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const count = await dbHelper.countByIndex('indexName', IDBKeyRange.only(value))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Mettre à jour un objet
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await dbHelper.update(object)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Supprimer un objet
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await dbHelper.delete(key)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Supprimer tous les objets
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await dbHelper.clear()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gestion des erreurs
|
||||||
|
|
||||||
|
Toutes les erreurs IndexedDB sont automatiquement wrappées dans `IndexedDBError` avec :
|
||||||
|
- Message d'erreur
|
||||||
|
- Nom de l'opération
|
||||||
|
- Nom du store (si applicable)
|
||||||
|
- Cause originale
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
try {
|
||||||
|
await dbHelper.add(object)
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof IndexedDBError) {
|
||||||
|
console.error(`Operation: ${error.operation}, Store: ${error.storeName}`)
|
||||||
|
}
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Transactions
|
||||||
|
|
||||||
|
Les transactions sont gérées automatiquement par `IndexedDBHelper`. Chaque opération utilise une transaction appropriée.
|
||||||
|
|
||||||
|
Pour des opérations multiples dans une seule transaction :
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const store = await dbHelper.getStore('readwrite')
|
||||||
|
// Toutes les opérations sur store sont dans la même transaction
|
||||||
|
await store.add(object1)
|
||||||
|
await store.add(object2)
|
||||||
|
// Transaction se ferme automatiquement à la fin de la fonction
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migrations
|
||||||
|
|
||||||
|
Les migrations sont gérées dans `onUpgrade` :
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const dbHelper = createIndexedDBHelper({
|
||||||
|
// ...
|
||||||
|
onUpgrade: (db, event) => {
|
||||||
|
const transaction = event.target.transaction
|
||||||
|
const store = transaction.objectStore('my_store')
|
||||||
|
|
||||||
|
// Ajouter un index si nécessaire
|
||||||
|
if (!store.indexNames.contains('newIndex')) {
|
||||||
|
store.createIndex('newIndex', 'newField', { unique: false })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bonnes pratiques
|
||||||
|
|
||||||
|
1. **Toujours utiliser IndexedDBHelper** : Ne pas créer de code d'initialisation IndexedDB personnalisé
|
||||||
|
2. **Gérer les erreurs** : Toujours utiliser try/catch avec IndexedDBError
|
||||||
|
3. **Typage strict** : Utiliser les génériques TypeScript pour le typage
|
||||||
|
4. **Transactions** : Regrouper les opérations liées dans une seule transaction
|
||||||
|
5. **Migrations** : Tester les migrations sur des données réelles avant déploiement
|
||||||
|
|
||||||
|
## Exemples complets
|
||||||
|
|
||||||
|
### Service de cache simple
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createIndexedDBHelper } from '@/lib/helpers/indexedDBHelper'
|
||||||
|
|
||||||
|
class MyCacheService {
|
||||||
|
private dbHelper = createIndexedDBHelper({
|
||||||
|
dbName: 'my_cache',
|
||||||
|
version: 1,
|
||||||
|
storeName: 'items',
|
||||||
|
keyPath: 'id',
|
||||||
|
indexes: [
|
||||||
|
{ name: 'timestamp', keyPath: 'timestamp', unique: false },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
async init(): Promise<void> {
|
||||||
|
await this.dbHelper.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
async addItem(item: MyItem): Promise<void> {
|
||||||
|
await this.dbHelper.add(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItem(id: string): Promise<MyItem | null> {
|
||||||
|
return await this.dbHelper.get<MyItem>(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllItems(): Promise<MyItem[]> {
|
||||||
|
return await this.dbHelper.getAll<MyItem>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
152
docs/patterns/subscription-patterns.md
Normal file
152
docs/patterns/subscription-patterns.md
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# Patterns de subscription Nostr
|
||||||
|
|
||||||
|
**Date** : 2024-12-19
|
||||||
|
**Auteur** : Équipe 4NK
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Ce document décrit les patterns à utiliser pour créer des subscriptions Nostr avec rotation de relais et gestion des événements.
|
||||||
|
|
||||||
|
## Pattern recommandé : Utilisation de createSyncSubscription
|
||||||
|
|
||||||
|
### Subscription simple avec relay rotation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createSyncSubscription } from '@/lib/helpers/syncSubscriptionHelper'
|
||||||
|
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
||||||
|
import type { Filter } from 'nostr-tools'
|
||||||
|
|
||||||
|
async function fetchEvents(
|
||||||
|
pool: SimplePoolWithSub,
|
||||||
|
filters: Filter[]
|
||||||
|
): Promise<Event[]> {
|
||||||
|
const result = await createSyncSubscription({
|
||||||
|
pool,
|
||||||
|
filters,
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.events
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subscription avec filtrage d'événements
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const result = await createSyncSubscription({
|
||||||
|
pool,
|
||||||
|
filters,
|
||||||
|
eventFilter: (event: Event): boolean => {
|
||||||
|
const tags = extractTagsFromEvent(event)
|
||||||
|
return tags.type === 'publication' && !tags.hidden
|
||||||
|
},
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subscription avec callbacks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const result = await createSyncSubscription({
|
||||||
|
pool,
|
||||||
|
filters,
|
||||||
|
onEvent: (event: Event): void => {
|
||||||
|
console.log('Received event:', event.id)
|
||||||
|
// Traitement immédiat si nécessaire
|
||||||
|
},
|
||||||
|
onComplete: async (events: Event[]): Promise<void> => {
|
||||||
|
console.log(`Received ${events.length} events`)
|
||||||
|
// Traitement final de tous les événements
|
||||||
|
},
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Subscription avec mise à jour du progrès
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const result = await createSyncSubscription({
|
||||||
|
pool,
|
||||||
|
filters,
|
||||||
|
updateProgress: (relayUrl: string): void => {
|
||||||
|
// Mise à jour personnalisée du progrès
|
||||||
|
console.log('Using relay:', relayUrl)
|
||||||
|
},
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gestion des erreurs
|
||||||
|
|
||||||
|
Les erreurs de subscription sont gérées automatiquement :
|
||||||
|
- Rotation automatique vers le relais suivant en cas d'échec
|
||||||
|
- Fallback vers le relais principal si tous les relais échouent
|
||||||
|
- Timeout automatique après le délai spécifié
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
try {
|
||||||
|
const result = await createSyncSubscription({
|
||||||
|
pool,
|
||||||
|
filters,
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
// Traiter les événements
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Subscription failed:', error)
|
||||||
|
// Gérer l'erreur
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bonnes pratiques
|
||||||
|
|
||||||
|
1. **Toujours utiliser createSyncSubscription** : Ne pas créer de code de subscription personnalisé
|
||||||
|
2. **Définir un timeout approprié** : Par défaut 10 secondes, ajuster selon le contexte
|
||||||
|
3. **Filtrer les événements** : Utiliser `eventFilter` pour éviter de traiter des événements non pertinents
|
||||||
|
4. **Gérer les callbacks** : Utiliser `onEvent` pour traitement immédiat, `onComplete` pour traitement final
|
||||||
|
5. **Mise à jour du progrès** : Utiliser `updateProgress` pour informer l'utilisateur
|
||||||
|
|
||||||
|
## Exemples complets
|
||||||
|
|
||||||
|
### Synchronisation de publications
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createSyncSubscription } from '@/lib/helpers/syncSubscriptionHelper'
|
||||||
|
import { buildTagFilter } from '@/lib/nostrTagSystemFilter'
|
||||||
|
import { PLATFORM_SERVICE } from '@/lib/platformConfig'
|
||||||
|
import { extractTagsFromEvent } from '@/lib/nostrTagSystem'
|
||||||
|
|
||||||
|
async function syncPublications(
|
||||||
|
pool: SimplePoolWithSub,
|
||||||
|
authorPubkey: string
|
||||||
|
): Promise<void> {
|
||||||
|
const { getLastSyncDate } = await import('./syncStorage')
|
||||||
|
const lastSyncDate = await getLastSyncDate()
|
||||||
|
|
||||||
|
const filters = [
|
||||||
|
{
|
||||||
|
...buildTagFilter({
|
||||||
|
type: 'publication',
|
||||||
|
authorPubkey,
|
||||||
|
service: PLATFORM_SERVICE,
|
||||||
|
}),
|
||||||
|
since: lastSyncDate,
|
||||||
|
limit: 1000,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = await createSyncSubscription({
|
||||||
|
pool,
|
||||||
|
filters,
|
||||||
|
eventFilter: (event: Event): boolean => {
|
||||||
|
const tags = extractTagsFromEvent(event)
|
||||||
|
return tags.type === 'publication' && !tags.hidden
|
||||||
|
},
|
||||||
|
timeout: 10000,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Traiter les événements
|
||||||
|
for (const event of result.events) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -79,14 +79,16 @@ export async function extractAndWriteObject<T extends { hash?: string; index?: n
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeObjectToCache({
|
const params: WriteObjectParams = {
|
||||||
objectType,
|
objectType,
|
||||||
hash,
|
hash,
|
||||||
event,
|
event,
|
||||||
parsed: extracted,
|
parsed: extracted,
|
||||||
index: extracted.index,
|
}
|
||||||
})
|
if (extracted.index !== undefined) {
|
||||||
|
params.index = extracted.index
|
||||||
|
}
|
||||||
|
await writeObjectToCache(params)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
36
lib/nostr.ts
36
lib/nostr.ts
@ -14,7 +14,7 @@ import { getPrimaryRelay, getPrimaryRelaySync } from './config'
|
|||||||
import { buildTagFilter } from './nostrTagSystem'
|
import { buildTagFilter } from './nostrTagSystem'
|
||||||
import { PLATFORM_SERVICE, MIN_EVENT_DATE } from './platformConfig'
|
import { PLATFORM_SERVICE, MIN_EVENT_DATE } from './platformConfig'
|
||||||
import type { PublishResult, RelayPublishStatus } from './publishResult'
|
import type { PublishResult, RelayPublishStatus } from './publishResult'
|
||||||
import { objectCache, type ObjectType } from './objectCache'
|
import { objectCache, type CachedObject } from './objectCache'
|
||||||
|
|
||||||
class NostrService {
|
class NostrService {
|
||||||
private pool: SimplePool | null = null
|
private pool: SimplePool | null = null
|
||||||
@ -486,33 +486,15 @@ class NostrService {
|
|||||||
// If not found in unpublished, search all objects
|
// If not found in unpublished, search all objects
|
||||||
for (const objectType of objectTypes) {
|
for (const objectType of objectTypes) {
|
||||||
try {
|
try {
|
||||||
// Use private method via type assertion for direct database access
|
// Use getAll to search all objects
|
||||||
const db = await (objectCache as unknown as { initDB: (objectType: ObjectType) => Promise<IDBDatabase> }).initDB(objectType)
|
const allObjects = await objectCache.getAll(objectType)
|
||||||
const transaction = db.transaction(['objects'], 'readonly')
|
const matching = allObjects.find((obj) => {
|
||||||
const store = transaction.objectStore('objects')
|
const cachedObj = obj as CachedObject
|
||||||
const request = store.openCursor()
|
return cachedObj.event?.id === eventId
|
||||||
|
|
||||||
const found = await new Promise<string | null>((resolve, reject) => {
|
|
||||||
request.onsuccess = (event: globalThis.Event): void => {
|
|
||||||
const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result
|
|
||||||
if (cursor) {
|
|
||||||
const obj = cursor.value as { id: string; event: { id: string } }
|
|
||||||
if (obj.event.id === eventId) {
|
|
||||||
resolve(obj.id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cursor.continue()
|
|
||||||
} else {
|
|
||||||
resolve(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request.onerror = (): void => {
|
|
||||||
reject(request.error)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
if (matching) {
|
||||||
if (found) {
|
const cachedObj = matching as CachedObject
|
||||||
await writeService.updatePublished(objectType, found, published)
|
await writeService.updatePublished(objectType, cachedObj.id, published)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { nostrService } from './nostr'
|
import { nostrService } from './nostr'
|
||||||
|
import type { SimplePool } from 'nostr-tools'
|
||||||
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
||||||
import type { SyncProgress } from './helpers/syncProgressHelper'
|
import type { SyncProgress } from './helpers/syncProgressHelper'
|
||||||
import { initializeSyncProgress, finalizeSync } from './helpers/syncProgressHelper'
|
import { initializeSyncProgress, finalizeSync } from './helpers/syncProgressHelper'
|
||||||
@ -30,7 +31,7 @@ export async function syncUserContentToCache(
|
|||||||
onProgress?: (progress: SyncProgress) => void
|
onProgress?: (progress: SyncProgress) => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const pool = nostrService.getPool()
|
const pool: SimplePool | null = (nostrService as { getPool: () => SimplePool | null }).getPool()
|
||||||
if (!pool) {
|
if (!pool) {
|
||||||
const errorMsg = 'Pool not initialized, cannot sync user content'
|
const errorMsg = 'Pool not initialized, cannot sync user content'
|
||||||
console.warn(errorMsg)
|
console.warn(errorMsg)
|
||||||
|
|||||||
@ -72,10 +72,10 @@ async function executeWriteTask(task) {
|
|||||||
await handleCreateNotification(data, id)
|
await handleCreateNotification(data, id)
|
||||||
break
|
break
|
||||||
case 'LOG_PUBLICATION':
|
case 'LOG_PUBLICATION':
|
||||||
await handleLogPublication(data, id)
|
await handleLogPublication(data)
|
||||||
break
|
break
|
||||||
case 'WRITE_MULTI_TABLE':
|
case 'WRITE_MULTI_TABLE':
|
||||||
await handleWriteMultiTable(data, id)
|
await handleWriteMultiTable(data)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown message type: ${type}`)
|
throw new Error(`Unknown message type: ${type}`)
|
||||||
@ -121,7 +121,7 @@ async function handleWriteObject(data, taskId) {
|
|||||||
const store = transaction.objectStore('objects')
|
const store = transaction.objectStore('objects')
|
||||||
|
|
||||||
// Vérifier si l'objet existe déjà pour préserver published
|
// Vérifier si l'objet existe déjà pour préserver published
|
||||||
const existing = await executeTransactionOperation(store, (s) => s.get(finalId)).catch((_e) => null)
|
const existing = await executeTransactionOperation(store, (s) => s.get(finalId)).catch(() => null)
|
||||||
|
|
||||||
// Préserver published si existant et non fourni
|
// Préserver published si existant et non fourni
|
||||||
const finalPublished = existing && published === false ? existing.published : (published ?? false)
|
const finalPublished = existing && published === false ? existing.published : (published ?? false)
|
||||||
@ -218,7 +218,7 @@ async function handleUpdatePublished(data, taskId) {
|
|||||||
* Handle write multi-table request
|
* Handle write multi-table request
|
||||||
* Transactions multi-tables : plusieurs transactions, logique de découpage côté worker
|
* Transactions multi-tables : plusieurs transactions, logique de découpage côté worker
|
||||||
*/
|
*/
|
||||||
async function handleWriteMultiTable(data, _taskId) {
|
async function handleWriteMultiTable(data) {
|
||||||
const { writes } = data // Array of { objectType, hash, event, parsed, version, hidden, index, published }
|
const { writes } = data // Array of { objectType, hash, event, parsed, version, hidden, index, published }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -251,7 +251,7 @@ async function handleWriteMultiTable(data, _taskId) {
|
|||||||
finalId = `${hash}:${count}:${version}`
|
finalId = `${hash}:${count}:${version}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = await executeTransactionOperation(store, (s) => s.get(finalId)).catch((_e) => null)
|
const existing = await executeTransactionOperation(store, (s) => s.get(finalId)).catch(() => null)
|
||||||
|
|
||||||
const finalPublished = existing && published === false ? existing.published : (published ?? false)
|
const finalPublished = existing && published === false ? existing.published : (published ?? false)
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ async function handleCreateNotification(data, taskId) {
|
|||||||
|
|
||||||
// Vérifier si la notification existe déjà
|
// Vérifier si la notification existe déjà
|
||||||
const index = store.index('eventId')
|
const index = store.index('eventId')
|
||||||
const existing = await executeTransactionOperation(index, (idx) => idx.get(eventId)).catch((_e) => null)
|
const existing = await executeTransactionOperation(index, (idx) => idx.get(eventId)).catch(() => null)
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// Notification déjà existante
|
// Notification déjà existante
|
||||||
@ -344,7 +344,7 @@ async function handleCreateNotification(data, taskId) {
|
|||||||
/**
|
/**
|
||||||
* Handle log publication request
|
* Handle log publication request
|
||||||
*/
|
*/
|
||||||
async function handleLogPublication(data, _taskId) {
|
async function handleLogPublication(data) {
|
||||||
const { eventId, relayUrl, success, error, objectType, objectId } = data
|
const { eventId, relayUrl, success, error, objectType, objectId } = data
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -418,7 +418,7 @@ function openDB(objectType) {
|
|||||||
* Open IndexedDB for notifications
|
* Open IndexedDB for notifications
|
||||||
*/
|
*/
|
||||||
function openNotificationDB() {
|
function openNotificationDB() {
|
||||||
return openIndexedDB('nostr_notifications', 1, (db, _event) => {
|
return openIndexedDB('nostr_notifications', 1, (db) => {
|
||||||
if (!db.objectStoreNames.contains('notifications')) {
|
if (!db.objectStoreNames.contains('notifications')) {
|
||||||
const store = db.createObjectStore('notifications', { keyPath: 'id' })
|
const store = db.createObjectStore('notifications', { keyPath: 'id' })
|
||||||
store.createIndex('type', 'type', { unique: false })
|
store.createIndex('type', 'type', { unique: false })
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user