refactor: address maintainer feedback on routing logic and env fallbacks

This commit is contained in:
2026-04-30 13:10:08 +05:30
committed by hodlbod
parent e380e4e3d6
commit faf1b02a2c
+107 -43
View File
@@ -2,9 +2,10 @@ import path from "node:path"
import {promises as fs} from "node:fs" import {promises as fs} from "node:fs"
import {fileURLToPath} from "node:url" import {fileURLToPath} from "node:url"
import "dotenv/config"
import {serve} from "@hono/node-server" import {serve} from "@hono/node-server"
import {serveStatic} from "@hono/node-server/serve-static" import {serveStatic} from "@hono/node-server/serve-static"
import {fetchRelay} from "@welshman/app" import {loadRelay} from "@welshman/app"
import {displayRelayUrl, normalizeRelayUrl} from "@welshman/util" import {displayRelayUrl, normalizeRelayUrl} from "@welshman/util"
import {load} from "cheerio" import {load} from "cheerio"
import {Hono} from "hono" import {Hono} from "hono"
@@ -26,15 +27,8 @@ try {
process.exit(1) process.exit(1)
} }
const TEMPLATE_DOCUMENT = load(TEMPLATE_HTML) const PLATFORM_NAME = process.env.VITE_PLATFORM_NAME
const DEFAULT_PLATFORM_NAME = const PLATFORM_DESCRIPTION = process.env.VITE_PLATFORM_DESCRIPTION
process.env.VITE_PLATFORM_NAME ||
TEMPLATE_DOCUMENT('meta[property="og:title"]').attr("content") ||
"Flotilla"
const DEFAULT_PLATFORM_DESCRIPTION =
process.env.VITE_PLATFORM_DESCRIPTION ||
TEMPLATE_DOCUMENT('meta[name="description"]').attr("content") ||
"Flotilla is nostr - for communities."
// Match client-side decode logic // Match client-side decode logic
const decodeRelay = url => { const decodeRelay = url => {
@@ -61,71 +55,141 @@ const requestUrlFromContext = context => {
return requestUrl return requestUrl
} }
const resolveMetadata = async requestUrl => { const fetchRelayMeta = async relayUrl => {
const pathname = requestUrl.pathname if (!relayUrl) return undefined
let relayParam = undefined
// Match /join?r=...
if (pathname === "/join" || pathname === "/join/") {
relayParam = requestUrl.searchParams.get("r")
}
// Match /spaces/:relay/...
else if (pathname.startsWith("/spaces/")) {
const parts = pathname.split("/").filter(Boolean)
if (parts.length >= 2) {
relayParam = decodeRelay(parts[1])
}
}
if (!relayParam) {
return undefined
}
try { try {
// Note: fetchRelay from @welshman/app handles the ws->http conversion and caching return await loadRelay(normalizeRelayUrl(relayUrl))
const relayMetadata = await fetchRelay(normalizeRelayUrl(relayParam)) } catch (err) {
console.error(`Failed to fetch relay metadata for ${relayUrl}:`, err)
if (!relayMetadata) {
return undefined return undefined
} }
}
const buildDefaultImage = requestUrl => {
return new URL("/maskable-icon-512x512.png", requestUrl.origin).toString()
}
const getMetadataForInvite = async (url, match) => {
const relayParam = url.searchParams.get("r")
if (!relayParam) return undefined
const relayMetadata = await fetchRelayMeta(relayParam)
if (!relayMetadata) return undefined
const relayDisplay = displayRelayUrl(relayParam) const relayDisplay = displayRelayUrl(relayParam)
const spaceName = relayMetadata.name const spaceName = relayMetadata.name
const relayDescription = relayMetadata.description const relayDescription = relayMetadata.description
const title = spaceName const title = spaceName
? `Invite to ${spaceName} on ${DEFAULT_PLATFORM_NAME}` ? `Invite to ${spaceName} on ${PLATFORM_NAME}`
: `Invite to a Space on ${DEFAULT_PLATFORM_NAME}` : `Invite to a Space on ${PLATFORM_NAME}`
const parts = [] const parts = []
if (spaceName) { if (spaceName) {
parts.push(`You are invited to join ${spaceName} on ${DEFAULT_PLATFORM_NAME}.`) parts.push(`You are invited to join ${spaceName} on ${PLATFORM_NAME}.`)
} else { } else {
parts.push(`You are invited to join a space on ${DEFAULT_PLATFORM_NAME}.`) parts.push(`You are invited to join a space on ${PLATFORM_NAME}.`)
} }
if (relayDisplay) parts.push(`Relay: ${relayDisplay}.`) if (relayDisplay) parts.push(`Relay: ${relayDisplay}.`)
if (relayDescription) parts.push(relayDescription) if (relayDescription) parts.push(relayDescription)
else parts.push(DEFAULT_PLATFORM_DESCRIPTION) else parts.push(PLATFORM_DESCRIPTION)
const description = parts.join(" ") const description = parts.join(" ")
const image = const image =
relayMetadata.icon || relayMetadata.icon ||
relayMetadata.picture || relayMetadata.picture ||
relayMetadata.image || relayMetadata.image ||
new URL("/maskable-icon-512x512.png", requestUrl.origin).toString() buildDefaultImage(url)
return { return {
title, title,
description, description,
image, image,
url: requestUrl.toString(), url: url.toString(),
site: requestUrl.origin, site: url.origin,
} }
}
const getMetadataForSpace = async (url, match) => {
const relayParam = decodeRelay(match[1])
if (!relayParam) return undefined
const relayMetadata = await fetchRelayMeta(relayParam)
if (!relayMetadata) return undefined
const spaceName = relayMetadata.name || displayRelayUrl(relayParam)
return {
title: `${spaceName} on ${PLATFORM_NAME}`,
description: relayMetadata.description || PLATFORM_DESCRIPTION,
image:
relayMetadata.icon ||
relayMetadata.picture ||
relayMetadata.image ||
buildDefaultImage(url),
url: url.toString(),
site: url.origin,
}
}
const getMetadataForSpaceSection = async (url, match) => {
const spaceMeta = await getMetadataForSpace(url, match)
if (!spaceMeta) return undefined
const section = match[2]
const sectionName = section.charAt(0).toUpperCase() + section.slice(1)
spaceMeta.title = `${sectionName} on ${spaceMeta.title}`
return spaceMeta
}
const getMetadataForSpaceItem = async (url, match) => {
const spaceMeta = await getMetadataForSpace(url, match)
if (!spaceMeta) return undefined
const section = match[2]
let itemType = "Item"
if (section === "calendar") itemType = "Event"
if (section === "threads") itemType = "Thread"
if (section === "polls") itemType = "Poll"
if (section === "goals") itemType = "Goal"
if (section === "classifieds") itemType = "Listing"
spaceMeta.title = `${itemType} on ${spaceMeta.title}`
return spaceMeta
}
const getMetadataForRoom = async (url, match) => {
const spaceMeta = await getMetadataForSpace(url, match)
if (!spaceMeta) return undefined
// Room metadata requires fetching from Nostr, which can be added later.
spaceMeta.title = `Room on ${spaceMeta.title}`
return spaceMeta
}
const routes = [
[/^\/join\/?$/, getMetadataForInvite],
[/^\/spaces\/([^/]+)\/(calendar|chat|threads|polls|goals|classifieds|recent)\/?$/, getMetadataForSpaceSection],
[/^\/spaces\/([^/]+)\/(calendar|threads|polls|goals|classifieds)\/([^/]+)\/?$/, getMetadataForSpaceItem],
[/^\/spaces\/([^/]+)\/([^/]+)\/?$/, getMetadataForRoom],
[/^\/spaces\/([^/]+)\/?$/, getMetadataForSpace],
]
const getMetadataForRoute = async url => {
for (const [regex, getMetadata] of routes) {
const match = url.pathname.match(regex)
if (match) {
try {
return await getMetadata(url, match)
} catch (err) { } catch (err) {
console.error(`Error generating metadata for route ${url.pathname}:`, err)
return undefined return undefined
} }
} }
}
return undefined
}
const injectMeta = metadata => { const injectMeta = metadata => {
const $ = load(TEMPLATE_HTML) const $ = load(TEMPLATE_HTML)
@@ -196,7 +260,7 @@ app.get("*", async context => {
return context.text("Not found", 404) return context.text("Not found", 404)
} }
const metadata = await resolveMetadata(requestUrl) const metadata = await getMetadataForRoute(requestUrl)
const html = metadata ? injectMeta(metadata) : TEMPLATE_HTML const html = metadata ? injectMeta(metadata) : TEMPLATE_HTML
return context.html(html, 200, { return context.html(html, 200, {