Browse Source

keep relay status out of published events

imwald
Silberengel 4 months ago
parent
commit
ca002f14ab
  1. 5
      src/components/PostEditor/PostContent.tsx
  2. 33
      src/providers/NostrProvider/index.tsx
  3. 14
      src/services/client.service.ts
  4. 32
      src/services/indexed-db.service.ts

5
src/components/PostEditor/PostContent.tsx

@ -320,7 +320,10 @@ export default function PostContent({ @@ -320,7 +320,10 @@ export default function PostContent({
// Full success - clean up and close
postEditorCache.clearPostCache({ defaultContent, parentEvent })
deleteDraftEventCache(draftEvent)
addReplies([newEvent])
// Remove relayStatuses before storing the event (it's only for UI feedback)
const cleanEvent = { ...newEvent }
delete (cleanEvent as any).relayStatuses
addReplies([cleanEvent])
close()
} catch (error) {
console.error('Publishing error:', error)

33
src/providers/NostrProvider/index.tsx

@ -830,10 +830,9 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { @@ -830,10 +830,9 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
try {
const publishResult = await client.publishEvent(relays, event)
// Store relay status for display
if (publishResult.relayStatuses.length > 0) {
(event as any).relayStatuses = publishResult.relayStatuses
}
// Store relay status temporarily for display (but don't persist it on the event)
// This metadata is only for logging/feedback, not part of the actual event
const relayStatuses = publishResult.relayStatuses.length > 0 ? publishResult.relayStatuses : undefined
// If publishing failed completely, throw an error so the form doesn't close
if (!publishResult.success) {
@ -847,15 +846,35 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { @@ -847,15 +846,35 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
throw error
}
// Attach relayStatuses only temporarily for UI feedback, then remove it
// This prevents it from being included in the event when serialized
if (relayStatuses) {
(event as any).relayStatuses = relayStatuses
// Remove it immediately after return so it's not persisted
// The components that need it will read it synchronously
setTimeout(() => {
delete (event as any).relayStatuses
}, 0)
}
return event
} catch (error) {
// Check for authentication-related errors
if (error instanceof AggregateError && (error as any).relayStatuses) {
(event as any).relayStatuses = (error as any).relayStatuses
// Attach relayStatuses temporarily for UI feedback
const errorRelayStatuses = (error as any).relayStatuses as Array<{ url: string; success: boolean; error?: string }>
// Attach to event temporarily for UI feedback
(event as any).relayStatuses = errorRelayStatuses
// Remove it after a brief delay to allow UI components to read it
setTimeout(() => {
delete (event as any).relayStatuses
}, 100)
// Check if any relay returned an "invalid key" error
const invalidKeyErrors = (error as any).relayStatuses.filter(
(status: any) => status.error && status.error.includes('invalid key')
const invalidKeyErrors = errorRelayStatuses.filter(
(status) => status.error && status.error.includes('invalid key')
)
if (invalidKeyErrors.length > 0) {

14
src/services/client.service.ts

@ -901,12 +901,16 @@ class ClientService extends EventTarget { @@ -901,12 +901,16 @@ class ClientService extends EventTarget {
}
addEventToCache(event: NEvent) {
this.eventDataLoader.prime(event.id, Promise.resolve(event))
if (isReplaceableEvent(event.kind)) {
const coordinate = getReplaceableCoordinateFromEvent(event)
// Remove relayStatuses before caching (it's metadata for logging, not part of the event)
const cleanEvent = { ...event } as NEvent
delete (cleanEvent as any).relayStatuses
this.eventDataLoader.prime(cleanEvent.id, Promise.resolve(cleanEvent))
if (isReplaceableEvent(cleanEvent.kind)) {
const coordinate = getReplaceableCoordinateFromEvent(cleanEvent)
const cachedEvent = this.replaceableEventCacheMap.get(coordinate)
if (!cachedEvent || compareEvents(event, cachedEvent) > 0) {
this.replaceableEventCacheMap.set(coordinate, event)
if (!cachedEvent || compareEvents(cleanEvent, cachedEvent) > 0) {
this.replaceableEventCacheMap.set(coordinate, cleanEvent)
}
}
}

32
src/services/indexed-db.service.ts

@ -167,7 +167,11 @@ class IndexedDbService { @@ -167,7 +167,11 @@ class IndexedDbService {
}
async putReplaceableEvent(event: Event): Promise<Event> {
const storeName = this.getStoreNameByKind(event.kind)
// Remove relayStatuses before storing (it's metadata for logging, not part of the event)
const cleanEvent = { ...event }
delete (cleanEvent as any).relayStatuses
const storeName = this.getStoreNameByKind(cleanEvent.kind)
if (!storeName) {
return Promise.reject('store name not found')
}
@ -191,23 +195,23 @@ class IndexedDbService { @@ -191,23 +195,23 @@ class IndexedDbService {
if (!this.db.objectStoreNames.contains(storeName)) {
console.warn(`Store ${storeName} not found in database. Cannot save event.`)
// Return the event anyway (don't reject) - caching is optional
return resolve(event)
return resolve(cleanEvent)
}
const transaction = this.db.transaction(storeName, 'readwrite')
const store = transaction.objectStore(storeName)
const key = this.getReplaceableEventKeyFromEvent(event)
const key = this.getReplaceableEventKeyFromEvent(cleanEvent)
const getRequest = store.get(key)
getRequest.onsuccess = () => {
const oldValue = getRequest.result as TValue<Event> | undefined
if (oldValue?.value && oldValue.value.created_at >= event.created_at) {
if (oldValue?.value && oldValue.value.created_at >= cleanEvent.created_at) {
transaction.commit()
return resolve(oldValue.value)
}
const putRequest = store.put(this.formatValue(key, event))
const putRequest = store.put(this.formatValue(key, cleanEvent))
putRequest.onsuccess = () => {
transaction.commit()
resolve(event)
resolve(cleanEvent)
}
putRequest.onerror = (event) => {
@ -541,7 +545,11 @@ class IndexedDbService { @@ -541,7 +545,11 @@ class IndexedDbService {
}
private async putReplaceableEventWithMaster(event: Event, masterKey: string): Promise<Event> {
const storeName = this.getStoreNameByKind(event.kind)
// Remove relayStatuses before storing (it's metadata for logging, not part of the event)
const cleanEvent = { ...event }
delete (cleanEvent as any).relayStatuses
const storeName = this.getStoreNameByKind(cleanEvent.kind)
if (!storeName) {
return Promise.reject('store name not found')
}
@ -562,16 +570,16 @@ class IndexedDbService { @@ -562,16 +570,16 @@ class IndexedDbService {
}
if (!this.db.objectStoreNames.contains(storeName)) {
console.warn(`Store ${storeName} not found in database. Cannot save event.`)
return resolve(event)
return resolve(cleanEvent)
}
const transaction = this.db.transaction(storeName, 'readwrite')
const store = transaction.objectStore(storeName)
const key = this.getReplaceableEventKeyFromEvent(event)
const key = this.getReplaceableEventKeyFromEvent(cleanEvent)
const getRequest = store.get(key)
getRequest.onsuccess = () => {
const oldValue = getRequest.result as TValue<Event> | undefined
if (oldValue?.value && oldValue.value.created_at >= event.created_at) {
if (oldValue?.value && oldValue.value.created_at >= cleanEvent.created_at) {
// Update master key link even if event is not newer
if (oldValue.masterPublicationKey !== masterKey) {
const value = this.formatValue(key, oldValue.value)
@ -582,12 +590,12 @@ class IndexedDbService { @@ -582,12 +590,12 @@ class IndexedDbService {
return resolve(oldValue.value)
}
// Store with master key link
const value = this.formatValue(key, event)
const value = this.formatValue(key, cleanEvent)
value.masterPublicationKey = masterKey
const putRequest = store.put(value)
putRequest.onsuccess = () => {
transaction.commit()
resolve(event)
resolve(cleanEvent)
}
putRequest.onerror = (event) => {

Loading…
Cancel
Save