mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-09 23:16:50 +02:00
feat: wait for EOSE before rendering messages to prevent scroll jumping
Message Loading Improvements: - Use RxJS Subject to track EOSE (End Of Stored Events) - Use skipUntil operator to delay timeline emissions until EOSE received - Prevents scroll position jumping during initial message load - Messages still update reactively after initial EOSE NIP-29 Adapter: - Create eoseSubject to track EOSE state - Emit from subject when EOSE string received from relay subscription - Apply skipUntil(eoseSubject) to eventStore.timeline() observable NIP-C7 Adapter: - Add relay subscription to track EOSE (was missing) - Use same EOSE tracking pattern as NIP-29 - Apply skipUntil to prevent premature timeline emissions Benefits: - Smooth initial load experience without scroll jumping - All messages appear together after EOSE - Maintains reactive updates for new messages - Consistent behavior across both chat protocols Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Observable } from "rxjs";
|
||||
import { map, first } from "rxjs/operators";
|
||||
import { Observable, Subject } from "rxjs";
|
||||
import { map, first, skipUntil } from "rxjs/operators";
|
||||
import type { Filter } from "nostr-tools";
|
||||
import { ChatProtocolAdapter } from "./base-adapter";
|
||||
import type {
|
||||
@@ -292,6 +292,9 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
filter.since = options.after;
|
||||
}
|
||||
|
||||
// Create a subject to track EOSE
|
||||
const eoseSubject = new Subject<void>();
|
||||
|
||||
// Start a persistent subscription to the group relay
|
||||
// This will feed new messages into the EventStore in real-time
|
||||
pool
|
||||
@@ -303,6 +306,8 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
if (typeof response === "string") {
|
||||
// EOSE received
|
||||
console.log("[NIP-29] EOSE received for messages");
|
||||
eoseSubject.next();
|
||||
eoseSubject.complete();
|
||||
} else {
|
||||
// Event received
|
||||
console.log(
|
||||
@@ -313,7 +318,9 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
});
|
||||
|
||||
// Return observable from EventStore which will update automatically
|
||||
// Wait for EOSE before emitting to prevent scroll jumping during initial load
|
||||
return eventStore.timeline(filter).pipe(
|
||||
skipUntil(eoseSubject),
|
||||
map((events) => {
|
||||
console.log(`[NIP-29] Timeline has ${events.length} messages`);
|
||||
return events
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Observable, firstValueFrom } from "rxjs";
|
||||
import { map, first } from "rxjs/operators";
|
||||
import { Observable, firstValueFrom, Subject } from "rxjs";
|
||||
import { map, first, skipUntil } from "rxjs/operators";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import type { Filter } from "nostr-tools";
|
||||
import { ChatProtocolAdapter } from "./base-adapter";
|
||||
@@ -156,15 +156,35 @@ export class NipC7Adapter extends ChatProtocolAdapter {
|
||||
filter.since = options.after;
|
||||
}
|
||||
|
||||
return eventStore
|
||||
.timeline(filter)
|
||||
.pipe(
|
||||
map((events) =>
|
||||
events
|
||||
.map((event) => this.eventToMessage(event, conversation.id))
|
||||
.sort((a, b) => a.timestamp - b.timestamp),
|
||||
),
|
||||
);
|
||||
// Create a subject to track EOSE
|
||||
const eoseSubject = new Subject<void>();
|
||||
|
||||
// Start subscription to populate EventStore and track EOSE
|
||||
pool
|
||||
.subscription([], [filter], {
|
||||
eventStore, // Automatically add to store
|
||||
})
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
if (typeof response === "string") {
|
||||
// EOSE received
|
||||
console.log("[NIP-C7] EOSE received for messages");
|
||||
eoseSubject.next();
|
||||
eoseSubject.complete();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Return observable from EventStore
|
||||
// Wait for EOSE before emitting to prevent scroll jumping during initial load
|
||||
return eventStore.timeline(filter).pipe(
|
||||
skipUntil(eoseSubject),
|
||||
map((events) =>
|
||||
events
|
||||
.map((event) => this.eventToMessage(event, conversation.id))
|
||||
.sort((a, b) => a.timestamp - b.timestamp),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user