mirror of
https://github.com/hzrd149/nsite-gateway.git
synced 2025-06-23 12:05:01 +00:00
Add simple landing page
This commit is contained in:
parent
50afa5b70d
commit
bfc1b1c4c2
5
.changeset/hot-llamas-clap.md
Normal file
5
.changeset/hot-llamas-clap.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"nsite-ts": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add simple landing page
|
6
.env
6
.env
@ -1,6 +1,2 @@
|
|||||||
CACHE_PATH="in-memory"
|
CACHE_PATH="in-memory"
|
||||||
|
LOOKUP_RELAYS=wss://user.kindpag.es,wss://purplepag.es
|
||||||
NOSTR_RELAYS=wss://nos.lol,wss://relay.damus.io
|
|
||||||
BLOSSOM_SERVERS=https://cdn.hzrd149.com
|
|
||||||
|
|
||||||
NGINX_HOST='nginx'
|
|
||||||
|
@ -15,7 +15,8 @@ services:
|
|||||||
|
|
||||||
nsite:
|
nsite:
|
||||||
build: .
|
build: .
|
||||||
|
image: ghcr.io/hzrd149/nsite-ts:master
|
||||||
environment:
|
environment:
|
||||||
NOSTR_RELAYS: wss://nos.lol,wss://relay.damus.io
|
LOOKUP_RELAYS: wss://user.kindpag.es,wss://purplepag.es
|
||||||
ports:
|
ports:
|
||||||
- 3000:80
|
- 3000:80
|
||||||
|
@ -6,7 +6,7 @@ server {
|
|||||||
proxy_cache request_cache;
|
proxy_cache request_cache;
|
||||||
proxy_cache_valid 200 60m;
|
proxy_cache_valid 200 60m;
|
||||||
proxy_cache_valid 404 10m;
|
proxy_cache_valid 404 10m;
|
||||||
proxy_cache_key $scheme$proxy_host$request_uri;
|
proxy_cache_key $scheme$host$request_uri;
|
||||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||||
|
|
||||||
add_header X-Cache $upstream_cache_status;
|
add_header X-Cache $upstream_cache_status;
|
||||||
|
@ -14,33 +14,19 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<label>relays</label>
|
<h1>nsite-ts</h1>
|
||||||
<br />
|
<a href="https://github.com/hzrd149/nsite-ts" target="_blank">Source Code</a>
|
||||||
<textarea type="text" id="relays" cols="50" rows="4"></textarea>
|
|
||||||
<br />
|
<h2>Latest nsites:</h2>
|
||||||
<br />
|
<div id="sites"></div>
|
||||||
<label>blossom servers</label>
|
|
||||||
<br />
|
<template id="site">
|
||||||
<textarea type="text" id="servers" cols="50" rows="4"></textarea>
|
<div class="site">
|
||||||
<br />
|
<a class="pubkey link"></a>
|
||||||
<br />
|
<span class="date"></span>
|
||||||
<input type="file" id="files" webkitdirectory directory multiple />
|
</div>
|
||||||
<button id="upload-button">Upload nsite</button>
|
</template>
|
||||||
<div
|
|
||||||
id="log"
|
|
||||||
style="
|
|
||||||
max-height: 50em;
|
|
||||||
max-width: 80em;
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid gray;
|
|
||||||
min-height: 8em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 0.8em;
|
|
||||||
gap: 0.1em;
|
|
||||||
white-space: pre;
|
|
||||||
"
|
|
||||||
></div>
|
|
||||||
<script type="module" src="./main.js"></script>
|
<script type="module" src="./main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
156
public/main.js
156
public/main.js
@ -1,142 +1,32 @@
|
|||||||
import { multiServerUpload, BlossomClient } from "blossom-client-sdk";
|
import { nip19, SimplePool } from "nostr-tools";
|
||||||
import { SimplePool } from "nostr-tools";
|
|
||||||
|
|
||||||
const logContainer = document.getElementById("log");
|
const seen = new Set();
|
||||||
function log(...args) {
|
function addSite(event) {
|
||||||
const el = document.createElement("div");
|
if (seen.has(event.pubkey)) return;
|
||||||
el.innerText = args.join(" ");
|
seen.add(event.pubkey);
|
||||||
logContainer.appendChild(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadButton = document.getElementById("upload-button");
|
try {
|
||||||
|
const template = document.getElementById("site");
|
||||||
|
const site = template.content.cloneNode(true);
|
||||||
|
const npub = nip19.npubEncode(event.pubkey);
|
||||||
|
|
||||||
/** @type {HTMLInputElement} */
|
site.querySelector(".pubkey").textContent = npub;
|
||||||
const filesInput = document.getElementById("files");
|
site.querySelector(".link").href = new URL("/", `${location.protocol}//${npub}.${location.host}`).toString();
|
||||||
|
|
||||||
/**
|
document.getElementById("sites").appendChild(site);
|
||||||
* @param {FileSystemFileEntry} fileEntry
|
} catch (error) {
|
||||||
* @returns {File}
|
console.log("Failed to add site", event);
|
||||||
*/
|
console.log(error);
|
||||||
export function readFileSystemFile(fileEntry) {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
fileEntry.file(
|
|
||||||
(file) => res(file),
|
|
||||||
(err) => rej(err),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FileSystemDirectoryEntry} directory
|
|
||||||
* @returns {FileSystemEntry[]}
|
|
||||||
*/
|
|
||||||
export function readFileSystemDirectory(directory) {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
directory.createReader().readEntries(
|
|
||||||
(entries) => res(entries),
|
|
||||||
(err) => rej(err),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* uploads a file system entry to blossom servers
|
|
||||||
* @param {FileSystemEntry} entry
|
|
||||||
* @returns {{file: File, path: string, sha256: string}[]}
|
|
||||||
*/
|
|
||||||
async function readFileSystemEntry(entry) {
|
|
||||||
const files = [];
|
|
||||||
if (entry instanceof FileSystemFileEntry && entry.isFile) {
|
|
||||||
try {
|
|
||||||
const file = await readFileSystemFile(entry);
|
|
||||||
const sha256 = await BlossomClient.getFileSha256(file);
|
|
||||||
const path = entry.fullPath;
|
|
||||||
|
|
||||||
files.push({ file, path, sha256 });
|
|
||||||
} catch (e) {
|
|
||||||
log("Failed to add" + entry.fullPath);
|
|
||||||
log(e.message);
|
|
||||||
}
|
|
||||||
} else if (entry instanceof FileSystemDirectoryEntry && entry.isDirectory) {
|
|
||||||
const entries = await readFileSystemDirectory(entry);
|
|
||||||
for (const e of entries) files.push(...(await readFileSystemEntry(e)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* uploads a file system entry to blossom servers
|
|
||||||
* @param {FileList} list
|
|
||||||
* @returns {{file: File, path: string, sha256: string}[]}
|
|
||||||
*/
|
|
||||||
async function readFileList(list) {
|
|
||||||
const files = [];
|
|
||||||
for (const file of list) {
|
|
||||||
const path = file.webkitRelativePath ? file.webkitRelativePath : file.name;
|
|
||||||
const sha256 = await BlossomClient.getFileSha256(file);
|
|
||||||
files.push({ file, path, sha256 });
|
|
||||||
}
|
|
||||||
return files;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pool = new SimplePool();
|
const pool = new SimplePool();
|
||||||
|
|
||||||
/**
|
console.log("Loading sites");
|
||||||
* uploads a file system entry to blossom servers
|
pool.subscribeMany(
|
||||||
* @param {{file:File, path:string}} files
|
["wss://relay.damus.io", "wss://nos.lol", "wss://nostr.wine"],
|
||||||
* @param {import("blossom-client-sdk").Signer} signer
|
[{ kinds: [34128], "#d": ["/index.html"] }],
|
||||||
* @param {*} auth
|
{
|
||||||
* @param {string[]} servers
|
onevent: addSite,
|
||||||
* @param {string[]} relays
|
},
|
||||||
*/
|
);
|
||||||
async function uploadFiles(files, signer, auth, servers, relays) {
|
|
||||||
for (const { file, path, sha256 } of files) {
|
|
||||||
try {
|
|
||||||
const upload = multiServerUpload(servers, file, signer, auth);
|
|
||||||
|
|
||||||
let published = false;
|
|
||||||
for await (let { blob } of upload) {
|
|
||||||
if (!published) {
|
|
||||||
const signed = await signer({
|
|
||||||
kind: 34128,
|
|
||||||
content: "",
|
|
||||||
created_at: Math.round(Date.now() / 1000),
|
|
||||||
tags: [
|
|
||||||
["d", path],
|
|
||||||
["x", sha256],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
await pool.publish(relays, signed);
|
|
||||||
|
|
||||||
log("Published", path, sha256, signed.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
log(`Failed to upload ${path}`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadButton.addEventListener("click", async () => {
|
|
||||||
if (!window.nostr) return alert("Missing NIP-07 signer");
|
|
||||||
|
|
||||||
const signer = (draft) => window.nostr.signEvent(draft);
|
|
||||||
const relays = document.getElementById("relays").value.split(/\n|,/);
|
|
||||||
const servers = document.getElementById("servers").value.split(/\n|,/);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (filesInput.files) {
|
|
||||||
const files = await readFileList(filesInput.files);
|
|
||||||
|
|
||||||
// strip leading dir
|
|
||||||
for (const file of files) file.path = file.path.replace(/^[^\/]+\//, "/");
|
|
||||||
|
|
||||||
log(`Found ${files.length} files`);
|
|
||||||
|
|
||||||
await uploadFiles(files, signer, undefined, servers, relays);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
alert(`Failed to upload files: ${error.message}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
46
public/upload/index.html
Normal file
46
public/upload/index.html
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>nsite</title>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"blossom-client-sdk": "https://esm.run/blossom-client-sdk",
|
||||||
|
"nostr-tools": "https://esm.run/nostr-tools"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<label>relays</label>
|
||||||
|
<br />
|
||||||
|
<textarea type="text" id="relays" cols="50" rows="4"></textarea>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<label>blossom servers</label>
|
||||||
|
<br />
|
||||||
|
<textarea type="text" id="servers" cols="50" rows="4"></textarea>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<input type="file" id="files" webkitdirectory directory multiple />
|
||||||
|
<button id="upload-button">Upload nsite</button>
|
||||||
|
<div
|
||||||
|
id="log"
|
||||||
|
style="
|
||||||
|
max-height: 50em;
|
||||||
|
max-width: 80em;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid gray;
|
||||||
|
min-height: 8em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 0.8em;
|
||||||
|
gap: 0.1em;
|
||||||
|
white-space: pre;
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
<script type="module" src="./upload.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
142
public/upload/upload.js
Normal file
142
public/upload/upload.js
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import { multiServerUpload, BlossomClient } from "blossom-client-sdk";
|
||||||
|
import { SimplePool } from "nostr-tools";
|
||||||
|
|
||||||
|
const logContainer = document.getElementById("log");
|
||||||
|
function log(...args) {
|
||||||
|
const el = document.createElement("div");
|
||||||
|
el.innerText = args.join(" ");
|
||||||
|
logContainer.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadButton = document.getElementById("upload-button");
|
||||||
|
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const filesInput = document.getElementById("files");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {FileSystemFileEntry} fileEntry
|
||||||
|
* @returns {File}
|
||||||
|
*/
|
||||||
|
export function readFileSystemFile(fileEntry) {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
fileEntry.file(
|
||||||
|
(file) => res(file),
|
||||||
|
(err) => rej(err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {FileSystemDirectoryEntry} directory
|
||||||
|
* @returns {FileSystemEntry[]}
|
||||||
|
*/
|
||||||
|
export function readFileSystemDirectory(directory) {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
directory.createReader().readEntries(
|
||||||
|
(entries) => res(entries),
|
||||||
|
(err) => rej(err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uploads a file system entry to blossom servers
|
||||||
|
* @param {FileSystemEntry} entry
|
||||||
|
* @returns {{file: File, path: string, sha256: string}[]}
|
||||||
|
*/
|
||||||
|
async function readFileSystemEntry(entry) {
|
||||||
|
const files = [];
|
||||||
|
if (entry instanceof FileSystemFileEntry && entry.isFile) {
|
||||||
|
try {
|
||||||
|
const file = await readFileSystemFile(entry);
|
||||||
|
const sha256 = await BlossomClient.getFileSha256(file);
|
||||||
|
const path = entry.fullPath;
|
||||||
|
|
||||||
|
files.push({ file, path, sha256 });
|
||||||
|
} catch (e) {
|
||||||
|
log("Failed to add" + entry.fullPath);
|
||||||
|
log(e.message);
|
||||||
|
}
|
||||||
|
} else if (entry instanceof FileSystemDirectoryEntry && entry.isDirectory) {
|
||||||
|
const entries = await readFileSystemDirectory(entry);
|
||||||
|
for (const e of entries) files.push(...(await readFileSystemEntry(e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uploads a file system entry to blossom servers
|
||||||
|
* @param {FileList} list
|
||||||
|
* @returns {{file: File, path: string, sha256: string}[]}
|
||||||
|
*/
|
||||||
|
async function readFileList(list) {
|
||||||
|
const files = [];
|
||||||
|
for (const file of list) {
|
||||||
|
const path = file.webkitRelativePath ? file.webkitRelativePath : file.name;
|
||||||
|
const sha256 = await BlossomClient.getFileSha256(file);
|
||||||
|
files.push({ file, path, sha256 });
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pool = new SimplePool();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uploads a file system entry to blossom servers
|
||||||
|
* @param {{file:File, path:string}} files
|
||||||
|
* @param {import("blossom-client-sdk").Signer} signer
|
||||||
|
* @param {*} auth
|
||||||
|
* @param {string[]} servers
|
||||||
|
* @param {string[]} relays
|
||||||
|
*/
|
||||||
|
async function uploadFiles(files, signer, auth, servers, relays) {
|
||||||
|
for (const { file, path, sha256 } of files) {
|
||||||
|
try {
|
||||||
|
const upload = multiServerUpload(servers, file, signer, auth);
|
||||||
|
|
||||||
|
let published = false;
|
||||||
|
for await (let { blob } of upload) {
|
||||||
|
if (!published) {
|
||||||
|
const signed = await signer({
|
||||||
|
kind: 34128,
|
||||||
|
content: "",
|
||||||
|
created_at: Math.round(Date.now() / 1000),
|
||||||
|
tags: [
|
||||||
|
["d", path],
|
||||||
|
["x", sha256],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await pool.publish(relays, signed);
|
||||||
|
|
||||||
|
log("Published", path, sha256, signed.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
log(`Failed to upload ${path}`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadButton.addEventListener("click", async () => {
|
||||||
|
if (!window.nostr) return alert("Missing NIP-07 signer");
|
||||||
|
|
||||||
|
const signer = (draft) => window.nostr.signEvent(draft);
|
||||||
|
const relays = document.getElementById("relays").value.split(/\n|,/);
|
||||||
|
const servers = document.getElementById("servers").value.split(/\n|,/);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (filesInput.files) {
|
||||||
|
const files = await readFileList(filesInput.files);
|
||||||
|
|
||||||
|
// strip leading dir
|
||||||
|
for (const file of files) file.path = file.path.replace(/^[^\/]+\//, "/");
|
||||||
|
|
||||||
|
log(`Found ${files.length} files`);
|
||||||
|
|
||||||
|
await uploadFiles(files, signer, undefined, servers, relays);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Failed to upload files: ${error.message}`);
|
||||||
|
}
|
||||||
|
});
|
@ -1,6 +1,7 @@
|
|||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import xbytes from "xbytes";
|
import xbytes from "xbytes";
|
||||||
|
|
||||||
|
const LOOKUP_RELAYS = process.env.LOOKUP_RELAYS?.split(",") ?? ["wss://user.kindpag.es/", "wss://purplepag.es/"];
|
||||||
const NOSTR_RELAYS = process.env.NOSTR_RELAYS?.split(",") ?? [];
|
const NOSTR_RELAYS = process.env.NOSTR_RELAYS?.split(",") ?? [];
|
||||||
const BLOSSOM_SERVERS = process.env.BLOSSOM_SERVERS?.split(",") ?? [];
|
const BLOSSOM_SERVERS = process.env.BLOSSOM_SERVERS?.split(",") ?? [];
|
||||||
|
|
||||||
@ -9,6 +10,4 @@ const MAX_FILE_SIZE = process.env.MAX_FILE_SIZE ? xbytes.parseSize(process.env.M
|
|||||||
const NGINX_HOST = process.env.NGINX_HOST;
|
const NGINX_HOST = process.env.NGINX_HOST;
|
||||||
const CACHE_PATH = process.env.CACHE_PATH;
|
const CACHE_PATH = process.env.CACHE_PATH;
|
||||||
|
|
||||||
if (NOSTR_RELAYS.length === 0) throw new Error("Requires at least one relay in NOSTR_RELAYS");
|
export { NOSTR_RELAYS, LOOKUP_RELAYS, BLOSSOM_SERVERS, MAX_FILE_SIZE, NGINX_HOST, CACHE_PATH };
|
||||||
|
|
||||||
export { NOSTR_RELAYS, BLOSSOM_SERVERS, MAX_FILE_SIZE, NGINX_HOST, CACHE_PATH };
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { extname, isAbsolute, join } from "path";
|
import { extname, isAbsolute, join } from "path";
|
||||||
import { NSITE_KIND } from "./const.js";
|
import { NSITE_KIND } from "./const.js";
|
||||||
import ndk from "./ndk.js";
|
import ndk from "./ndk.js";
|
||||||
|
import { NDKRelaySet } from "@nostr-dev-kit/ndk";
|
||||||
|
|
||||||
export function getSearchPaths(path: string) {
|
export function getSearchPaths(path: string) {
|
||||||
const paths = [path];
|
const paths = [path];
|
||||||
@ -10,10 +11,10 @@ export function getSearchPaths(path: string) {
|
|||||||
|
|
||||||
// also look for relative paths
|
// also look for relative paths
|
||||||
for (const p of Array.from(paths)) {
|
for (const p of Array.from(paths)) {
|
||||||
if (isAbsolute(p)) paths.push(path.replace(/^\//, ""));
|
if (isAbsolute(p)) paths.push(p.replace(/^\//, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
return paths;
|
return paths.filter((p) => !!p);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseNsiteEvent(event: { pubkey: string; tags: string[][] }) {
|
export function parseNsiteEvent(event: { pubkey: string; tags: string[][] }) {
|
||||||
@ -28,9 +29,13 @@ export function parseNsiteEvent(event: { pubkey: string; tags: string[][] }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getNsiteBlobs(pubkey: string, path: string) {
|
export async function getNsiteBlobs(pubkey: string, path: string, relays?: string[]) {
|
||||||
const paths = getSearchPaths(path);
|
const paths = getSearchPaths(path);
|
||||||
const events = await ndk.fetchEvents({ kinds: [NSITE_KIND], "#d": paths, authors: [pubkey] });
|
const events = await ndk.fetchEvents(
|
||||||
|
{ kinds: [NSITE_KIND], "#d": paths, authors: [pubkey] },
|
||||||
|
{},
|
||||||
|
relays && NDKRelaySet.fromRelayUrls(relays, ndk, true),
|
||||||
|
);
|
||||||
|
|
||||||
return Array.from(events)
|
return Array.from(events)
|
||||||
.map(parseNsiteEvent)
|
.map(parseNsiteEvent)
|
||||||
|
15
src/index.ts
15
src/index.ts
@ -13,7 +13,8 @@ import { resolveNpubFromHostname } from "./helpers/dns.js";
|
|||||||
import { getNsiteBlobs } from "./events.js";
|
import { getNsiteBlobs } from "./events.js";
|
||||||
import { downloadFile, getUserBlossomServers } from "./blossom.js";
|
import { downloadFile, getUserBlossomServers } from "./blossom.js";
|
||||||
import { BLOSSOM_SERVERS } from "./env.js";
|
import { BLOSSOM_SERVERS } from "./env.js";
|
||||||
import { userServers } from "./cache.js";
|
import { userRelays, userServers } from "./cache.js";
|
||||||
|
import { getUserOutboxes } from "./ndk.js";
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
@ -49,8 +50,16 @@ app.use(async (ctx, next) => {
|
|||||||
const pubkey = (ctx.state.pubkey = await resolveNpubFromHostname(ctx.hostname));
|
const pubkey = (ctx.state.pubkey = await resolveNpubFromHostname(ctx.hostname));
|
||||||
|
|
||||||
if (pubkey) {
|
if (pubkey) {
|
||||||
|
console.log(`${pubkey}: Fetching relays`);
|
||||||
|
|
||||||
|
let relays = await userRelays.get<string[] | undefined>(pubkey);
|
||||||
|
if (!relays) {
|
||||||
|
relays = await getUserOutboxes(pubkey);
|
||||||
|
if (relays) await userRelays.set(pubkey, relays);
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`${pubkey}: Searching for ${ctx.path}`);
|
console.log(`${pubkey}: Searching for ${ctx.path}`);
|
||||||
const blobs = await getNsiteBlobs(pubkey, ctx.path);
|
const blobs = await getNsiteBlobs(pubkey, ctx.path, relays);
|
||||||
|
|
||||||
if (blobs.length === 0) {
|
if (blobs.length === 0) {
|
||||||
ctx.status = 404;
|
ctx.status = 404;
|
||||||
@ -58,7 +67,7 @@ app.use(async (ctx, next) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let servers = await userServers.get<string[]>(pubkey);
|
let servers = await userServers.get<string[] | undefined>(pubkey);
|
||||||
if (!servers) {
|
if (!servers) {
|
||||||
console.log(`${pubkey}: Searching for blossom servers`);
|
console.log(`${pubkey}: Searching for blossom servers`);
|
||||||
servers = (await getUserBlossomServers(pubkey)) ?? [];
|
servers = (await getUserBlossomServers(pubkey)) ?? [];
|
||||||
|
11
src/ndk.ts
11
src/ndk.ts
@ -1,10 +1,17 @@
|
|||||||
import NDK from "@nostr-dev-kit/ndk";
|
import NDK from "@nostr-dev-kit/ndk";
|
||||||
import { NOSTR_RELAYS } from "./env.js";
|
import { LOOKUP_RELAYS, NOSTR_RELAYS } from "./env.js";
|
||||||
|
|
||||||
const ndk = new NDK({
|
const ndk = new NDK({
|
||||||
explicitRelayUrls: NOSTR_RELAYS,
|
explicitRelayUrls: [...LOOKUP_RELAYS, ...NOSTR_RELAYS],
|
||||||
});
|
});
|
||||||
|
|
||||||
ndk.connect();
|
ndk.connect();
|
||||||
|
|
||||||
|
export async function getUserOutboxes(pubkey: string) {
|
||||||
|
const mailboxes = await ndk.fetchEvent({ kinds: [10002], authors: [pubkey] });
|
||||||
|
if (!mailboxes) return;
|
||||||
|
|
||||||
|
return mailboxes.tags.filter((t) => t[0] === "r" && (t[2] === undefined || t[2] === "write")).map((t) => t[1]);
|
||||||
|
}
|
||||||
|
|
||||||
export default ndk;
|
export default ndk;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user