mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-09 23:16:50 +02:00
refactor: add stronger types and optimize message sorting
- Add discriminated union types for ProtocolIdentifier (GroupIdentifier, LiveActivityIdentifier, DMIdentifier, NIP05Identifier, ChannelIdentifier) - Optimize message sorting using reverse() instead of full sort (O(n) vs O(n log n)) - Add type narrowing in adapter resolveConversation methods - Remove unused Observable import from ChatViewer
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useMemo, useState, memo, useCallback, useRef, useEffect } from "react";
|
||||
import { use$ } from "applesauce-react/hooks";
|
||||
import { from, catchError, of, map, Observable } from "rxjs";
|
||||
import { from, catchError, of, map } from "rxjs";
|
||||
import { Virtuoso, VirtuosoHandle } from "react-virtuoso";
|
||||
import { Loader2, Reply, Zap, AlertTriangle, RefreshCw } from "lucide-react";
|
||||
import { getZapRequest } from "applesauce-common/helpers/zap";
|
||||
|
||||
@@ -101,6 +101,12 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
async resolveConversation(
|
||||
identifier: ProtocolIdentifier,
|
||||
): Promise<Conversation> {
|
||||
// This adapter only handles group identifiers
|
||||
if (identifier.type !== "group") {
|
||||
throw new Error(
|
||||
`NIP-29 adapter cannot handle identifier type: ${identifier.type}`,
|
||||
);
|
||||
}
|
||||
const groupId = identifier.value;
|
||||
const relayUrl = identifier.relays?.[0];
|
||||
|
||||
@@ -367,7 +373,10 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
});
|
||||
|
||||
console.log(`[NIP-29] Timeline has ${messages.length} events`);
|
||||
return messages.sort((a, b) => a.timestamp - b.timestamp);
|
||||
// EventStore timeline returns events sorted by created_at desc,
|
||||
// we need ascending order for chat. Since it's already sorted,
|
||||
// just reverse instead of full sort (O(n) vs O(n log n))
|
||||
return messages.reverse();
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -413,7 +422,9 @@ export class Nip29Adapter extends ChatProtocolAdapter {
|
||||
return this.eventToMessage(event, conversation.id);
|
||||
});
|
||||
|
||||
return messages.sort((a, b) => a.timestamp - b.timestamp);
|
||||
// loadMoreMessages returns events in desc order from relay,
|
||||
// reverse for ascending chronological order
|
||||
return messages.reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,11 +84,13 @@ export class Nip53Adapter extends ChatProtocolAdapter {
|
||||
async resolveConversation(
|
||||
identifier: ProtocolIdentifier,
|
||||
): Promise<Conversation> {
|
||||
const { pubkey, identifier: dTag } = identifier.value as {
|
||||
kind: number;
|
||||
pubkey: string;
|
||||
identifier: string;
|
||||
};
|
||||
// This adapter only handles live-activity identifiers
|
||||
if (identifier.type !== "live-activity") {
|
||||
throw new Error(
|
||||
`NIP-53 adapter cannot handle identifier type: ${identifier.type}`,
|
||||
);
|
||||
}
|
||||
const { pubkey, identifier: dTag } = identifier.value;
|
||||
const relayHints = identifier.relays || [];
|
||||
|
||||
const activePubkey = accountManager.active$.value?.pubkey;
|
||||
@@ -311,7 +313,10 @@ export class Nip53Adapter extends ChatProtocolAdapter {
|
||||
.filter((msg): msg is Message => msg !== null);
|
||||
|
||||
console.log(`[NIP-53] Timeline has ${messages.length} events`);
|
||||
return messages.sort((a, b) => a.timestamp - b.timestamp);
|
||||
// EventStore timeline returns events sorted by created_at desc,
|
||||
// we need ascending order for chat. Since it's already sorted,
|
||||
// just reverse instead of full sort (O(n) vs O(n log n))
|
||||
return messages.reverse();
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -380,7 +385,9 @@ export class Nip53Adapter extends ChatProtocolAdapter {
|
||||
})
|
||||
.filter((msg): msg is Message => msg !== null);
|
||||
|
||||
return messages.sort((a, b) => a.timestamp - b.timestamp);
|
||||
// loadMoreMessages returns events in desc order from relay,
|
||||
// reverse for ascending chronological order
|
||||
return messages.reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -93,8 +93,15 @@ export class NipC7Adapter extends ChatProtocolAdapter {
|
||||
throw new Error(`Failed to resolve NIP-05: ${identifier.value}`);
|
||||
}
|
||||
pubkey = resolved;
|
||||
} else {
|
||||
} else if (
|
||||
identifier.type === "chat-partner" ||
|
||||
identifier.type === "dm-recipient"
|
||||
) {
|
||||
pubkey = identifier.value;
|
||||
} else {
|
||||
throw new Error(
|
||||
`NIP-C7 adapter cannot handle identifier type: ${identifier.type}`,
|
||||
);
|
||||
}
|
||||
|
||||
const activePubkey = accountManager.active$.value?.pubkey;
|
||||
|
||||
@@ -120,14 +120,74 @@ export interface Message {
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol-specific identifier
|
||||
* NIP-29 group identifier
|
||||
*/
|
||||
export interface GroupIdentifier {
|
||||
type: "group";
|
||||
/** Group ID (e.g., "bitcoin-dev") */
|
||||
value: string;
|
||||
/** Relay URL where the group is hosted (required for NIP-29) */
|
||||
relays: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-53 live activity identifier
|
||||
*/
|
||||
export interface LiveActivityIdentifier {
|
||||
type: "live-activity";
|
||||
/** Address pointer for the live activity */
|
||||
value: {
|
||||
kind: 30311;
|
||||
pubkey: string;
|
||||
identifier: string;
|
||||
};
|
||||
/** Relay hints from naddr encoding */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-C7/NIP-17 direct message identifier (resolved pubkey)
|
||||
*/
|
||||
export interface DMIdentifier {
|
||||
type: "dm-recipient" | "chat-partner";
|
||||
/** Recipient pubkey (hex) */
|
||||
value: string;
|
||||
/** Relay hints */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-C7 NIP-05 identifier (needs resolution)
|
||||
*/
|
||||
export interface NIP05Identifier {
|
||||
type: "chat-partner-nip05";
|
||||
/** NIP-05 address to resolve */
|
||||
value: string;
|
||||
/** Relay hints */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-28 channel identifier (future)
|
||||
*/
|
||||
export interface ChannelIdentifier {
|
||||
type: "channel";
|
||||
/** Channel creation event ID or address */
|
||||
value: string;
|
||||
/** Relay hints */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol-specific identifier - discriminated union
|
||||
* Returned by adapter parseIdentifier()
|
||||
*/
|
||||
export interface ProtocolIdentifier {
|
||||
type: string; // e.g., 'dm-recipient', 'channel-event', 'group-id'
|
||||
value: any; // Protocol-specific value
|
||||
relays?: string[]; // Relay hints from bech32 encoding
|
||||
}
|
||||
export type ProtocolIdentifier =
|
||||
| GroupIdentifier
|
||||
| LiveActivityIdentifier
|
||||
| DMIdentifier
|
||||
| NIP05Identifier
|
||||
| ChannelIdentifier;
|
||||
|
||||
/**
|
||||
* Chat command parsing result
|
||||
|
||||
Reference in New Issue
Block a user