Resolve raw hex identifiers as event ID or pubkey in search and routing
Detect 64-char hex strings in the search bar and NIP19Page route. Query relays to check if the hex is an event ID first, then fall back to treating it as a pubkey if a kind-0 profile is found.
This commit is contained in:
@@ -5,6 +5,11 @@ import { nip19 } from 'nostr-tools';
|
||||
*/
|
||||
const NIP19_PREFIXES = ['npub1', 'nprofile1', 'note1', 'nevent1', 'naddr1'];
|
||||
|
||||
/**
|
||||
* Matches a 64-character lowercase hex string (a raw Nostr event ID or pubkey).
|
||||
*/
|
||||
const HEX_64_RE = /^[0-9a-f]{64}$/;
|
||||
|
||||
/**
|
||||
* Checks whether a string looks like a NIP-05 identifier (user@domain.com)
|
||||
* or a bare domain (e.g. fiatjaf.com). Strips a leading `@` if present.
|
||||
@@ -46,6 +51,11 @@ export function getNostrIdentifierPath(input: string): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
// Try raw 64-char hex (event ID or pubkey) — route handles it directly
|
||||
if (HEX_64_RE.test(value)) {
|
||||
return `/${value}`;
|
||||
}
|
||||
|
||||
// Try NIP-05
|
||||
if (looksLikeNip05(value)) {
|
||||
// Strip leading @ for the URL path
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useNostr } from '@nostrify/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import NotFound from './NotFound';
|
||||
import { ProfilePage } from './ProfilePage';
|
||||
import { PostDetailPage, AddrPostDetailPage } from './PostDetailPage';
|
||||
import type { AddressPointer } from 'nostr-tools/nip19';
|
||||
|
||||
const HEX_64_RE = /^[0-9a-f]{64}$/;
|
||||
|
||||
/**
|
||||
* Returns true if the identifier looks like a NIP-05 username (contains @).
|
||||
*/
|
||||
@@ -12,12 +16,50 @@ function isNip05Like(id: string): boolean {
|
||||
return id.includes('@');
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a raw 64-char hex string to either an event ID or a pubkey.
|
||||
* Tries to find an event with that ID first; if none is found, checks
|
||||
* whether a kind-0 profile exists for it as a pubkey.
|
||||
*/
|
||||
function HexIdentifierPage({ hex }: { hex: string }) {
|
||||
const { nostr } = useNostr();
|
||||
|
||||
const { data: resolved, isLoading } = useQuery({
|
||||
queryKey: ['hex-resolve', hex],
|
||||
queryFn: async () => {
|
||||
// Try as event ID first
|
||||
const events = await nostr.query([{ ids: [hex], limit: 1 }]);
|
||||
if (events.length > 0) {
|
||||
return 'event' as const;
|
||||
}
|
||||
// Try as pubkey (look for kind 0 profile)
|
||||
const profiles = await nostr.query([{ kinds: [0], authors: [hex], limit: 1 }]);
|
||||
if (profiles.length > 0) {
|
||||
return 'pubkey' as const;
|
||||
}
|
||||
return 'event' as const; // default to event — PostDetailPage will handle "not found"
|
||||
},
|
||||
staleTime: Infinity,
|
||||
});
|
||||
|
||||
if (isLoading || !resolved) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (resolved === 'pubkey') {
|
||||
return <ProfilePage />;
|
||||
}
|
||||
|
||||
return <PostDetailPage eventId={hex} />;
|
||||
}
|
||||
|
||||
/**
|
||||
* Universal route handler for `/:param`.
|
||||
*
|
||||
* Dispatches based on the shape of the identifier:
|
||||
* - NIP-19 (`npub1...`, `note1...`, `nevent1...`, `naddr1...`, `nprofile1...`)
|
||||
* - NIP-05 (`user@domain.com`) → profile
|
||||
* - Raw 64-char hex → event ID or pubkey (resolved via relay query)
|
||||
*/
|
||||
export function NIP19Page() {
|
||||
const { nip19: identifier } = useParams<{ nip19: string }>();
|
||||
@@ -31,6 +73,11 @@ export function NIP19Page() {
|
||||
return <ProfilePage />;
|
||||
}
|
||||
|
||||
// Raw 64-char hex — could be event ID or pubkey, need to resolve
|
||||
if (HEX_64_RE.test(identifier)) {
|
||||
return <HexIdentifierPage hex={identifier} />;
|
||||
}
|
||||
|
||||
// Try NIP-19 decoding
|
||||
let decoded;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user