refactor: consolidate NIP-29 chat and nutzap into single REQ

- Use single filter with kinds [9, 9000, 9001, 9321] instead of
  separate subscriptions with combineLatest
- Enables proper pagination for "load older" with single page fetches
- Add rounded corners to zap gradient border for consistent rendering
This commit is contained in:
Claude
2026-01-12 14:12:02 +00:00
parent b0321fce8f
commit f69f5cac2f
2 changed files with 25 additions and 55 deletions

View File

@@ -191,13 +191,13 @@ const MessageItem = memo(function MessageItem({
return (
<div className="pl-2 mb-1">
<div
className="p-[1px]"
className="p-[1px] rounded"
style={{
background:
"linear-gradient(to right, rgb(250 204 21), rgb(251 146 60), rgb(168 85 247), rgb(34 211 238))",
}}
>
<div className="bg-background px-1">
<div className="bg-background px-1 rounded-sm">
<div className="flex items-center gap-2">
<UserName
pubkey={message.author}

View File

@@ -1,4 +1,4 @@
import { Observable, combineLatest } from "rxjs";
import { Observable } from "rxjs";
import { map, first } from "rxjs/operators";
import type { Filter } from "nostr-tools";
import { nip19 } from "nostr-tools";
@@ -312,85 +312,55 @@ export class Nip29Adapter extends ChatProtocolAdapter {
console.log(`[NIP-29] Loading messages for ${groupId} from ${relayUrl}`);
// Subscribe to group messages (kind 9) and admin events (9000-9022)
// Single filter for all group events:
// kind 9: chat messages
// kind 9000: put-user (admin adds user)
// kind 9001: remove-user (admin removes user)
const chatFilter: Filter = {
kinds: [9, 9000, 9001],
"#h": [groupId],
limit: options?.limit || 50,
};
// Filter for nutzaps (kind 9321) targeting this group
const nutzapFilter: Filter = {
kinds: [9321],
// kind 9321: nutzaps (NIP-61)
const filter: Filter = {
kinds: [9, 9000, 9001, 9321],
"#h": [groupId],
limit: options?.limit || 50,
};
if (options?.before) {
chatFilter.until = options.before;
nutzapFilter.until = options.before;
filter.until = options.before;
}
if (options?.after) {
chatFilter.since = options.after;
nutzapFilter.since = options.after;
filter.since = options.after;
}
// Start persistent subscriptions for both chat and nutzaps
// Start a persistent subscription to the group relay
pool
.subscription([relayUrl], [chatFilter], {
.subscription([relayUrl], [filter], {
eventStore,
})
.subscribe({
next: (response) => {
if (typeof response === "string") {
console.log("[NIP-29] EOSE received for messages");
console.log("[NIP-29] EOSE received");
} else {
console.log(
`[NIP-29] Received message: ${response.id.slice(0, 8)}...`,
`[NIP-29] Received event k${response.kind}: ${response.id.slice(0, 8)}...`,
);
}
},
});
pool
.subscription([relayUrl], [nutzapFilter], {
eventStore,
})
.subscribe({
next: (response) => {
if (typeof response === "string") {
console.log("[NIP-29] EOSE received for nutzaps");
} else {
console.log(
`[NIP-29] Received nutzap: ${response.id.slice(0, 8)}...`,
);
// Return observable from EventStore which will update automatically
return eventStore.timeline(filter).pipe(
map((events) => {
const messages = events.map((event) => {
// Convert nutzaps (kind 9321) using nutzapToMessage
if (event.kind === 9321) {
return this.nutzapToMessage(event, conversation.id);
}
},
});
// All other events use eventToMessage
return this.eventToMessage(event, conversation.id);
});
// Combine chat messages and nutzaps from EventStore
const chatMessages$ = eventStore.timeline(chatFilter);
const nutzapMessages$ = eventStore.timeline(nutzapFilter);
return combineLatest([chatMessages$, nutzapMessages$]).pipe(
map(([chatEvents, nutzapEvents]) => {
const chatMsgs = chatEvents.map((event) =>
this.eventToMessage(event, conversation.id),
);
const nutzapMsgs = nutzapEvents.map((event) =>
this.nutzapToMessage(event, conversation.id),
);
const allMessages = [...chatMsgs, ...nutzapMsgs];
console.log(
`[NIP-29] Timeline has ${chatMsgs.length} messages, ${nutzapMsgs.length} nutzaps`,
);
return allMessages.sort((a, b) => a.timestamp - b.timestamp);
console.log(`[NIP-29] Timeline has ${messages.length} events`);
return messages.sort((a, b) => a.timestamp - b.timestamp);
}),
);
}