fix(metadata): add case-insensitive HTML title fallback parsing for invite links #248
Reference in New Issue
Block a user
Delete Branch "Khushvendra/flotilla:issue/131-invite-link-preview"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Description
This PR implements dynamic, server-side invite link previews for Flotilla Spaces. By introducing a lightweight Node.js server (
server.js) to serve the built application, we can now dynamically intercept/joinroutes and inject rich OpenGraph (OG) and Twitter card metadata.Previously, invite links to spaces resulted in generic, static previews. Now, when a user shares a space invite link (e.g.,
.../join?r=relay.scuttle.works&c=...), the server will probe the relay's metadata on the fly and populate the preview card with the relay's specific name, description, and icon.Key Changes
server.jsto serve the frontend while dynamically generating and injecting SEO/OG metadata for/joininvite URLs.application/nostr+json).relay.scuttle.works). The server safely parses the HTML text to extract<title>,<meta description>, and various icon links (og:image,twitter:image, or<link rel="icon">).package.jsonand theDockerfileto usenode server.jsas the main start command instead of a static server.app.html.Testing / Validation
<title>and icons.pnpm run check).Closes #131
I think we're doing way too much manually here, look into using hono.js for the server so that we can serve static files more simply without faffing around with mime types. The only file we need to modify is index.html, so see if you can add middleware that does that. Also, use an html parsing library like cheerio to modify the html rather than regular expressions. I believe cheerio will handle sanitization too. Use welshman library functions for fetching relay information.
@@ -0,0 +468,4 @@if (existingHead.length > 0) {return existingHead}This PR is full of just in case things like this, why do we need so much verbose stuff when we have full control over the html template? Just assume it's there, because it is. This would cut the PR in half at least.
@@ -0,0 +536,4 @@}const renderIndex = async requestUrl => {if (!isJoinInvitePath(requestUrl.pathname)) {The invite path isn't the only one we need to render. This file should cover pretty much anything: calendar events, polls, chat rooms, etc. We might not always be able to fetch the data, but we should try to render it. Continuing with the current approach will result in 2k LOC probably; if we import @welshman/app, it will make all of it much easier (and solve caching at the same time).
i have tried this, did decrease the LOC by ~75%. Also have made the corresponding changes according to you feed back. Lmk if you think there could be more improvements?
@hodlbod Does this align with what you mentioned?
Looks better, but still a ways to go. See comments above.
@@ -0,0 +34,4 @@const DEFAULT_PLATFORM_DESCRIPTION =process.env.VITE_PLATFORM_DESCRIPTION ||TEMPLATE_DOCUMENT('meta[name="description"]').attr("content") ||"Flotilla is nostr - for communities."These will always be defined (because .env is checked in to version control), no need for a fallback
@@ -0,0 +75,4 @@if (parts.length >= 2) {relayParam = decodeRelay(parts[1])}}This routing logic is still incomplete and is pretty brittle. We should do something like this:
This way it's clear which function is responsible for which route. Common utilities can be factored out (e.g. relay fetching, relay title generation, etc).
@@ -0,0 +124,4 @@}} catch (err) {return undefined}We should not be swallowing errors, add a console.error statement here
@hodlbod Addressed the issues you pointed out, also i swapped out fetchRelay with loadRelay (also imported directly from @welshman/app)
f938bec632tofaf1b02a2c