feat: nreq
This commit is contained in:
32
packages/app/src/Element/Feed/Generic.tsx
Normal file
32
packages/app/src/Element/Feed/Generic.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { NostrLink, NoteCollection, ReqFilter, RequestBuilder } from "@snort/system";
|
||||||
|
import { useReactions, useRequestBuilder } from "@snort/system-react";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { TimelineRenderer } from "./TimelineFragment";
|
||||||
|
|
||||||
|
export function GenericFeed({ link }: { link: NostrLink }) {
|
||||||
|
const sub = useMemo(() => {
|
||||||
|
console.debug(link);
|
||||||
|
const sub = new RequestBuilder("generic");
|
||||||
|
sub.withOptions({ leaveOpen: true });
|
||||||
|
const reqs = JSON.parse(link.id) as Array<ReqFilter>;
|
||||||
|
reqs.forEach(a => {
|
||||||
|
const f = sub.withBareFilter(a);
|
||||||
|
link.relays?.forEach(r => f.relay(r));
|
||||||
|
});
|
||||||
|
return sub;
|
||||||
|
}, [link]);
|
||||||
|
|
||||||
|
const evs = useRequestBuilder(NoteCollection, sub);
|
||||||
|
const reactions = useReactions("generic:reactions", evs.data?.map(a => NostrLink.fromEvent(a)) ?? []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TimelineRenderer
|
||||||
|
frags={[{ events: evs.data ?? [], refTime: 0 }]}
|
||||||
|
related={reactions.data ?? []}
|
||||||
|
latest={[]}
|
||||||
|
showLatest={() => {
|
||||||
|
//nothing
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -7,6 +7,7 @@ import { fetchNip05Pubkey } from "@snort/shared";
|
|||||||
import Spinner from "Icons/Spinner";
|
import Spinner from "Icons/Spinner";
|
||||||
import ProfilePage from "Pages/Profile/ProfilePage";
|
import ProfilePage from "Pages/Profile/ProfilePage";
|
||||||
import { ThreadRoute } from "Element/Event/Thread";
|
import { ThreadRoute } from "Element/Event/Thread";
|
||||||
|
import { GenericFeed } from "Element/Feed/Generic";
|
||||||
|
|
||||||
export default function NostrLinkHandler() {
|
export default function NostrLinkHandler() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
@ -24,6 +25,8 @@ export default function NostrLinkHandler() {
|
|||||||
} else if (nav.type === NostrPrefix.PublicKey || nav.type === NostrPrefix.Profile) {
|
} else if (nav.type === NostrPrefix.PublicKey || nav.type === NostrPrefix.Profile) {
|
||||||
const id = nav.encode();
|
const id = nav.encode();
|
||||||
setRenderComponent(<ProfilePage key={id} id={id} state={state} />); // Directly render ProfilePage
|
setRenderComponent(<ProfilePage key={id} id={id} state={state} />); // Directly render ProfilePage
|
||||||
|
} else if (nav.type === NostrPrefix.Req) {
|
||||||
|
setRenderComponent(<GenericFeed link={nav} />);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (state) {
|
if (state) {
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
NostrEvent,
|
NostrEvent,
|
||||||
mapEventToProfile,
|
mapEventToProfile,
|
||||||
PowWorker,
|
PowWorker,
|
||||||
|
encodeTLVEntries,
|
||||||
} from "@snort/system";
|
} from "@snort/system";
|
||||||
import { SnortContext } from "@snort/system-react";
|
import { SnortContext } from "@snort/system-react";
|
||||||
import { removeUndefined, throwIfOffline } from "@snort/shared";
|
import { removeUndefined, throwIfOffline } from "@snort/shared";
|
||||||
@ -286,3 +287,7 @@ root.render(
|
|||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
//@ts-ignore
|
||||||
|
window.encodeTLV = encodeTLVEntries;
|
||||||
|
@ -12,6 +12,7 @@ export const enum NostrPrefix {
|
|||||||
Event = "nevent",
|
Event = "nevent",
|
||||||
Relay = "nrelay",
|
Relay = "nrelay",
|
||||||
Address = "naddr",
|
Address = "naddr",
|
||||||
|
Req = "nreq",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TLVEntryType {
|
export enum TLVEntryType {
|
||||||
@ -54,7 +55,9 @@ export function encodeTLVEntries(prefix: NostrPrefix, ...entries: Array<TLVEntry
|
|||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
case TLVEntryType.Special: {
|
case TLVEntryType.Special: {
|
||||||
const buf =
|
const buf =
|
||||||
prefix === NostrPrefix.Address ? enc.encode(v.value as string) : utils.hexToBytes(v.value as string);
|
prefix === NostrPrefix.Address || prefix === NostrPrefix.Req
|
||||||
|
? enc.encode(v.value as string)
|
||||||
|
: utils.hexToBytes(v.value as string);
|
||||||
buffers.push(0, buf.length, ...buf);
|
buffers.push(0, buf.length, ...buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -101,8 +104,8 @@ export function decodeTLV(str: string) {
|
|||||||
function decodeTLVEntry(type: TLVEntryType, prefix: string, data: Uint8Array) {
|
function decodeTLVEntry(type: TLVEntryType, prefix: string, data: Uint8Array) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TLVEntryType.Special: {
|
case TLVEntryType.Special: {
|
||||||
if (prefix === NostrPrefix.Address) {
|
if (prefix === NostrPrefix.Address || prefix === NostrPrefix.Req) {
|
||||||
return new TextDecoder("ASCII").decode(data);
|
return new TextDecoder().decode(data);
|
||||||
} else {
|
} else {
|
||||||
return utils.bytesToHex(data);
|
return utils.bytesToHex(data);
|
||||||
}
|
}
|
||||||
@ -114,7 +117,7 @@ function decodeTLVEntry(type: TLVEntryType, prefix: string, data: Uint8Array) {
|
|||||||
return new Uint32Array(new Uint8Array(data.reverse()).buffer)[0];
|
return new Uint32Array(new Uint8Array(data.reverse()).buffer)[0];
|
||||||
}
|
}
|
||||||
case TLVEntryType.Relay: {
|
case TLVEntryType.Relay: {
|
||||||
return new TextDecoder("ASCII").decode(data);
|
return new TextDecoder().decode(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLin
|
|||||||
let entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link;
|
let entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link;
|
||||||
|
|
||||||
// trim any non-bech32 chars
|
// trim any non-bech32 chars
|
||||||
entity = entity.match(/(n(?:pub|profile|event|ote|addr)1[acdefghjklmnpqrstuvwxyz023456789]+)/)?.[0] ?? entity;
|
entity = entity.match(/(n(?:pub|profile|event|ote|addr|req)1[acdefghjklmnpqrstuvwxyz023456789]+)/)?.[0] ?? entity;
|
||||||
|
|
||||||
const isPrefix = (prefix: NostrPrefix) => {
|
const isPrefix = (prefix: NostrPrefix) => {
|
||||||
return entity.startsWith(prefix);
|
return entity.startsWith(prefix);
|
||||||
@ -251,7 +251,12 @@ export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLin
|
|||||||
const id = bech32ToHex(entity);
|
const id = bech32ToHex(entity);
|
||||||
if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id");
|
if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id");
|
||||||
return new NostrLink(NostrPrefix.Note, id);
|
return new NostrLink(NostrPrefix.Note, id);
|
||||||
} else if (isPrefix(NostrPrefix.Profile) || isPrefix(NostrPrefix.Event) || isPrefix(NostrPrefix.Address)) {
|
} else if (
|
||||||
|
isPrefix(NostrPrefix.Profile) ||
|
||||||
|
isPrefix(NostrPrefix.Event) ||
|
||||||
|
isPrefix(NostrPrefix.Address) ||
|
||||||
|
isPrefix(NostrPrefix.Req)
|
||||||
|
) {
|
||||||
const decoded = decodeTLV(entity);
|
const decoded = decodeTLV(entity);
|
||||||
|
|
||||||
const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string;
|
const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string;
|
||||||
@ -267,6 +272,8 @@ export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLin
|
|||||||
return new NostrLink(NostrPrefix.Event, id, kind, author, relays);
|
return new NostrLink(NostrPrefix.Event, id, kind, author, relays);
|
||||||
} else if (isPrefix(NostrPrefix.Address)) {
|
} else if (isPrefix(NostrPrefix.Address)) {
|
||||||
return new NostrLink(NostrPrefix.Address, id, kind, author, relays);
|
return new NostrLink(NostrPrefix.Address, id, kind, author, relays);
|
||||||
|
} else if (isPrefix(NostrPrefix.Req)) {
|
||||||
|
return new NostrLink(NostrPrefix.Req, id);
|
||||||
}
|
}
|
||||||
} else if (prefixHint) {
|
} else if (prefixHint) {
|
||||||
return new NostrLink(prefixHint, link);
|
return new NostrLink(prefixHint, link);
|
||||||
|
Reference in New Issue
Block a user