mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
[og] Route crawlers via middleware, not a rewrite
The OG function deployed and worked (`/api/og?v=<nevent>` returns the real title, description, thumbnail and player card), but crawlers hitting `/?v=<nevent>` still got the site-wide card: Vercel evaluates `rewrites` AFTER the filesystem, and `/` matches the static index.html, so the rewrite never fired. Middleware runs before the filesystem check, so that is where the routing belongs. Replace the dead `rewrites` block with a root middleware that matches only `/`, bails immediately when there is no `v` param or the user-agent is not a known preview crawler, and otherwise rewrites to /api/og. Real viewers are unaffected -- they fall through to the untouched SPA. Note the one behavioral difference from the rewrite design: middleware now executes on homepage requests (matcher is `/` only) rather than being invoked solely for crawlers. It returns next() after two cheap checks. Verified on the live unstable deployment that /api/og already renders `x-bitvid-og: video` with og:type video.other for the real note; this only fixes how crawlers reach it. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
e5784893a8
commit
04075ff56b
4 files changed
+63
-17
No files matched your search
@@ -0,0 +1,43 @@
|
||||
// Routes crawler requests for `/?v=<nevent>` to the per-video OpenGraph
|
||||
// renderer (api/og.js).
|
||||
//
|
||||
// This has to be middleware rather than a `rewrites` entry in vercel.json:
|
||||
// rewrites are evaluated AFTER the filesystem, and `/` matches the static
|
||||
// index.html, so the rewrite never fired and crawlers kept getting the
|
||||
// site-wide card. Middleware runs before the filesystem check.
|
||||
//
|
||||
// Deliberately minimal. It matches only `/`, bails immediately when there is no
|
||||
// `v` param or the visitor is not a known preview crawler, and never touches
|
||||
// the response for a real viewer — they continue to the untouched SPA. If this
|
||||
// file is removed the site keeps working, just with the generic card.
|
||||
|
||||
import { next, rewrite } from "@vercel/edge";
|
||||
import { isCrawlerUserAgent } from "./api/_lib/ogRenderer.mjs";
|
||||
|
||||
export const config = {
|
||||
// Only the share-link path. Every other route skips middleware entirely.
|
||||
matcher: "/",
|
||||
};
|
||||
|
||||
export default function middleware(request) {
|
||||
let url;
|
||||
try {
|
||||
url = new URL(request.url);
|
||||
} catch (err) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// A bare homepage visit is not a share link.
|
||||
if (!url.searchParams.get("v")) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const userAgent = request.headers?.get?.("user-agent") || "";
|
||||
if (!isCrawlerUserAgent(userAgent)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const target = new URL(url.toString());
|
||||
target.pathname = "/api/og";
|
||||
return rewrite(target);
|
||||
}
|
||||
Generated
+7
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.4",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@vercel/edge": "^1.3.1",
|
||||
"autoprefixer": "^10.4.24",
|
||||
"cross-env": "^10.1.0",
|
||||
"esbuild": "^0.27.3",
|
||||
@@ -1478,6 +1479,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vercel/edge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.3.1.tgz",
|
||||
"integrity": "sha512-k0tKWeYEWOv6qU6+Z8+hv2Nt/u3vFHRZdB0uvwE0DxoddU/5kWX/Chu8F6ojvqmRlnZwuX/7kyZFVeCP6DxqBg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz",
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.4",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@vercel/edge": "^1.3.1",
|
||||
"autoprefixer": "^10.4.24",
|
||||
"cross-env": "^10.1.0",
|
||||
"esbuild": "^0.27.3",
|
||||
|
||||
+12
-17
@@ -7,37 +7,32 @@
|
||||
"unstable": true
|
||||
}
|
||||
},
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/",
|
||||
"has": [
|
||||
{ "type": "query", "key": "v" },
|
||||
{
|
||||
"type": "header",
|
||||
"key": "user-agent",
|
||||
"value": ".*(facebookexternalhit|Twitterbot|Slackbot|Discordbot|TelegramBot|WhatsApp|LinkedInBot|Pinterest|redditbot|Embedly|Iframely|Mastodon|Bluesky|SkypeUriPreview|vkShare|Googlebot|bingbot|Applebot|YandexBot|DuckDuckBot|Baiduspider|PetalBot|primal).*"
|
||||
}
|
||||
],
|
||||
"destination": "/api/og"
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"source": "/sw.min.js",
|
||||
"headers": [
|
||||
{ "key": "Cache-Control", "value": "no-cache, must-revalidate" }
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "no-cache, must-revalidate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/",
|
||||
"headers": [
|
||||
{ "key": "Cache-Control", "value": "no-cache, must-revalidate" }
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "no-cache, must-revalidate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/(.*\\.html)",
|
||||
"headers": [
|
||||
{ "key": "Cache-Control", "value": "no-cache, must-revalidate" }
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "no-cache, must-revalidate"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user