fix favicon delivery and cache invalidation
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { ImageResponse } from "next/og";
|
||||
|
||||
import { routing } from "@/i18n/routing";
|
||||
|
||||
import { getSiteSettings, getSiteSettingsMediaBindings } from "./app-config";
|
||||
|
||||
const INTERNAL_FAVICON_PATH = "/favicon.ico";
|
||||
const INTERNAL_APPLE_ICON_PATH = "/apple-icon.png";
|
||||
const INTERNAL_MANIFEST_PATH = "/manifest.webmanifest";
|
||||
const DEFAULT_ICON_VERSION = "default";
|
||||
|
||||
type SiteIconInput = {
|
||||
siteName: string;
|
||||
faviconAssetId?: string | null;
|
||||
faviconUrl?: string | null;
|
||||
};
|
||||
|
||||
type SiteIconUrls = {
|
||||
siteName: string;
|
||||
version: string;
|
||||
faviconHref: string;
|
||||
appleIconHref: string;
|
||||
manifestHref: string;
|
||||
faviconAssetUrl: string | null;
|
||||
};
|
||||
|
||||
function appendVersionToUrl(url: string, version: string): string {
|
||||
const base = url.startsWith("http://") || url.startsWith("https://") ? undefined : "https://local.invalid";
|
||||
const resolved = new URL(url, base);
|
||||
|
||||
resolved.searchParams.set("v", version);
|
||||
|
||||
if (base) {
|
||||
return `${resolved.pathname}${resolved.search}${resolved.hash}`;
|
||||
}
|
||||
|
||||
return resolved.toString();
|
||||
}
|
||||
|
||||
function getFallbackLabel(siteName: string): string {
|
||||
const firstCharacter = siteName.trim().charAt(0).toUpperCase() || "M";
|
||||
|
||||
return firstCharacter;
|
||||
}
|
||||
|
||||
export function buildSiteIconUrls(input: SiteIconInput): SiteIconUrls {
|
||||
const siteName = input.siteName.trim() || "Moh";
|
||||
const version = input.faviconAssetId?.trim() || DEFAULT_ICON_VERSION;
|
||||
|
||||
return {
|
||||
siteName,
|
||||
version,
|
||||
faviconHref: appendVersionToUrl(INTERNAL_FAVICON_PATH, version),
|
||||
appleIconHref: appendVersionToUrl(INTERNAL_APPLE_ICON_PATH, version),
|
||||
manifestHref: appendVersionToUrl(INTERNAL_MANIFEST_PATH, version),
|
||||
faviconAssetUrl: input.faviconUrl ? appendVersionToUrl(input.faviconUrl, version) : null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getDynamicSiteIconUrls(): Promise<SiteIconUrls> {
|
||||
const [settings, bindings] = await Promise.all([getSiteSettings(), getSiteSettingsMediaBindings()]);
|
||||
const defaultLocaleSettings = settings.locales[routing.defaultLocale];
|
||||
|
||||
return buildSiteIconUrls({
|
||||
siteName: defaultLocaleSettings.siteName,
|
||||
faviconAssetId: bindings.favicon?.assetId,
|
||||
faviconUrl: bindings.favicon?.url,
|
||||
});
|
||||
}
|
||||
|
||||
export function buildFallbackIconResponse(siteName: string, size: number) {
|
||||
const label = getFallbackLabel(siteName);
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
background: "linear-gradient(135deg, #111827 0%, #0f766e 100%)",
|
||||
color: "#f8fafc",
|
||||
fontSize: size * 0.52,
|
||||
fontWeight: 700,
|
||||
letterSpacing: "-0.08em",
|
||||
borderRadius: size * 0.22,
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
),
|
||||
{
|
||||
width: size,
|
||||
height: size,
|
||||
headers: {
|
||||
"Cache-Control": "no-store, max-age=0",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user