mirror of
https://github.com/hzrd149/nsite-gateway.git
synced 2025-08-22 04:19:33 +00:00
cleanup
bump dependencies
This commit is contained in:
parent
b2b8e0108e
commit
d87497e6c0
@ -14,7 +14,7 @@ BLOSSOM_SERVERS=https://nostr.download,https://cdn.satellite.earth
|
|||||||
# The max file size to serve
|
# The max file size to serve
|
||||||
MAX_FILE_SIZE='2 MB'
|
MAX_FILE_SIZE='2 MB'
|
||||||
|
|
||||||
# The cache folder for nginx
|
# The cache folder for nginx (used for cache invalidation)
|
||||||
NGINX_CACHE_DIR='/var/nginx/cache'
|
NGINX_CACHE_DIR='/var/nginx/cache'
|
||||||
|
|
||||||
# A nprofile pointer for an nsite to use as the default homepage
|
# A nprofile pointer for an nsite to use as the default homepage
|
||||||
|
30
package.json
30
package.json
@ -19,32 +19,32 @@
|
|||||||
"public"
|
"public"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@keyv/redis": "^3.0.1",
|
"@keyv/redis": "^4.3.2",
|
||||||
"@keyv/sqlite": "^4.0.1",
|
"@keyv/sqlite": "^4.0.1",
|
||||||
"@koa/cors": "^5.0.0",
|
"@koa/cors": "^5.0.0",
|
||||||
"blossom-client-sdk": "^2.1.1",
|
"blossom-client-sdk": "^3.0.1",
|
||||||
"debug": "^4.4.0",
|
"debug": "^4.4.0",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"follow-redirects": "^1.15.9",
|
"follow-redirects": "^1.15.9",
|
||||||
"keyv": "^5.2.3",
|
"keyv": "^5.3.2",
|
||||||
"koa": "^2.15.3",
|
"koa": "^2.16.0",
|
||||||
"koa-morgan": "^1.0.1",
|
"koa-morgan": "^1.0.1",
|
||||||
"koa-send": "^5.0.1",
|
"koa-send": "^5.0.1",
|
||||||
"koa-static": "^5.0.0",
|
"koa-static": "^5.0.0",
|
||||||
"mime": "^4.0.6",
|
"mime": "^4.0.6",
|
||||||
"nostr-tools": "^2.10.4",
|
"nostr-tools": "^2.11.0",
|
||||||
"nsite-cli": "^0.1.14",
|
"nsite-cli": "^0.1.16",
|
||||||
"pac-proxy-agent": "^7.1.0",
|
"pac-proxy-agent": "^7.2.0",
|
||||||
"proxy-agent": "^6.5.0",
|
"proxy-agent": "^6.5.0",
|
||||||
"puppeteer": "^23.11.1",
|
"puppeteer": "^23.11.1",
|
||||||
"websocket-polyfill": "1.0.0",
|
"websocket-polyfill": "1.0.0",
|
||||||
"ws": "^8.18.0",
|
"ws": "^8.18.1",
|
||||||
"xbytes": "^1.9.1"
|
"xbytes": "^1.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/cli": "^2.27.11",
|
"@changesets/cli": "^2.28.1",
|
||||||
"@swc-node/register": "^1.10.9",
|
"@swc-node/register": "^1.10.10",
|
||||||
"@swc/core": "^1.10.9",
|
"@swc/core": "^1.11.10",
|
||||||
"@types/better-sqlite3": "^7.6.12",
|
"@types/better-sqlite3": "^7.6.12",
|
||||||
"@types/debug": "^4.1.12",
|
"@types/debug": "^4.1.12",
|
||||||
"@types/follow-redirects": "^1.14.4",
|
"@types/follow-redirects": "^1.14.4",
|
||||||
@ -54,12 +54,12 @@
|
|||||||
"@types/koa-static": "^4.0.4",
|
"@types/koa-static": "^4.0.4",
|
||||||
"@types/koa__cors": "^5.0.0",
|
"@types/koa__cors": "^5.0.0",
|
||||||
"@types/koa__router": "^12.0.4",
|
"@types/koa__router": "^12.0.4",
|
||||||
"@types/node": "^20.17.14",
|
"@types/node": "^20.17.24",
|
||||||
"@types/proxy-from-env": "^1.0.4",
|
"@types/proxy-from-env": "^1.0.4",
|
||||||
"@types/ws": "^8.5.13",
|
"@types/ws": "^8.18.0",
|
||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.5.3",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"websocket-polyfill": "1.0.0"
|
"websocket-polyfill": "1.0.0"
|
||||||
|
1184
pnpm-lock.yaml
generated
1184
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,13 @@
|
|||||||
import { IncomingMessage } from "node:http";
|
import { IncomingMessage } from "node:http";
|
||||||
import { getServersFromServerListEvent, USER_BLOSSOM_SERVER_LIST_KIND } from "blossom-client-sdk";
|
|
||||||
|
|
||||||
import { BLOSSOM_SERVERS, MAX_FILE_SIZE } from "./env.js";
|
import { BLOSSOM_SERVERS, MAX_FILE_SIZE } from "./env.js";
|
||||||
import { makeRequestWithAbort } from "./helpers/http.js";
|
import { makeRequestWithAbort } from "./helpers/http.js";
|
||||||
import pool from "./nostr.js";
|
|
||||||
|
|
||||||
export async function getUserBlossomServers(pubkey: string, relays: string[]) {
|
|
||||||
const blossomServersEvent = await pool.get(relays, { kinds: [USER_BLOSSOM_SERVER_LIST_KIND], authors: [pubkey] });
|
|
||||||
|
|
||||||
return blossomServersEvent ? getServersFromServerListEvent(blossomServersEvent).map((u) => u.toString()) : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads a file from multiple servers
|
* Downloads a file from multiple servers
|
||||||
* @todo download the file to /tmp and verify it
|
* @todo download the file to /tmp and verify it
|
||||||
*/
|
*/
|
||||||
export function downloadFile(sha256: string, servers = BLOSSOM_SERVERS): Promise<IncomingMessage> {
|
export function downloadBlob(sha256: string, servers = BLOSSOM_SERVERS): Promise<IncomingMessage> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const controllers = new Map<string, AbortController>();
|
const controllers = new Map<string, AbortController>();
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { extname, isAbsolute, join } from "path";
|
import { extname, join } from "path";
|
||||||
import { NSITE_KIND } from "./const.js";
|
import { NSITE_KIND } from "./const.js";
|
||||||
import { requestEvents } from "./nostr.js";
|
import { requestEvents } from "./nostr.js";
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ export function getSearchPaths(path: string) {
|
|||||||
return paths.filter((p) => !!p);
|
return paths.filter((p) => !!p);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseNsiteEvent(event: { pubkey: string; tags: string[][] }) {
|
export function parseNsiteEvent(event: { pubkey: string; tags: string[][]; created_at: number }) {
|
||||||
const path = event.tags.find((t) => t[0] === "d" && t[1])?.[1];
|
const path = event.tags.find((t) => t[0] === "d" && t[1])?.[1];
|
||||||
const sha256 = event.tags.find((t) => t[0] === "x" && t[1])?.[1];
|
const sha256 = event.tags.find((t) => t[0] === "x" && t[1])?.[1];
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ export function parseNsiteEvent(event: { pubkey: string; tags: string[][] }) {
|
|||||||
pubkey: event.pubkey,
|
pubkey: event.pubkey,
|
||||||
path: join("/", path),
|
path: join("/", path),
|
||||||
sha256,
|
sha256,
|
||||||
|
created_at: event.created_at,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
207
src/index.ts
207
src/index.ts
@ -14,13 +14,12 @@ import { spawn } from "node:child_process";
|
|||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
|
|
||||||
import { resolveNpubFromHostname } from "./helpers/dns.js";
|
import { resolveNpubFromHostname } from "./helpers/dns.js";
|
||||||
import { getNsiteBlobs, parseNsiteEvent } from "./events.js";
|
import { getNsiteBlobs } from "./events.js";
|
||||||
import { downloadFile, getUserBlossomServers } from "./blossom.js";
|
import { downloadBlob } from "./blossom.js";
|
||||||
import {
|
import {
|
||||||
BLOSSOM_SERVERS,
|
BLOSSOM_SERVERS,
|
||||||
ENABLE_SCREENSHOTS,
|
ENABLE_SCREENSHOTS,
|
||||||
HOST,
|
HOST,
|
||||||
NGINX_CACHE_DIR,
|
|
||||||
NSITE_HOMEPAGE,
|
NSITE_HOMEPAGE,
|
||||||
NSITE_HOMEPAGE_DIR,
|
NSITE_HOMEPAGE_DIR,
|
||||||
NSITE_HOST,
|
NSITE_HOST,
|
||||||
@ -29,9 +28,9 @@ import {
|
|||||||
SUBSCRIPTION_RELAYS,
|
SUBSCRIPTION_RELAYS,
|
||||||
} from "./env.js";
|
} from "./env.js";
|
||||||
import { userDomains, userRelays, userServers } from "./cache.js";
|
import { userDomains, userRelays, userServers } from "./cache.js";
|
||||||
import { invalidatePubkeyPath } from "./nginx.js";
|
import pool, { getUserBlossomServers, getUserOutboxes } from "./nostr.js";
|
||||||
import pool, { getUserOutboxes, subscribeForEvents } from "./nostr.js";
|
|
||||||
import logger from "./logger.js";
|
import logger from "./logger.js";
|
||||||
|
import { watchInvalidation } from "./invalidation.js";
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
@ -79,96 +78,100 @@ app.use(async (ctx, next) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pubkey) {
|
if (!pubkey) return await next();
|
||||||
const npub = npubEncode(pubkey);
|
|
||||||
const log = logger.extend(npub);
|
|
||||||
ctx.state.pubkey = pubkey;
|
|
||||||
|
|
||||||
let relays = await userRelays.get<string[] | undefined>(pubkey);
|
const npub = npubEncode(pubkey);
|
||||||
|
const log = logger.extend(npub);
|
||||||
|
ctx.state.pubkey = pubkey;
|
||||||
|
|
||||||
// fetch relays if not in cache
|
let relays = await userRelays.get<string[] | undefined>(pubkey);
|
||||||
if (!relays) {
|
|
||||||
log(`Fetching relays`);
|
|
||||||
|
|
||||||
relays = await getUserOutboxes(pubkey);
|
// fetch relays if not in cache
|
||||||
if (relays) {
|
if (!relays) {
|
||||||
await userRelays.set(pubkey, relays);
|
log(`Fetching relays`);
|
||||||
log(`Found ${relays.length} relays`);
|
|
||||||
} else {
|
relays = await getUserOutboxes(pubkey);
|
||||||
relays = [];
|
if (relays) {
|
||||||
await userServers.set(pubkey, [], 30_000);
|
await userRelays.set(pubkey, relays);
|
||||||
log(`Failed to find relays`);
|
log(`Found ${relays.length} relays`);
|
||||||
}
|
} else {
|
||||||
|
relays = [];
|
||||||
|
await userServers.set(pubkey, [], 30_000);
|
||||||
|
log(`Failed to find relays`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// always check subscription relays
|
||||||
|
relays.push(...SUBSCRIPTION_RELAYS);
|
||||||
|
|
||||||
|
if (relays.length === 0) throw new Error("No nostr relays");
|
||||||
|
|
||||||
|
log(`Searching for ${ctx.path}`);
|
||||||
|
let blobs = await getNsiteBlobs(pubkey, ctx.path, relays);
|
||||||
|
|
||||||
|
if (blobs.length === 0) {
|
||||||
|
// fallback to custom 404 page
|
||||||
|
log(`Looking for custom 404 page`);
|
||||||
|
blobs = await getNsiteBlobs(pubkey, "/404.html", relays);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blobs.length === 0) {
|
||||||
|
log(`Found 0 events`);
|
||||||
|
ctx.status = 404;
|
||||||
|
ctx.body = "Not Found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let servers = await userServers.get<string[] | undefined>(pubkey);
|
||||||
|
|
||||||
|
// fetch blossom servers if not in cache
|
||||||
|
if (!servers) {
|
||||||
|
log(`Fetching blossom servers`);
|
||||||
|
servers = await getUserBlossomServers(pubkey, relays);
|
||||||
|
|
||||||
|
if (servers) {
|
||||||
|
await userServers.set(pubkey, servers);
|
||||||
|
log(`Found ${servers.length} servers`);
|
||||||
|
} else {
|
||||||
|
servers = [];
|
||||||
|
await userServers.set(pubkey, [], 30_000);
|
||||||
|
log(`Failed to find servers`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// always fetch from additional servers
|
||||||
|
servers.push(...BLOSSOM_SERVERS);
|
||||||
|
|
||||||
|
for (const blob of blobs) {
|
||||||
|
const res = await downloadBlob(blob.sha256, servers);
|
||||||
|
if (!res) continue;
|
||||||
|
|
||||||
|
const type = mime.getType(blob.path);
|
||||||
|
if (type) ctx.set("content-type", type);
|
||||||
|
else if (res.headers["content-type"]) ctx.set("content-type", res.headers["content-type"]);
|
||||||
|
|
||||||
|
// pass headers along
|
||||||
|
if (res.headers["content-length"]) ctx.set("content-length", res.headers["content-length"]);
|
||||||
|
|
||||||
|
// set Onion-Location header
|
||||||
|
if (ONION_HOST) {
|
||||||
|
const url = new URL(ONION_HOST);
|
||||||
|
url.hostname = npubEncode(pubkey) + "." + url.hostname;
|
||||||
|
ctx.set("Onion-Location", url.toString().replace(/\/$/, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
relays.push(...SUBSCRIPTION_RELAYS);
|
// add cache headers
|
||||||
|
ctx.set("ETag", res.headers["etag"] || `"${blob.sha256}"`);
|
||||||
|
ctx.set("Cache-Control", "public, max-age=3600");
|
||||||
|
ctx.set("Last-Modified", res.headers["last-modified"] || new Date(blob.created_at * 1000).toUTCString());
|
||||||
|
|
||||||
if (relays.length === 0) throw new Error("No nostr relays");
|
ctx.status = 200;
|
||||||
|
ctx.body = res;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log(`Searching for ${ctx.path}`);
|
ctx.status = 500;
|
||||||
let blobs = await getNsiteBlobs(pubkey, ctx.path, relays);
|
ctx.body = "Failed to find blob";
|
||||||
|
|
||||||
if (blobs.length === 0) {
|
|
||||||
// fallback to custom 404 page
|
|
||||||
log(`Looking for custom 404 page`);
|
|
||||||
blobs = await getNsiteBlobs(pubkey, "/404.html", relays);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blobs.length === 0) {
|
|
||||||
log(`Found 0 events`);
|
|
||||||
ctx.status = 404;
|
|
||||||
ctx.body = "Not Found";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let servers = await userServers.get<string[] | undefined>(pubkey);
|
|
||||||
|
|
||||||
// fetch blossom servers if not in cache
|
|
||||||
if (!servers) {
|
|
||||||
log(`Fetching blossom servers`);
|
|
||||||
servers = await getUserBlossomServers(pubkey, relays);
|
|
||||||
|
|
||||||
if (servers) {
|
|
||||||
await userServers.set(pubkey, servers);
|
|
||||||
log(`Found ${servers.length} servers`);
|
|
||||||
} else {
|
|
||||||
servers = [];
|
|
||||||
await userServers.set(pubkey, [], 30_000);
|
|
||||||
log(`Failed to find servers`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// always fetch from additional servers
|
|
||||||
servers.push(...BLOSSOM_SERVERS);
|
|
||||||
|
|
||||||
for (const blob of blobs) {
|
|
||||||
const res = await downloadFile(blob.sha256, servers);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
const type = mime.getType(blob.path);
|
|
||||||
if (type) ctx.set("content-type", type);
|
|
||||||
else if (res.headers["content-type"]) ctx.set("content-type", res.headers["content-type"]);
|
|
||||||
|
|
||||||
// pass headers along
|
|
||||||
if (res.headers["content-length"]) ctx.set("content-length", res.headers["content-length"]);
|
|
||||||
if (res.headers["last-modified"]) ctx.set("last-modified", res.headers["last-modified"]);
|
|
||||||
|
|
||||||
// set Onion-Location header
|
|
||||||
if (ONION_HOST) {
|
|
||||||
const url = new URL(ONION_HOST);
|
|
||||||
url.hostname = npubEncode(pubkey) + "." + url.hostname;
|
|
||||||
ctx.set("Onion-Location", url.toString().replace(/\/$/, ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.status = 200;
|
|
||||||
ctx.body = res;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.status = 500;
|
|
||||||
ctx.body = "Failed to find blob";
|
|
||||||
} else await next();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ONION_HOST) {
|
if (ONION_HOST) {
|
||||||
@ -247,35 +250,13 @@ try {
|
|||||||
app.use(serve(www, serveOptions));
|
app.use(serve(www, serveOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start the server
|
||||||
app.listen({ host: NSITE_HOST, port: NSITE_PORT }, () => {
|
app.listen({ host: NSITE_HOST, port: NSITE_PORT }, () => {
|
||||||
logger("Started on port", HOST);
|
logger("Started on port", HOST);
|
||||||
});
|
});
|
||||||
|
|
||||||
// invalidate nginx cache and screenshots on new events
|
// watch for invalidations
|
||||||
if (SUBSCRIPTION_RELAYS.length > 0) {
|
watchInvalidation();
|
||||||
logger(`Listening for new nsite events on: ${SUBSCRIPTION_RELAYS.join(", ")}`);
|
|
||||||
|
|
||||||
subscribeForEvents(SUBSCRIPTION_RELAYS, async (event) => {
|
|
||||||
try {
|
|
||||||
const nsite = parseNsiteEvent(event);
|
|
||||||
if (nsite) {
|
|
||||||
const log = logger.extend(nip19.npubEncode(nsite.pubkey));
|
|
||||||
if (NGINX_CACHE_DIR) {
|
|
||||||
log(`Invalidating ${nsite.path}`);
|
|
||||||
await invalidatePubkeyPath(nsite.pubkey, nsite.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// invalidate screenshot for nsite
|
|
||||||
if (ENABLE_SCREENSHOTS && (nsite.path === "/" || nsite.path === "/index.html")) {
|
|
||||||
const { removeScreenshot } = await import("./screenshots.js");
|
|
||||||
await removeScreenshot(nsite.pubkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`Failed to invalidate ${event.id}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on("unhandledRejection", (reason, promise) => {
|
process.on("unhandledRejection", (reason, promise) => {
|
||||||
console.error("Unhandled Rejection at:", promise, "reason:", reason);
|
console.error("Unhandled Rejection at:", promise, "reason:", reason);
|
||||||
|
38
src/invalidation.ts
Normal file
38
src/invalidation.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { nip19 } from "nostr-tools";
|
||||||
|
|
||||||
|
import { ENABLE_SCREENSHOTS, NGINX_CACHE_DIR, SUBSCRIPTION_RELAYS } from "./env.js";
|
||||||
|
import { parseNsiteEvent } from "./events.js";
|
||||||
|
import pool from "./nostr.js";
|
||||||
|
import { invalidatePubkeyPath } from "./nginx.js";
|
||||||
|
import { NSITE_KIND } from "./const.js";
|
||||||
|
import logger from "./logger.js";
|
||||||
|
|
||||||
|
export function watchInvalidation() {
|
||||||
|
// invalidate nginx cache and screenshots on new events
|
||||||
|
if (SUBSCRIPTION_RELAYS.length > 0) {
|
||||||
|
logger(`Listening for new nsite events on: ${SUBSCRIPTION_RELAYS.join(", ")}`);
|
||||||
|
|
||||||
|
pool.subscribeMany(SUBSCRIPTION_RELAYS, [{ kinds: [NSITE_KIND], since: Math.round(Date.now() / 1000) - 60 * 60 }], {
|
||||||
|
onevent: async (event) => {
|
||||||
|
try {
|
||||||
|
const nsite = parseNsiteEvent(event);
|
||||||
|
if (nsite) {
|
||||||
|
const log = logger.extend(nip19.npubEncode(nsite.pubkey));
|
||||||
|
if (NGINX_CACHE_DIR) {
|
||||||
|
log(`Invalidating ${nsite.path}`);
|
||||||
|
await invalidatePubkeyPath(nsite.pubkey, nsite.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidate screenshot for nsite
|
||||||
|
if (ENABLE_SCREENSHOTS && (nsite.path === "/" || nsite.path === "/index.html")) {
|
||||||
|
const { removeScreenshot } = await import("./screenshots.js");
|
||||||
|
await removeScreenshot(nsite.pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Failed to invalidate ${event.id}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
11
src/nostr.ts
11
src/nostr.ts
@ -1,6 +1,7 @@
|
|||||||
import { Filter, NostrEvent, SimplePool } from "nostr-tools";
|
import { Filter, NostrEvent, SimplePool } from "nostr-tools";
|
||||||
|
import { getServersFromServerListEvent, USER_BLOSSOM_SERVER_LIST_KIND } from "blossom-client-sdk";
|
||||||
|
|
||||||
import { LOOKUP_RELAYS } from "./env.js";
|
import { LOOKUP_RELAYS } from "./env.js";
|
||||||
import { NSITE_KIND } from "./const.js";
|
|
||||||
|
|
||||||
const pool = new SimplePool();
|
const pool = new SimplePool();
|
||||||
|
|
||||||
@ -11,10 +12,10 @@ export async function getUserOutboxes(pubkey: string) {
|
|||||||
return mailboxes.tags.filter((t) => t[0] === "r" && (t[2] === undefined || t[2] === "write")).map((t) => t[1]);
|
return mailboxes.tags.filter((t) => t[0] === "r" && (t[2] === undefined || t[2] === "write")).map((t) => t[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function subscribeForEvents(relays: string[], onevent: (event: NostrEvent) => any) {
|
export async function getUserBlossomServers(pubkey: string, relays: string[]) {
|
||||||
return pool.subscribeMany(relays, [{ kinds: [NSITE_KIND], since: Math.round(Date.now() / 1000) - 60 * 60 }], {
|
const blossomServersEvent = await pool.get(relays, { kinds: [USER_BLOSSOM_SERVER_LIST_KIND], authors: [pubkey] });
|
||||||
onevent,
|
|
||||||
});
|
return blossomServersEvent ? getServersFromServerListEvent(blossomServersEvent).map((u) => u.toString()) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requestEvents(relays: string[], filter: Filter) {
|
export function requestEvents(relays: string[], filter: Filter) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user