mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-09 15:07:10 +02:00
Implement NIP-43 relay access metadata (#104)
* feat: add NIP-43 relay access metadata support Add feed and detail rendering for kind 13534 (Relay Members) events, and enable all NIP-43 kind constants for relay access management. - Add RelayMembersRenderer with feed and detail views - Enable kind constants: 13534, 28934, 28935, 28936 - Use Shield icon to represent relay access control - Extract members from NIP-43's "member" tags (not standard "p" tags) * feat: add renderers for NIP-43 Add/Remove User events - Change kind 13534 icon from Shield to Users for consistency - Add feed and detail renderers for kind 8000 (Add User) - Add feed and detail renderers for kind 8001 (Remove User) - Both show the affected pubkey using PubkeyListFull component * fix: show username in Add/Remove User feed renderers Display the actual username (via UserName component) in kind 8000/8001 feed views instead of just generic text. * refactor: simplify NIP-43 renderers to follow codebase patterns - Use PubkeyListPreview in RelayMembersRenderer feed view (shows actual users instead of just count, matching FollowSetRenderer pattern) - Remove redundant icon props from detail renderers (PubkeyListFull has sensible defaults) - Simplify variable naming and reduce comments - No functional changes, just cleaner code --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
67
src/components/nostr/kinds/RelayMembersRenderer.tsx
Normal file
67
src/components/nostr/kinds/RelayMembersRenderer.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Users } from "lucide-react";
|
||||
import { getTagValues } from "@/lib/nostr-utils";
|
||||
import {
|
||||
BaseEventProps,
|
||||
BaseEventContainer,
|
||||
ClickableEventTitle,
|
||||
} from "./BaseEventRenderer";
|
||||
import { PubkeyListPreview, PubkeyListFull } from "../lists";
|
||||
import type { NostrEvent } from "@/types/nostr";
|
||||
|
||||
/**
|
||||
* Kind 13534 Renderer - Relay Members (Feed View)
|
||||
* NIP-43 relay membership list using "member" tags
|
||||
*/
|
||||
export function RelayMembersRenderer({ event }: BaseEventProps) {
|
||||
const members = getTagValues(event, "member");
|
||||
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="flex items-center gap-1.5 text-sm font-medium"
|
||||
>
|
||||
<Users className="size-4 text-muted-foreground" />
|
||||
<span>Relay Members</span>
|
||||
</ClickableEventTitle>
|
||||
|
||||
{members.length === 0 ? (
|
||||
<div className="text-xs text-muted-foreground italic">
|
||||
Empty membership list
|
||||
</div>
|
||||
) : (
|
||||
<PubkeyListPreview
|
||||
pubkeys={members}
|
||||
previewLimit={3}
|
||||
label="members"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kind 13534 Detail View - Full relay membership list
|
||||
*/
|
||||
export function RelayMembersDetailRenderer({ event }: { event: NostrEvent }) {
|
||||
const members = getTagValues(event, "member");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Users className="size-6 text-muted-foreground" />
|
||||
<span className="text-lg font-semibold">Relay Members</span>
|
||||
</div>
|
||||
|
||||
{members.length > 0 ? (
|
||||
<PubkeyListFull pubkeys={members} label="Members" />
|
||||
) : (
|
||||
<div className="text-sm text-muted-foreground italic">
|
||||
Empty membership list
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
132
src/components/nostr/kinds/RelayUserChangeRenderer.tsx
Normal file
132
src/components/nostr/kinds/RelayUserChangeRenderer.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { UserPlus, UserMinus } from "lucide-react";
|
||||
import { getTagValue } from "applesauce-core/helpers";
|
||||
import {
|
||||
BaseEventProps,
|
||||
BaseEventContainer,
|
||||
ClickableEventTitle,
|
||||
} from "./BaseEventRenderer";
|
||||
import { PubkeyListFull } from "../lists";
|
||||
import { UserName } from "../UserName";
|
||||
import type { NostrEvent } from "@/types/nostr";
|
||||
|
||||
/**
|
||||
* Kind 8000 Renderer - Add User (Feed View)
|
||||
* NIP-43 event published when a member is added to a relay
|
||||
*/
|
||||
export function AddUserRenderer({ event }: BaseEventProps) {
|
||||
const pubkey = getTagValue(event, "p");
|
||||
|
||||
if (!pubkey) {
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="text-xs text-muted-foreground italic">
|
||||
Invalid event (missing pubkey)
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="flex items-center gap-1.5 text-sm font-medium"
|
||||
>
|
||||
<UserPlus className="size-4 text-muted-foreground" />
|
||||
<span>User Added</span>
|
||||
</ClickableEventTitle>
|
||||
|
||||
<div className="text-xs">
|
||||
<UserName pubkey={pubkey} className="text-xs" />
|
||||
<span className="text-muted-foreground"> added to relay</span>
|
||||
</div>
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kind 8000 Detail View
|
||||
*/
|
||||
export function AddUserDetailRenderer({ event }: { event: NostrEvent }) {
|
||||
const pubkey = getTagValue(event, "p");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserPlus className="size-6 text-muted-foreground" />
|
||||
<span className="text-lg font-semibold">User Added</span>
|
||||
</div>
|
||||
|
||||
{pubkey ? (
|
||||
<PubkeyListFull pubkeys={[pubkey]} label="Added Member" />
|
||||
) : (
|
||||
<div className="text-sm text-muted-foreground italic">
|
||||
Invalid event (missing pubkey)
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kind 8001 Renderer - Remove User (Feed View)
|
||||
* NIP-43 event published when a member is removed from a relay
|
||||
*/
|
||||
export function RemoveUserRenderer({ event }: BaseEventProps) {
|
||||
const pubkey = getTagValue(event, "p");
|
||||
|
||||
if (!pubkey) {
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="text-xs text-muted-foreground italic">
|
||||
Invalid event (missing pubkey)
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="flex items-center gap-1.5 text-sm font-medium"
|
||||
>
|
||||
<UserMinus className="size-4 text-muted-foreground" />
|
||||
<span>User Removed</span>
|
||||
</ClickableEventTitle>
|
||||
|
||||
<div className="text-xs">
|
||||
<UserName pubkey={pubkey} className="text-xs" />
|
||||
<span className="text-muted-foreground"> removed from relay</span>
|
||||
</div>
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kind 8001 Detail View
|
||||
*/
|
||||
export function RemoveUserDetailRenderer({ event }: { event: NostrEvent }) {
|
||||
const pubkey = getTagValue(event, "p");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserMinus className="size-6 text-muted-foreground" />
|
||||
<span className="text-lg font-semibold">User Removed</span>
|
||||
</div>
|
||||
|
||||
{pubkey ? (
|
||||
<PubkeyListFull pubkeys={[pubkey]} label="Removed Member" />
|
||||
) : (
|
||||
<div className="text-sm text-muted-foreground italic">
|
||||
Invalid event (missing pubkey)
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -67,6 +67,16 @@ import { ZapstoreAppSetDetailRenderer } from "./ZapstoreAppSetDetailRenderer";
|
||||
import { ZapstoreReleaseRenderer } from "./ZapstoreReleaseRenderer";
|
||||
import { ZapstoreReleaseDetailRenderer } from "./ZapstoreReleaseDetailRenderer";
|
||||
import { GroupMetadataRenderer } from "./GroupMetadataRenderer";
|
||||
import {
|
||||
RelayMembersRenderer,
|
||||
RelayMembersDetailRenderer,
|
||||
} from "./RelayMembersRenderer";
|
||||
import {
|
||||
AddUserRenderer,
|
||||
AddUserDetailRenderer,
|
||||
RemoveUserRenderer,
|
||||
RemoveUserDetailRenderer,
|
||||
} from "./RelayUserChangeRenderer";
|
||||
// NIP-51 List Renderers
|
||||
import { MuteListRenderer, MuteListDetailRenderer } from "./MuteListRenderer";
|
||||
import { PinListRenderer, PinListDetailRenderer } from "./PinListRenderer";
|
||||
@@ -159,6 +169,8 @@ const kindRenderers: Record<number, React.ComponentType<BaseEventProps>> = {
|
||||
1621: IssueRenderer, // Issue (NIP-34)
|
||||
9735: Kind9735Renderer, // Zap Receipt
|
||||
9802: Kind9802Renderer, // Highlight
|
||||
8000: AddUserRenderer, // Add User (NIP-43)
|
||||
8001: RemoveUserRenderer, // Remove User (NIP-43)
|
||||
777: SpellRenderer, // Spell (Grimoire)
|
||||
10000: MuteListRenderer, // Mute List (NIP-51)
|
||||
10001: PinListRenderer, // Pin List (NIP-51)
|
||||
@@ -178,6 +190,7 @@ const kindRenderers: Record<number, React.ComponentType<BaseEventProps>> = {
|
||||
10101: WikiAuthorsRenderer, // Good Wiki Authors (NIP-51)
|
||||
10102: WikiRelaysRenderer, // Good Wiki Relays (NIP-51)
|
||||
10317: Kind10317Renderer, // User Grasp List (NIP-34)
|
||||
13534: RelayMembersRenderer, // Relay Members (NIP-43)
|
||||
30000: FollowSetRenderer, // Follow Sets (NIP-51)
|
||||
30002: GenericRelayListRenderer, // Relay Sets (NIP-51)
|
||||
30003: BookmarkSetRenderer, // Bookmark Sets (NIP-51)
|
||||
@@ -255,6 +268,8 @@ const detailRenderers: Record<
|
||||
1618: PullRequestDetailRenderer, // Pull Request Detail (NIP-34)
|
||||
1621: IssueDetailRenderer, // Issue Detail (NIP-34)
|
||||
9802: Kind9802DetailRenderer, // Highlight Detail
|
||||
8000: AddUserDetailRenderer, // Add User Detail (NIP-43)
|
||||
8001: RemoveUserDetailRenderer, // Remove User Detail (NIP-43)
|
||||
10000: MuteListDetailRenderer, // Mute List Detail (NIP-51)
|
||||
10001: PinListDetailRenderer, // Pin List Detail (NIP-51)
|
||||
10002: Kind10002DetailRenderer, // Relay List Detail (NIP-65)
|
||||
@@ -268,6 +283,7 @@ const detailRenderers: Record<
|
||||
10101: WikiAuthorsDetailRenderer, // Good Wiki Authors Detail (NIP-51)
|
||||
10102: WikiRelaysDetailRenderer, // Good Wiki Relays Detail (NIP-51)
|
||||
10317: Kind10317DetailRenderer, // User Grasp List Detail (NIP-34)
|
||||
13534: RelayMembersDetailRenderer, // Relay Members Detail (NIP-43)
|
||||
30000: FollowSetDetailRenderer, // Follow Sets Detail (NIP-51)
|
||||
30003: BookmarkSetDetailRenderer, // Bookmark Sets Detail (NIP-51)
|
||||
30004: ArticleCurationSetDetailRenderer, // Article Curation Sets Detail (NIP-51)
|
||||
|
||||
@@ -887,13 +887,13 @@ export const EVENT_KINDS: Record<number | string, EventKind> = {
|
||||
nip: "47",
|
||||
icon: Wallet,
|
||||
},
|
||||
// 13534: {
|
||||
// kind: 13534,
|
||||
// name: "Membership Lists",
|
||||
// description: "Membership Lists",
|
||||
// nip: "43",
|
||||
// icon: Users,
|
||||
// },
|
||||
13534: {
|
||||
kind: 13534,
|
||||
name: "Relay Members",
|
||||
description: "Relay membership list",
|
||||
nip: "43",
|
||||
icon: Users,
|
||||
},
|
||||
// 17375: {
|
||||
// kind: 17375,
|
||||
// name: "Cashu Wallet Event",
|
||||
@@ -950,27 +950,27 @@ export const EVENT_KINDS: Record<number | string, EventKind> = {
|
||||
nip: "98",
|
||||
icon: Key,
|
||||
},
|
||||
// 28934: {
|
||||
// kind: 28934,
|
||||
// name: "Join Request",
|
||||
// description: "Join Request",
|
||||
// nip: "43",
|
||||
// icon: UserPlus,
|
||||
// },
|
||||
// 28935: {
|
||||
// kind: 28935,
|
||||
// name: "Invite Request",
|
||||
// description: "Invite Request",
|
||||
// nip: "43",
|
||||
// icon: Mail,
|
||||
// },
|
||||
// 28936: {
|
||||
// kind: 28936,
|
||||
// name: "Leave Request",
|
||||
// description: "Leave Request",
|
||||
// nip: "43",
|
||||
// icon: UserMinus,
|
||||
// },
|
||||
28934: {
|
||||
kind: 28934,
|
||||
name: "Join Request",
|
||||
description: "Relay join request with invite code",
|
||||
nip: "43",
|
||||
icon: UserPlus,
|
||||
},
|
||||
28935: {
|
||||
kind: 28935,
|
||||
name: "Invite Request",
|
||||
description: "Request invite code from relay",
|
||||
nip: "43",
|
||||
icon: Mail,
|
||||
},
|
||||
28936: {
|
||||
kind: 28936,
|
||||
name: "Leave Request",
|
||||
description: "Request to revoke relay access",
|
||||
nip: "43",
|
||||
icon: UserMinus,
|
||||
},
|
||||
|
||||
// Group Control
|
||||
9000: {
|
||||
|
||||
Reference in New Issue
Block a user