Files
mintel.me/apps/web/scripts/check-og-images.ts
Marc Mintel 025906889c
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 2m4s
Build & Deploy / 🏗️ Build (push) Successful in 11m17s
Build & Deploy / 🚀 Deploy (push) Failing after 8s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
chore(ci): dynamic OG image verification with hash resilience
2026-03-02 10:48:26 +01:00

105 lines
2.9 KiB
TypeScript

const BASE_URL = process.env.TEST_URL || "http://localhost:3000";
console.log(`\n🚀 Starting Dynamic OG Image Verification for ${BASE_URL}\n`);
const pages = ["/", "/about", "/contact"];
async function getOgImageUrl(pagePath: string): Promise<string | null> {
const url = `${BASE_URL}${pagePath}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch page: ${response.status}`);
}
const html = await response.text();
// Extract og:image content
const match = html.match(/property="og:image"\s+content="([^"]+)"/);
if (!match || !match[1]) {
// Try name="twitter:image" as fallback or check if it's there
const twitterMatch = html.match(
/name="twitter:image"\s+content="([^"]+)"/,
);
return twitterMatch ? twitterMatch[1] : null;
}
return match[1];
} catch (error) {
console.error(` ❌ Failed to discover OG image for ${pagePath}:`, error);
return null;
}
}
async function verifyImage(
imageUrl: string,
pagePath: string,
): Promise<boolean> {
// If the image URL is absolute and contains mintel.me (base domain),
// we replace it with our BASE_URL to test the current environment's generated image
let testUrl = imageUrl;
if (imageUrl.startsWith("https://mintel.me")) {
testUrl = imageUrl.replace("https://mintel.me", BASE_URL);
} else if (imageUrl.startsWith("/")) {
testUrl = `${BASE_URL}${imageUrl}`;
}
const start = Date.now();
try {
const response = await fetch(testUrl);
const duration = Date.now() - start;
console.log(`Checking OG Image for ${pagePath}: ${testUrl}...`);
const body = await response.clone().text();
const contentType = response.headers.get("content-type");
if (response.status !== 200) {
throw new Error(`Status: ${response.status}`);
}
if (!contentType?.includes("image/")) {
throw new Error(`Content-Type: ${contentType}`);
}
const buffer = await response.arrayBuffer();
const bytes = new Uint8Array(buffer);
if (bytes.length < 1000) {
throw new Error(`Image too small (${bytes.length} bytes)`);
}
console.log(` ✅ OK (${bytes.length} bytes, ${duration}ms)`);
return true;
} catch (error: unknown) {
console.error(` ❌ FAILED:`, error);
return false;
}
}
async function run() {
let allOk = true;
for (const page of pages) {
console.log(`Discovering OG image for ${page}...`);
const ogUrl = await getOgImageUrl(page);
if (!ogUrl) {
console.error(` ❌ No OG image meta tag found for ${page}`);
allOk = false;
continue;
}
const ok = await verifyImage(ogUrl, page);
if (!ok) allOk = false;
}
if (allOk) {
console.log("\n✨ All OG images verified successfully!\n");
process.exit(0);
} else {
console.error("\n❌ Some OG images failed verification.\n");
process.exit(1);
}
}
run();