From 9f7a0e15276deee943fc8a934e135623c0ca63b1 Mon Sep 17 00:00:00 2001 From: Nicolas Cantu Date: Wed, 7 Jan 2026 02:06:09 +0100 Subject: [PATCH] lint fix wip --- lib/articleMutations.ts | 250 +++++++++++++++++++++++++++++---- lib/articlePublisherPublish.ts | 117 ++++++++++++++- lib/notificationDetector.ts | 4 +- lib/paymentNotes.ts | 99 ++++++++++++- lib/platformTracking.ts | 10 +- lib/reviewRewardUpdate.ts | 131 +++++++++++------ lib/websocketService.ts | 9 +- lib/writeOrchestrator.ts | 4 +- lib/writeService.ts | 6 +- pages/author/[pubkey].tsx | 2 +- 10 files changed, 535 insertions(+), 97 deletions(-) diff --git a/lib/articleMutations.ts b/lib/articleMutations.ts index 608602b..103d344 100644 --- a/lib/articleMutations.ts +++ b/lib/articleMutations.ts @@ -4,10 +4,13 @@ import { storePrivateContent, getStoredPrivateContent } from './articleStorage' import { buildTags } from './nostrTagSystem' import { PLATFORM_SERVICE } from './platformConfig' import { generateSeriesHashId, generatePublicationHashId } from './hashIdGenerator' -import { parseObjectId } from './urlGenerator' +import { buildObjectId } from './urlGenerator' import type { ArticleDraft, PublishedArticle } from './articlePublisher' import type { AlbyInvoice } from '@/types/alby' -import type { Review, Series } from '@/types/nostr' +import type { Article, Review, Series } from '@/types/nostr' +import { writeOrchestrator } from './writeOrchestrator' +import { finalizeEvent } from 'nostr-tools' +import { hexToBytes } from 'nostr-tools/utils' export interface ArticleUpdateResult extends PublishedArticle { originalArticleId: string @@ -36,6 +39,55 @@ async function ensurePresentation(authorPubkey: string): Promise { return presentation.id } +async function buildParsedArticleFromDraft( + draft: ArticleDraft, + invoice: AlbyInvoice, + authorPubkey: string +): Promise<{ article: Article; hash: string; version: number; index: number }> { + const category = draft.category === 'science-fiction' ? 'sciencefiction' : draft.category === 'scientific-research' ? 'research' : 'sciencefiction' + + const hashId = await generatePublicationHashId({ + pubkey: authorPubkey, + title: draft.title, + preview: draft.preview, + category, + seriesId: draft.seriesId ?? undefined, + bannerUrl: draft.bannerUrl ?? undefined, + zapAmount: draft.zapAmount, + }) + + const hash = hashId + const version = 0 + const index = 0 + const id = buildObjectId(hash, index, version) + + const article: Article = { + id, + hash, + version, + index, + pubkey: authorPubkey, + title: draft.title, + preview: draft.preview, + content: '', + description: draft.preview, + contentDescription: draft.preview, + createdAt: Math.floor(Date.now() / 1000), + zapAmount: draft.zapAmount, + paid: false, + thumbnailUrl: draft.bannerUrl ?? '', + invoice: invoice.invoice, + paymentHash: invoice.paymentHash ?? undefined, + category: draft.category, + ...(draft.seriesId ? { seriesId: draft.seriesId } : {}), + ...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}), + ...(draft.pages && draft.pages.length > 0 ? { pages: draft.pages } : {}), + kindType: 'article', + } + + return { article, hash, version, index } +} + async function publishPreviewWithInvoice( draft: ArticleDraft, invoice: AlbyInvoice, @@ -43,9 +95,48 @@ async function publishPreviewWithInvoice( presentationId: string, extraTags?: string[][] ): Promise { - const previewEvent = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags) - const publishedEvent = await nostrService.publishEvent(previewEvent) - return publishedEvent ?? null + // Build parsed article object + const { article, hash, version, index } = await buildParsedArticleFromDraft(draft, invoice, authorPubkey) + + // Build event template + const previewEventTemplate = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags) + + // Set private key in orchestrator + const privateKey = nostrService.getPrivateKey() + if (!privateKey) { + throw new Error('Private key required for signing') + } + writeOrchestrator.setPrivateKey(privateKey) + + // Finalize event + const secretKey = hexToBytes(privateKey) + const event = finalizeEvent(previewEventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'publication', + hash, + event, + parsed: article, + version, + hidden: false, + index, + }, + relays + ) + + if (!result.success) { + return null + } + + return event } export async function publishSeries(params: { @@ -60,18 +151,27 @@ export async function publishSeries(params: { ensureKeys(params.authorPubkey, params.authorPrivateKey) const {category} = params requireCategory(category) - const event = await buildSeriesEvent(params, category) - const published = await nostrService.publishEvent(event) - if (!published) { - throw new Error('Failed to publish series') - } - const parsed = parseObjectId(published.id) - const {hash: parsedHash, version: parsedVersion, index: parsedIndex} = parsed - const hash = parsedHash ?? published.id - const version = parsedVersion ?? 0 - const index = parsedIndex ?? 0 - return { - id: published.id, + + // Map category to new system + const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research' + + // Generate hash ID from series data + const hashId = await generateSeriesHashId({ + pubkey: params.authorPubkey, + title: params.title, + description: params.description, + category: newCategory, + coverUrl: params.coverUrl ?? undefined, + }) + + const hash = hashId + const version = 0 + const index = 0 + const id = buildObjectId(hash, index, version) + + // Build parsed Series object + const parsedSeries: Series = { + id, hash, version, index, @@ -84,6 +184,46 @@ export async function publishSeries(params: { ...(params.coverUrl ? { coverUrl: params.coverUrl } : {}), kindType: 'series', } + + // Build event template + const eventTemplate = await buildSeriesEvent(params, category) + + // Set private key in orchestrator + const privateKey = params.authorPrivateKey ?? nostrService.getPrivateKey() + if (!privateKey) { + throw new Error('Private key required for signing') + } + writeOrchestrator.setPrivateKey(privateKey) + + // Finalize event + const secretKey = hexToBytes(privateKey) + const event = finalizeEvent(eventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'series', + hash, + event, + parsed: parsedSeries, + version, + hidden: false, + index, + }, + relays + ) + + if (!result.success) { + throw new Error('Failed to publish series') + } + + return parsedSeries } async function buildSeriesEvent( @@ -166,18 +306,28 @@ export async function publishReview(params: { ensureKeys(params.reviewerPubkey, params.authorPrivateKey) const {category} = params requireCategory(category) - const event = await buildReviewEvent(params, category) - const published = await nostrService.publishEvent(event) - if (!published) { - throw new Error('Failed to publish review') - } - const parsed = parseObjectId(published.id) - const {hash: parsedHash, version: parsedVersion, index: parsedIndex} = parsed - const hash = parsedHash ?? published.id - const version = parsedVersion ?? 0 - const index = parsedIndex ?? 0 - return { - id: published.id, + + // Map category to new system + const newCategory = category === 'science-fiction' ? 'sciencefiction' : 'research' + + // Generate hash ID from review data + const { generateReviewHashId } = await import('./hashIdGenerator') + const hashId = await generateReviewHashId({ + pubkey: params.reviewerPubkey, + articleId: params.articleId, + reviewerPubkey: params.reviewerPubkey, + content: params.content, + ...(params.title ? { title: params.title } : {}), + }) + + const hash = hashId + const version = 0 + const index = 0 + const id = buildObjectId(hash, index, version) + + // Build parsed Review object + const parsedReview: Review = { + id, hash, version, index, @@ -186,11 +336,51 @@ export async function publishReview(params: { reviewerPubkey: params.reviewerPubkey, content: params.content, description: params.content.substring(0, 200), - createdAt: published.created_at, + createdAt: Math.floor(Date.now() / 1000), ...(params.title ? { title: params.title } : {}), ...(params.text ? { text: params.text } : {}), kindType: 'review', } + + // Build event template + const eventTemplate = await buildReviewEvent(params, category) + + // Set private key in orchestrator + const privateKey = params.authorPrivateKey ?? nostrService.getPrivateKey() + if (!privateKey) { + throw new Error('Private key required for signing') + } + writeOrchestrator.setPrivateKey(privateKey) + + // Finalize event + const secretKey = hexToBytes(privateKey) + const event = finalizeEvent(eventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'review', + hash, + event, + parsed: parsedReview, + version, + hidden: false, + index, + }, + relays + ) + + if (!result.success) { + throw new Error('Failed to publish review') + } + + return parsedReview } async function buildReviewEvent( diff --git a/lib/articlePublisherPublish.ts b/lib/articlePublisherPublish.ts index dd97a57..e14f9d6 100644 --- a/lib/articlePublisherPublish.ts +++ b/lib/articlePublisherPublish.ts @@ -5,6 +5,12 @@ import { createArticleInvoice, createPreviewEvent } from './articleInvoice' import { encryptArticleContent, encryptDecryptionKey } from './articleEncryption' import { storePrivateContent } from './articleStorage' import type { PublishResult } from './publishResult' +import { writeOrchestrator } from './writeOrchestrator' +import { finalizeEvent } from 'nostr-tools' +import { hexToBytes } from 'nostr-tools/utils' +import { generatePublicationHashId } from './hashIdGenerator' +import { buildObjectId } from './urlGenerator' +import type { Article } from '@/types/nostr' export function buildFailure(error?: string): PublishedArticle { const base: PublishedArticle = { @@ -15,6 +21,55 @@ export function buildFailure(error?: string): PublishedArticle { return error ? { ...base, error } : base } +async function buildParsedArticleFromDraft( + draft: ArticleDraft, + invoice: AlbyInvoice, + authorPubkey: string +): Promise<{ article: Article; hash: string; version: number; index: number }> { + const category = draft.category === 'science-fiction' ? 'sciencefiction' : draft.category === 'scientific-research' ? 'research' : 'sciencefiction' + + const hashId = await generatePublicationHashId({ + pubkey: authorPubkey, + title: draft.title, + preview: draft.preview, + category, + seriesId: draft.seriesId ?? undefined, + bannerUrl: draft.bannerUrl ?? undefined, + zapAmount: draft.zapAmount, + }) + + const hash = hashId + const version = 0 + const index = 0 + const id = buildObjectId(hash, index, version) + + const article: Article = { + id, + hash, + version, + index, + pubkey: authorPubkey, + title: draft.title, + preview: draft.preview, + content: '', + description: draft.preview, + contentDescription: draft.preview, + createdAt: Math.floor(Date.now() / 1000), + zapAmount: draft.zapAmount, + paid: false, + thumbnailUrl: draft.bannerUrl ?? '', + invoice: invoice.invoice, + paymentHash: invoice.paymentHash ?? undefined, + category: draft.category, + ...(draft.seriesId ? { seriesId: draft.seriesId } : {}), + ...(draft.bannerUrl ? { bannerUrl: draft.bannerUrl } : {}), + ...(draft.pages && draft.pages.length > 0 ? { pages: draft.pages } : {}), + kindType: 'article', + } + + return { article, hash, version, index } +} + export async function publishPreview( draft: ArticleDraft, invoice: AlbyInvoice, @@ -25,12 +80,64 @@ export async function publishPreview( encryptedKey?: string, returnStatus?: boolean ): Promise { - const previewEvent = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags, encryptedContent, encryptedKey) - if (returnStatus) { - return await nostrService.publishEvent(previewEvent, true) + // Build parsed article object + const { article, hash, version, index } = await buildParsedArticleFromDraft(draft, invoice, authorPubkey) + + // Build event template + const previewEventTemplate = await createPreviewEvent(draft, invoice, authorPubkey, presentationId, extraTags, encryptedContent, encryptedKey) + + // Set private key in orchestrator + const privateKey = nostrService.getPrivateKey() + if (!privateKey) { + throw new Error('Private key required for signing') } - const publishedEvent = await nostrService.publishEvent(previewEvent, false) - return publishedEvent ?? null + writeOrchestrator.setPrivateKey(privateKey) + + // Finalize event + const secretKey = hexToBytes(privateKey) + const event = finalizeEvent(previewEventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'publication', + hash, + event, + parsed: article, + version, + hidden: false, + index, + }, + relays + ) + + if (!result.success) { + return null + } + + if (returnStatus) { + // Return PublishResult format + const { publishResult } = await import('./publishResult') + return { + event, + relayStatuses: relays.map((relayUrl, idx) => { + const isSuccess = typeof result.published === 'object' && result.published.includes(relayUrl) + return { + relayUrl, + success: isSuccess, + error: isSuccess ? undefined : 'Failed to publish', + } + }), + } + } + + return event } export function buildArticleExtraTags(draft: ArticleDraft, _category: NonNullable): string[][] { diff --git a/lib/notificationDetector.ts b/lib/notificationDetector.ts index bcce03f..3a8c73e 100644 --- a/lib/notificationDetector.ts +++ b/lib/notificationDetector.ts @@ -241,7 +241,7 @@ class NotificationDetector { /** * Get notification title based on type */ - private getNotificationTitle(type: NotificationType, _obj: CachedObject): string { + private _getNotificationTitle(type: NotificationType, _obj: CachedObject): string { switch (type) { case 'purchase': return 'Nouvel achat' @@ -263,7 +263,7 @@ class NotificationDetector { /** * Get notification message based on type */ - private getNotificationMessage(type: NotificationType, _obj: CachedObject): string { + private _getNotificationMessage(type: NotificationType, _obj: CachedObject): string { switch (type) { case 'purchase': return `Vous avez acheté un article` diff --git a/lib/paymentNotes.ts b/lib/paymentNotes.ts index 3453215..148a08b 100644 --- a/lib/paymentNotes.ts +++ b/lib/paymentNotes.ts @@ -150,6 +150,24 @@ export async function publishReviewTipNote(params: { tags.push(['json', paymentJson]) + // Build parsed ReviewTip object + const parsedReviewTip: ReviewTip = { + id, + hash: hashId, + version: 0, + index: 0, + payerPubkey: params.payerPubkey, + articleId: params.articleId, + reviewId: params.reviewId, + reviewerPubkey: params.reviewerPubkey, + authorPubkey: params.authorPubkey, + amount: params.amount, + paymentHash: params.paymentHash, + createdAt: Math.floor(Date.now() / 1000), + ...(params.text ? { text: params.text } : {}), + kindType: 'review_tip', + } + const content = params.text ? `Review tip confirmed: ${params.amount} sats for review ${params.reviewId}\n\n${params.text}` : `Review tip confirmed: ${params.amount} sats for review ${params.reviewId}` @@ -162,7 +180,37 @@ export async function publishReviewTipNote(params: { } nostrService.setPrivateKey(params.payerPrivateKey) - return nostrService.publishEvent(eventTemplate) + writeOrchestrator.setPrivateKey(params.payerPrivateKey) + + // Finalize event + const secretKey = hexToBytes(params.payerPrivateKey) + const event = finalizeEvent(eventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'review_tip', + hash: hashId, + event, + parsed: parsedReviewTip, + version: 0, + hidden: false, + index: 0, + }, + relays + ) + + if (!result.success) { + return null + } + + return event } /** @@ -237,6 +285,23 @@ export async function publishSponsoringNote(params: { tags.push(['json', paymentJson]) + // Build parsed Sponsoring object + const parsedSponsoring: Sponsoring = { + id, + hash: hashId, + version: 0, + index: 0, + payerPubkey: params.payerPubkey, + authorPubkey: params.authorPubkey, + amount: params.amount, + paymentHash: params.paymentHash, + createdAt: Math.floor(Date.now() / 1000), + ...(params.seriesId ? { seriesId: params.seriesId } : {}), + ...(params.articleId ? { articleId: params.articleId } : {}), + ...(params.text ? { text: params.text } : {}), + kindType: 'sponsoring', + } + const content = params.text ? `Sponsoring confirmed: ${params.amount} sats for author ${params.authorPubkey.substring(0, 16)}...\n\n${params.text}` : `Sponsoring confirmed: ${params.amount} sats for author ${params.authorPubkey.substring(0, 16)}...` @@ -249,5 +314,35 @@ export async function publishSponsoringNote(params: { } nostrService.setPrivateKey(params.payerPrivateKey) - return nostrService.publishEvent(eventTemplate) + writeOrchestrator.setPrivateKey(params.payerPrivateKey) + + // Finalize event + const secretKey = hexToBytes(params.payerPrivateKey) + const event = finalizeEvent(eventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'sponsoring', + hash: hashId, + event, + parsed: parsedSponsoring, + version: 0, + hidden: false, + index: 0, + }, + relays + ) + + if (!result.success) { + return null + } + + return event } diff --git a/lib/platformTracking.ts b/lib/platformTracking.ts index bd35b69..c9c5f8d 100644 --- a/lib/platformTracking.ts +++ b/lib/platformTracking.ts @@ -141,8 +141,9 @@ export class PlatformTrackingService { }) // Listen for EOSE via Service Worker messages - const handleEOSE = (data: { relays: string[] }): void => { - if (data.relays.includes(relayUrl) && !eoseReceived) { + const handleEOSE = (data: unknown): void => { + const eoseData = data as { relays: string[] } + if (eoseData.relays.includes(relayUrl) && !eoseReceived) { eoseReceived = true finalize() } @@ -214,8 +215,9 @@ export class PlatformTrackingService { }) // Listen for EOSE via Service Worker messages - const handleEOSE = (data: { relays: string[] }): void => { - if (data.relays.includes(relayUrl) && !eoseReceived) { + const handleEOSE = (data: unknown): void => { + const eoseData = data as { relays: string[] } + if (eoseData.relays.includes(relayUrl) && !eoseReceived) { eoseReceived = true finalize() } diff --git a/lib/reviewRewardUpdate.ts b/lib/reviewRewardUpdate.ts index 72efdc6..f9e4c12 100644 --- a/lib/reviewRewardUpdate.ts +++ b/lib/reviewRewardUpdate.ts @@ -1,44 +1,21 @@ import { nostrService } from './nostr' import { PLATFORM_COMMISSIONS } from './platformCommissions' import type { Event } from 'nostr-tools' +import { objectCache } from './objectCache' export async function fetchOriginalReviewEvent(reviewId: string): Promise { - const pool = nostrService.getPool() - if (!pool) { - throw new Error('Pool not initialized') + // Read only from IndexedDB cache + const parsed = await objectCache.getById('review', reviewId) + if (parsed) { + // Get the event from cache + const event = await objectCache.getEventById('review', reviewId) + if (event) { + return event + } } - const { getPrimaryRelaySync } = await import('./config') - const { createSubscription } = await import('@/types/nostr-tools-extended') - const relayUrl = getPrimaryRelaySync() - const filters = [ - { - kinds: [1], - ids: [reviewId], - limit: 1, - }, - ] - - return new Promise((resolve) => { - let resolved = false - const sub = createSubscription(pool, [relayUrl], filters) - - const finalize = (value: Event | null): void => { - if (resolved) { - return - } - resolved = true - sub.unsub() - resolve(value) - } - - sub.on('event', (event: Event) => { - finalize(event) - }) - - sub.on('eose', () => finalize(null)) - setTimeout(() => finalize(null), 5000) - }) + // Not found in cache - return null (no network request) + return null } export function buildRewardEvent(originalEvent: Event, reviewId: string): { @@ -72,7 +49,7 @@ export function checkIfAlreadyRewarded(originalEvent: Event, reviewId: string): } export async function publishRewardEvent( - updatedEvent: { + updatedEventTemplate: { kind: number created_at: number tags: string[][] @@ -80,16 +57,82 @@ export async function publishRewardEvent( }, reviewId: string ): Promise { - const publishedEvent = await nostrService.publishEvent(updatedEvent) - if (publishedEvent) { - console.warn('Review updated with reward tag', { - reviewId, - updatedEventId: publishedEvent.id, - timestamp: new Date().toISOString(), - }) - } else { - console.error('Failed to publish updated review event', { + try { + // Get original review to extract hash and parsed data + const originalEvent = await fetchOriginalReviewEvent(reviewId) + if (!originalEvent) { + throw new Error('Original review event not found in cache') + } + + const { parseReviewFromEvent } = await import('./nostrEventParsing') + const originalParsed = await parseReviewFromEvent(originalEvent) + if (!originalParsed) { + throw new Error('Failed to parse original review') + } + + // Increment version for update + const newVersion = (originalParsed.version ?? 0) + 1 + const {hash} = originalParsed + const index = originalParsed.index ?? 0 + + // Build updated parsed Review object + const updatedParsed = { + ...originalParsed, + version: newVersion, + rewarded: true, + rewardAmount: PLATFORM_COMMISSIONS.review.total, + } + + // Set private key in orchestrator + const privateKey = nostrService.getPrivateKey() + if (!privateKey) { + throw new Error('Private key required for signing') + } + const { writeOrchestrator } = await import('./writeOrchestrator') + writeOrchestrator.setPrivateKey(privateKey) + + // Finalize event + const { finalizeEvent } = await import('nostr-tools') + const { hexToBytes } = await import('nostr-tools/utils') + const secretKey = hexToBytes(privateKey) + const event = finalizeEvent(updatedEventTemplate, secretKey) + + // Get active relays + const { relaySessionManager } = await import('./relaySessionManager') + const activeRelays = await relaySessionManager.getActiveRelays() + const { getPrimaryRelay } = await import('./config') + const relays = activeRelays.length > 0 ? activeRelays : [await getPrimaryRelay()] + + // Publish via writeOrchestrator (parallel network + local write) + const result = await writeOrchestrator.writeAndPublish( + { + objectType: 'review', + hash, + event, + parsed: updatedParsed, + version: newVersion, + hidden: false, + index, + }, + relays + ) + + if (result.success) { + console.warn('Review updated with reward tag', { + reviewId, + updatedEventId: event.id, + timestamp: new Date().toISOString(), + }) + } else { + console.error('Failed to publish updated review event', { + reviewId, + timestamp: new Date().toISOString(), + }) + } + } catch (error) { + console.error('Error publishing reward event', { reviewId, + error: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }) } diff --git a/lib/websocketService.ts b/lib/websocketService.ts index 66ab131..b8d3b6c 100644 --- a/lib/websocketService.ts +++ b/lib/websocketService.ts @@ -8,7 +8,7 @@ import { SimplePool } from 'nostr-tools' import { swClient } from './swClient' -import type { Event } from 'nostr-tools' +import type { Event, Filter } from 'nostr-tools' interface ConnectionState { relayUrl: string @@ -220,8 +220,9 @@ class WebSocketService { this.updateConnectionState(relayUrl, true) // Assume connected when subscribing }) - // Create subscription - const sub = this.pool.subscribe(relays, filters, { + // Create subscription - use first filter or empty filter + const filter: Filter = (filters[0] as Filter) ?? {} + const sub = this.pool.subscribe(relays, filter, { onevent: (event: Event): void => { // Notify Service Worker of new event via postMessage void swClient.sendMessage({ @@ -261,7 +262,7 @@ class WebSocketService { } // Update all connection states - this.connectionStates.forEach((state, relayUrl) => { + this.connectionStates.forEach((_state, relayUrl) => { this.updateConnectionState(relayUrl, false) }) diff --git a/lib/writeOrchestrator.ts b/lib/writeOrchestrator.ts index e87c72a..7d0a4db 100644 --- a/lib/writeOrchestrator.ts +++ b/lib/writeOrchestrator.ts @@ -42,7 +42,7 @@ class WriteOrchestrator { params: WriteObjectParams, relays: string[] ): Promise<{ success: boolean; eventId: string; published: false | string[] }> { - const { objectType, hash, event, parsed, version, hidden, index, published = false } = params + const { objectType, hash, event, parsed, version, hidden, index } = params // Écriture en parallèle : réseau et local indépendamment const [networkResult, localResult] = await Promise.allSettled([ @@ -117,7 +117,7 @@ class WriteOrchestrator { parsed, version, hidden, - index, + ...(index !== undefined ? { index } : {}), }, relays ) diff --git a/lib/writeService.ts b/lib/writeService.ts index a193ff5..84f5b7a 100644 --- a/lib/writeService.ts +++ b/lib/writeService.ts @@ -34,7 +34,7 @@ class WriteService { } private createWorker(): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve, _reject) => { if (typeof window === 'undefined' || !window.Worker) { // Fallback: write directly if Worker not available console.warn('[WriteService] Web Workers not available, using direct writes') @@ -240,8 +240,8 @@ class WriteService { } // Fallback: direct write const { notificationService } = await import('./notificationService') - await notificationService.createNotificationDirect( - type as Parameters[0], + await notificationService.createNotification({ + type: type as Parameters[0]['type'], objectType, objectId, eventId, diff --git a/pages/author/[pubkey].tsx b/pages/author/[pubkey].tsx index 2b8479d..e8da04a 100644 --- a/pages/author/[pubkey].tsx +++ b/pages/author/[pubkey].tsx @@ -297,7 +297,7 @@ export default function AuthorPage(): React.ReactElement { const { presentation, series, totalSponsoring, loading, error, reload } = useAuthorData(hashIdOrPubkey ?? '') if (!hashIdOrPubkey) { - return null + return
} // Get the actual pubkey from presentation