Tell search engines and link previews what each page is
- /sitemap.xml, from the API's /slugs plus the landing and listings: every address in every language, with hreflang and x-default. A 503 when the API is down, rather than a sitemap missing half the site. - /robots.txt, naming the sitemap on whatever domain this is served on. - Slugs renamed in the panel now redirect. The API has always kept the old address the moment one changed; middleware/redirects.ts answers it with a 301, from a list kept for a minute and through outages. - og:url, og:image (the record's own picture, the logo otherwise) and schema.org JSON-LD: Organization on the landing; WebPage, CreativeWork, Person or Service elsewhere. Shared through core/head. - The proxy-derived origin moves to core/origin.ts, used by the page shell, the landing and both server routes. In development only /api/* reaches Nitro, so the two files 404 under `npm start`; they were checked against a production build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
27
landing/src/app/core/origin.ts
Normal file
27
landing/src/app/core/origin.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* The origin a visitor used, as the reverse proxy in front of this app reports
|
||||
* it. Absolute URLs — `canonical`, `hreflang`, the sitemap, `og:image` — need
|
||||
* one, and this app has no configured address of its own: it answers on
|
||||
* whichever domain the proxy sends it.
|
||||
*/
|
||||
export type HeaderBag = Record<string, string | string[] | undefined>;
|
||||
|
||||
export function originFromHeaders(
|
||||
headers: HeaderBag | undefined,
|
||||
): string | null {
|
||||
if (!headers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const first = (value: string | string[] | undefined) =>
|
||||
(Array.isArray(value) ? value[0] : value)?.split(',')[0]?.trim();
|
||||
|
||||
const host = first(headers['x-forwarded-host']) ?? first(headers['host']);
|
||||
// Behind the proxy the header is always there; without one this is a
|
||||
// developer's own machine, which does not speak TLS.
|
||||
const protocol =
|
||||
first(headers['x-forwarded-proto']) ??
|
||||
(/^(localhost|127\.)/.test(host ?? '') ? 'http' : 'https');
|
||||
|
||||
return host ? `${protocol}://${host}` : null;
|
||||
}
|
||||
Reference in New Issue
Block a user