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
+126 -62
View File
@@ -2,9 +2,10 @@ import path from "node:path"
import {promises as fs} from "node:fs"
import {fileURLToPath} from "node:url"
import "dotenv/config"
import {serve} from "@hono/node-server"
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 {load} from "cheerio"
import {Hono} from "hono"
@@ -26,15 +27,8 @@ try {
process.exit(1)
}
const TEMPLATE_DOCUMENT = load(TEMPLATE_HTML)
const DEFAULT_PLATFORM_NAME =
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."
const PLATFORM_NAME = process.env.VITE_PLATFORM_NAME
const PLATFORM_DESCRIPTION = process.env.VITE_PLATFORM_DESCRIPTION
// Match client-side decode logic
const decodeRelay = url => {
@@ -61,72 +55,142 @@ const requestUrlFromContext = context => {
return requestUrl
}
const resolveMetadata = async requestUrl => {
const pathname = requestUrl.pathname
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) {
const fetchRelayMeta = async relayUrl => {
if (!relayUrl) return undefined
try {
return await loadRelay(normalizeRelayUrl(relayUrl))
} catch (err) {
console.error(`Failed to fetch relay metadata for ${relayUrl}:`, err)
return undefined
}
}
try {
// Note: fetchRelay from @welshman/app handles the ws->http conversion and caching
const relayMetadata = await fetchRelay(normalizeRelayUrl(relayParam))
const buildDefaultImage = requestUrl => {
return new URL("/maskable-icon-512x512.png", requestUrl.origin).toString()
}
if (!relayMetadata) {
return undefined
}
const getMetadataForInvite = async (url, match) => {
const relayParam = url.searchParams.get("r")
if (!relayParam) return undefined
const relayDisplay = displayRelayUrl(relayParam)
const spaceName = relayMetadata.name
const relayDescription = relayMetadata.description
const relayMetadata = await fetchRelayMeta(relayParam)
if (!relayMetadata) return undefined
const title = spaceName
? `Invite to ${spaceName} on ${DEFAULT_PLATFORM_NAME}`
: `Invite to a Space on ${DEFAULT_PLATFORM_NAME}`
const relayDisplay = displayRelayUrl(relayParam)
const spaceName = relayMetadata.name
const relayDescription = relayMetadata.description
const parts = []
if (spaceName) {
parts.push(`You are invited to join ${spaceName} on ${DEFAULT_PLATFORM_NAME}.`)
} else {
parts.push(`You are invited to join a space on ${DEFAULT_PLATFORM_NAME}.`)
}
const title = spaceName
? `Invite to ${spaceName} on ${PLATFORM_NAME}`
: `Invite to a Space on ${PLATFORM_NAME}`
if (relayDisplay) parts.push(`Relay: ${relayDisplay}.`)
if (relayDescription) parts.push(relayDescription)
else parts.push(DEFAULT_PLATFORM_DESCRIPTION)
const parts = []
if (spaceName) {
parts.push(`You are invited to join ${spaceName} on ${PLATFORM_NAME}.`)
} else {
parts.push(`You are invited to join a space on ${PLATFORM_NAME}.`)
}
const description = parts.join(" ")
const image =
if (relayDisplay) parts.push(`Relay: ${relayDisplay}.`)
if (relayDescription) parts.push(relayDescription)
else parts.push(PLATFORM_DESCRIPTION)
const description = parts.join(" ")
const image =
relayMetadata.icon ||
relayMetadata.picture ||
relayMetadata.image ||
buildDefaultImage(url)
return {
title,
description,
image,
url: url.toString(),
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 ||
new URL("/maskable-icon-512x512.png", requestUrl.origin).toString()
return {
title,
description,
image,
url: requestUrl.toString(),
site: requestUrl.origin,
}
} catch (err) {
return undefined
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) {
console.error(`Error generating metadata for route ${url.pathname}:`, err)
return undefined
}
}
}
return undefined
}
const injectMeta = metadata => {
const $ = load(TEMPLATE_HTML)
@@ -196,7 +260,7 @@ app.get("*", async context => {
return context.text("Not found", 404)
}
const metadata = await resolveMetadata(requestUrl)
const metadata = await getMetadataForRoute(requestUrl)
const html = metadata ? injectMeta(metadata) : TEMPLATE_HTML
return context.html(html, 200, {