substr/nostr.ts
Râu Cao 5b0397268b
Some checks failed
CI / Test and lint (push) Failing after 10m22s
Improve Nostr link handling
Fixes a bunch of problems with how Nostr links are created and replaced
in Markdown content
2025-04-21 16:53:22 +04:00

97 lines
2.4 KiB
TypeScript

import { NostrEvent, NostrFilter, NPool, NRelay1 } from "@nostrify/nostrify";
import config from "./config.ts";
import Article from "./models/article.ts";
const relayPool = new NPool({
open: (url) => new NRelay1(url),
// deno-lint-ignore require-await
reqRouter: async (filters) =>
new Map(
config.relay_urls.map((url) => [url, filters]),
),
// deno-lint-ignore require-await
eventRouter: async (_event) => [],
});
async function fetchWithTimeout(filters: NostrFilter[]) {
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error("relay timeout")), config.query_timeout)
);
const eventsPromise = relayPool.query(filters);
const events = await Promise.race([eventsPromise, timeoutPromise]);
return events;
}
export async function fetchReplaceableEvent(
pubkey: string,
identifier: string,
) {
let events = await fetchWithTimeout([{
authors: [pubkey],
kinds: [30023],
"#d": [identifier],
limit: 1,
}]) as NostrEvent[];
if (events.length > 0) {
return events[0];
} else {
events = await fetchWithTimeout([{
authors: [pubkey],
kinds: [30024],
"#d": [identifier],
limit: 1,
}]) as NostrEvent[];
return events.length > 0 ? events[0] : null;
}
}
export async function fetchArticlesByAuthor(
pubkey: string,
limit: number = 10,
) {
const events = await fetchWithTimeout([{
authors: [pubkey],
kinds: [30023],
limit: limit,
}]) as NostrEvent[];
const articles = events.map((a) => new Article(a));
return articles
.filter((a) => !a.isDeleted)
.filter((a) => a.content.trim() !== "")
.sort((a, b) => b.publishedAt - a.publishedAt)
.slice(0, limit); // The limit seems to apply per relay, not per pool query
}
export async function fetchProfileEvent(pubkey: string) {
const events = await fetchWithTimeout([{
authors: [pubkey],
kinds: [0],
limit: 1,
}]) as NostrEvent[];
return events.length > 0 ? events[0] : null;
}
export async function verifyNip05Address(
address: string,
pubkey: string,
): Promise<boolean> {
const [username, host] = address.split("@");
const url = `https://${host}/.well-known/nostr.json?name=${username}`;
try {
const res = await fetch(url);
if (res.status === 404 || !res.ok) return false;
const data = await res.json();
return data.names && data.names[username] === pubkey;
} catch (_e) {
return false;
}
}