--- import Base from './Base.astro'; import TrackedProductLink from '../components/TrackedProductLink.astro'; import { coverWebpSources } from '../lib/cover-webp'; interface Props { title: string; description: string; metaTitle?: string; keywords?: string; pubDate: Date; modifiedDate?: Date; author?: string; authorUrl?: string; authorBio?: string; audience?: string; heroImage?: string; slug?: string; rawBody?: string; relatedPosts?: { title: string; description: string; href: string }[]; } const { title, description, metaTitle, keywords, pubDate, modifiedDate, author, authorUrl, authorBio, audience, heroImage, slug, rawBody, relatedPosts = [] } = Astro.props; function toAbsoluteWorldMonitorUrl(pathOrUrl: string | undefined): string | undefined { if (!pathOrUrl) return undefined; if (/^https?:\/\//.test(pathOrUrl)) return pathOrUrl; return new URL(pathOrUrl, 'https://www.worldmonitor.app').href; } const ogImage = toAbsoluteWorldMonitorUrl(heroImage || (slug ? `/blog/images/blog/${slug}.jpg` : undefined)); const canonicalUrl = slug ? `https://www.worldmonitor.app/blog/posts/${slug}/` : new URL(Astro.url.pathname, 'https://www.worldmonitor.app').href; const formattedDate = pubDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', }); const isoDate = pubDate.toISOString(); const isoModifiedDate = modifiedDate ? modifiedDate.toISOString() : isoDate; const DEFAULT_AUTHOR = 'Elie Habib'; const DEFAULT_AUTHOR_URL = 'https://www.worldmonitor.app/blog/authors/elie-habib/'; const DEFAULT_AUTHOR_ID = `${DEFAULT_AUTHOR_URL}#person`; const DEFAULT_AUTHOR_BIO = 'Founder of World Monitor. Previously co-founder & CEO of Anghami (NASDAQ: ANGH). Building open-source global intelligence infrastructure.'; const DEFAULT_AUTHOR_GITHUB = 'koala73'; const DEFAULT_SECTION = 'Global Intelligence'; const authorName = author || DEFAULT_AUTHOR; const resolvedAuthorUrl = authorUrl || (authorName === DEFAULT_AUTHOR ? DEFAULT_AUTHOR_URL : undefined); const resolvedAuthorBio = authorBio || (authorName === DEFAULT_AUTHOR ? DEFAULT_AUTHOR_BIO : undefined); const avatarSrc = authorName === DEFAULT_AUTHOR ? `https://unavatar.io/github/${DEFAULT_AUTHOR_GITHUB}` : '/favico/apple-touch-icon.png'; // Committed covers have generated .webp / -640.webp siblings (guarded by // tests/blog-cover-webp.test.mjs); coverWebpSources() returns null when the // siblings don't exist (e.g. deploy-generated /blog/og/*.png covers). const heroWebp = coverWebpSources(heroImage); const showUpdated = modifiedDate && modifiedDate.getTime() !== pubDate.getTime(); const formattedModifiedDate = modifiedDate ? modifiedDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }) : ''; const wordCount = rawBody ? rawBody.trim().split(/\s+/).filter(Boolean).length : undefined; const readingMinutes = wordCount ? Math.max(1, Math.ceil(wordCount / 220)) : undefined; function extractCitations(body: string | undefined): { "@type": string; name: string; url: string }[] { if (!body) return []; const citations: { "@type": string; name: string; url: string }[] = []; const seen = new Set(); const linkRegex = /\[([^\]]+)\]\((https?:\/\/[^\s)]+)(?:\s+"[^"]*")?\)/g; let match: RegExpExecArray | null; while ((match = linkRegex.exec(body)) !== null) { const url = match[2]; const host = new URL(url).hostname.replace(/^www\./, ''); if (host === 'worldmonitor.app' || host.endsWith('.worldmonitor.app') || seen.has(url)) continue; seen.add(url); citations.push({ "@type": "CreativeWork", "name": match[1].replace(/[*_`]/g, '').trim(), "url": url }); } return citations; } const citations = extractCitations(rawBody); const breadcrumbLd = { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Blog", "item": "https://www.worldmonitor.app/blog/" }, { "@type": "ListItem", "position": 2, "name": title, "item": canonicalUrl } ] }; const jsonLd = { "@context": "https://schema.org", "@type": "BlogPosting", "@id": `${canonicalUrl}#article`, "headline": title, ...(metaTitle && metaTitle !== title ? { "alternativeHeadline": metaTitle } : {}), "description": description, "datePublished": isoDate, "dateModified": isoModifiedDate, "inLanguage": "en-US", "isAccessibleForFree": true, "articleSection": DEFAULT_SECTION, ...(audience ? { "audience": { "@type": "Audience", "audienceType": audience } } : {}), ...(wordCount ? { "wordCount": wordCount } : {}), ...(readingMinutes ? { "timeRequired": `PT${readingMinutes}M` } : {}), "author": { "@type": "Person", "name": authorName, ...(resolvedAuthorUrl ? { "url": resolvedAuthorUrl } : {}), ...(authorName === DEFAULT_AUTHOR ? { "@id": DEFAULT_AUTHOR_ID, "sameAs": [ "https://x.com/eliehabib", `https://github.com/${DEFAULT_AUTHOR_GITHUB}` ] } : {}) }, "publisher": { "@type": "Organization", "@id": "https://www.worldmonitor.app/#organization", "name": "World Monitor", "url": "https://www.worldmonitor.app", "sameAs": [ "https://github.com/koala73/worldmonitor", "https://x.com/worldmonitorai" ], "logo": { "@type": "ImageObject", "url": "https://www.worldmonitor.app/favico/apple-touch-icon.png" } }, "mainEntityOfPage": { "@type": "WebPage", "@id": canonicalUrl }, "image": ogImage || "https://www.worldmonitor.app/favico/og-image.png", "url": canonicalUrl, "isPartOf": { "@type": "Blog", "@id": "https://www.worldmonitor.app/blog/#blog", "name": "World Monitor Blog", "url": "https://www.worldmonitor.app/blog/" }, ...(citations.length > 0 ? { "citation": citations } : {}), ...(keywords ? { "keywords": keywords } : {}) }; function extractFaqLd(body: string | undefined): object | null { if (!body) return null; const faqIdx = body.indexOf('## Frequently Asked Questions'); if (faqIdx === -1) return null; const afterFaq = body.slice(faqIdx + '## Frequently Asked Questions'.length); // The FAQ section ends at the next H2 OR at a horizontal rule — nearly // every post closes its FAQ with `---` followed by a bold takeaway/CTA // paragraph, which must not be extracted as a Question. const nextHeading = afterFaq.search(/\n##\s|\n---\s*\n/); const faqSection = nextHeading === -1 ? afterFaq : afterFaq.slice(0, nextHeading); // \n+ (not \n): every post writes a blank line between the bolded question // and its answer — with a single \n the regex matched nothing and NO post // ever emitted FAQPage JSON-LD (#5001). Guarded against the real post // corpus by tests/blog-faq-ld.test.mjs. const qaRegex = /\*\*(.+?)\*\*\n+([^\n*]+(?:\n[^\n*#]+)*)/g; const items: { "@type": string; name: string; acceptedAnswer: { "@type": string; text: string } }[] = []; let match: RegExpExecArray | null; while ((match = qaRegex.exec(faqSection)) !== null) { const q = match[1].trim(); const a = match[2].replace(/\[([^\]]+)\]\([^)]+\)/g, '$1').trim(); if (q && a) items.push({ "@type": "Question", name: q, acceptedAnswer: { "@type": "Answer", text: a } }); } if (items.length === 0) return null; return { "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": items }; } const faqLd = extractFaqLd(rawBody); ---
← All articles
{showUpdated && · Updated } {audience && · {audience}}
{heroImage && ( {heroWebp && ( )} {title} )}

{title}

{description}

{relatedPosts.length > 0 && ( )}

Put the Intelligence to Work

Open the live dashboard free, or explore Pro for deeper analyst workflows, alerts, and AI research.

Open Dashboard Explore Pro
{authorName}
{resolvedAuthorUrl ? : {authorName} }
{resolvedAuthorBio &&
}