mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-10 15:36:53 +02:00
fix: buffer NIP-29 messages until EOSE to prevent partial renders
The loadMessages observable was emitting on every event as they streamed in before EOSE, causing multiple re-renders with partial message lists. This resulted in incorrect scroll positions during initial chat load. Now uses combineLatest with a BehaviorSubject to track EOSE state and only emits the message list after the initial batch is fully loaded. New messages after EOSE continue to trigger immediate updates. https://claude.ai/code/session_0174r1Ddh5e2RuhHf2ZrFiNc
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
import { Observable, firstValueFrom } from "rxjs";
|
||||
import { map, first, toArray } from "rxjs/operators";
|
||||
import {
|
||||
Observable,
|
||||
firstValueFrom,
|
||||
BehaviorSubject,
|
||||
combineLatest,
|
||||
} from "rxjs";
|
||||
import { map, first, toArray, filter as filterOp } from "rxjs/operators";
|
||||
import type { Filter } from "nostr-tools";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import type { EventPointer, AddressPointer } from "nostr-tools/nip19";
|
||||
@@ -332,6 +337,9 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
const conversationId = `nip-29:${relayUrl}'${groupId}`;
|
||||
this.cleanup(conversationId);
|
||||
|
||||
// Track EOSE state - don't emit until initial batch is loaded
|
||||
const eoseReceived$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
// Start a persistent subscription to the group relay
|
||||
const subscription = pool
|
||||
.subscription([relayUrl], [filter], {
|
||||
@@ -341,6 +349,7 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
next: (response) => {
|
||||
if (typeof response === "string") {
|
||||
console.log("[NIP-29] EOSE received");
|
||||
eoseReceived$.next(true);
|
||||
} else {
|
||||
console.log(
|
||||
`[NIP-29] Received event k${response.kind}: ${response.id.slice(0, 8)}...`,
|
||||
@@ -352,9 +361,10 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
// Store subscription for cleanup
|
||||
this.subscriptions.set(conversationId, subscription);
|
||||
|
||||
// Return observable from EventStore which will update automatically
|
||||
return eventStore.timeline(filter).pipe(
|
||||
map((events) => {
|
||||
// Return observable that only emits after EOSE (prevents partial renders during initial load)
|
||||
return combineLatest([eventStore.timeline(filter), eoseReceived$]).pipe(
|
||||
filterOp(([, eose]) => eose), // Only emit after EOSE received
|
||||
map(([events]) => {
|
||||
const messages = events.map((event) => {
|
||||
// Convert nutzaps (kind 9321) using nutzapToMessage
|
||||
if (event.kind === 9321) {
|
||||
|
||||
Reference in New Issue
Block a user