@asteroidcms/core-utils 0.1.8 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/next.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/cmsImage.ts","../src/seo/seo.builders.ts","../src/seo/next.tsx"],"names":["Head","jsx"],"mappings":"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","file":"next.cjs","sourcesContent":["import { useAsteroidCMSConfig } from \"../provider/context\";\n\n/**\n * Build a canonical media URL from an asset id. Pass `cmsUrl` explicitly when\n * calling outside of React (e.g. SSR loaders, scripts). Inside components,\n * prefer `useCmsImage()`.\n */\nexport function cmsImage(\n id: string | undefined,\n options: { cmsUrl: string; mediaPath?: string },\n): string {\n if (!id) return \"\";\n const base = options.cmsUrl.replace(/\\/+$/, \"\");\n const path = (options.mediaPath ?? \"/media/canonical\").replace(/^\\/?/, \"/\");\n return `${base}${path}/${id}`;\n}\n\n/** Hook variant that pulls `cmsUrl`/`mediaPath` from the provider. */\nexport function useCmsImage(): (id?: string) => string {\n const { cmsUrl, mediaPath } = useAsteroidCMSConfig();\n return (id?: string) => cmsImage(id, { cmsUrl, mediaPath });\n}\n","// Pure builders that turn CMS posts + config into SEO values. Server-safe.\n\nimport { cmsImage } from \"../utils/cmsImage\";\nimport type {\n AsteroidOgImageParams,\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n SeoClientProps,\n} from \"./seo.config\";\n\n/** Apply the configured title template, defaulting to `${title} | ${siteName}`. */\nexport function applyTitleTemplate(\n config: AsteroidSeoConfig,\n title: string,\n): string {\n return config.titleTemplate\n ? config.titleTemplate(title)\n : `${title} | ${config.siteName}`;\n}\n\nexport function buildOgImageUrl(\n config: AsteroidSeoConfig,\n params: AsteroidOgImageParams,\n): string | undefined {\n if (config.getOgImageUrl) {\n return config.getOgImageUrl(params);\n }\n\n const palette = config.ogImage?.palette;\n if (!palette) return undefined;\n\n const apiPath = config.ogImage?.apiPath ?? \"/api/og\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const searchParams = new URLSearchParams({\n title: params.title,\n type: params.type ?? \"article\",\n siteName: config.siteName,\n bg: palette.background,\n fg: palette.foreground,\n accent: palette.accent,\n });\n\n if (params.subtitle?.trim()) searchParams.set(\"subtitle\", params.subtitle.trim());\n if (params.eyebrow?.trim()) searchParams.set(\"eyebrow\", params.eyebrow.trim());\n if (palette.accentMuted) searchParams.set(\"accentMuted\", palette.accentMuted);\n if (palette.mutedText) searchParams.set(\"muted\", palette.mutedText);\n\n return `${base}${apiPath}?${searchParams.toString()}`;\n}\n\ntype ArticleLike = {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n};\n\n/**\n * Generic per-page SEO builder. Use it directly for landing/marketing pages, or\n * as the base for the article/listing wrappers below. Content-type agnostic.\n */\nexport function buildPageSeoValues(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): ISeoValues {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const path = options.path ?? \"/\";\n const url = `${base}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const description =\n options.description?.trim() ||\n config.defaultDescription ||\n `${options.title} - ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, options.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: options.keywords ?? config.defaultKeywords ?? options.title,\n image:\n options.image ??\n buildOgImageUrl(config, {\n title: options.title,\n subtitle: description,\n eyebrow: options.eyebrow,\n type: options.ogType === \"article\" ? \"article\" : \"listing\",\n }),\n noindex: options.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nfunction resolveArticleImage<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n): string | undefined {\n // cmsUrl is required to resolve a real featured image. Without it we fall\n // back to the generated OG image rather than throwing; server builders must\n // never crash a render.\n const featuredImage = config.cmsUrl\n ? cmsImage(post.featured_image, { cmsUrl: config.cmsUrl })\n : \"\";\n\n if (featuredImage) return featuredImage;\n\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription;\n\n return buildOgImageUrl(config, {\n title: post.title,\n subtitle: description,\n eyebrow: config.contentLabel ?? \"Article\",\n type: \"article\",\n });\n}\n\n/** SEO for a single article; works for news, articles, or docs pages. */\nexport function buildArticleSeoValues<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n slug: string,\n options?: { noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}${articlePath}/${slug}`;\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription ||\n `Read the latest from ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, post.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: config.defaultKeywords ?? post.title,\n image: resolveArticleImage(post, config),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\n/** SEO for an article collection / category listing (any content type). */\nexport function buildArticleListingSeoValues(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string; noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const label = config.contentLabel ?? \"Articles\";\n const categoryName = options?.categoryName?.trim();\n const categorySlug = options?.categorySlug?.trim();\n\n const titleText = categoryName ? `${categoryName} ${label}` : label;\n\n const description = categoryName\n ? `Explore ${categoryName} ${label.toLowerCase()}, guides, and the latest updates from ${config.siteName}.`\n : config.defaultDescription ||\n `Browse ${label.toLowerCase()}, insights, and the latest updates from ${config.siteName}.`;\n\n const url = categorySlug\n ? `${base}${articlePath}/category/${categorySlug}`\n : `${base}${articlePath}`;\n\n return {\n title: applyTitleTemplate(config, titleText),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords:\n config.defaultKeywords ??\n (categoryName\n ? `${categoryName}, ${config.siteName}`\n : `${config.siteName} ${label.toLowerCase()}`),\n image: buildOgImageUrl(config, {\n title: titleText,\n subtitle: description,\n eyebrow: categoryName ? \"Category\" : label,\n type: \"listing\",\n }),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nexport function seoValuesToClientProps(values: ISeoValues): SeoClientProps {\n return {\n title: values.title,\n description: values.description,\n url: values.url,\n siteName: values.siteName,\n keywords: values.keywords,\n twitter: values.twitter,\n image: values.image,\n noindex: values.noindex,\n };\n}\n","// Next.js-only SEO helpers. Imports `next`; this module is exposed only via\n// the `@asteroidcms/core-utils/next` subpath so non-Next bundlers never resolve it.\n\nimport type { Metadata } from \"next\";\nimport Head from \"next/head\";\nimport {\n buildArticleListingSeoValues,\n buildArticleSeoValues,\n buildPageSeoValues,\n} from \"./seo.builders\";\nimport type {\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n} from \"./seo.config\";\n\nexport async function generateSeoMetadata(\n SeoInfo: ISeoValues,\n): Promise<Metadata> {\n return {\n title: SeoInfo.title,\n description: SeoInfo.description,\n publisher: SeoInfo.siteName,\n keywords: SeoInfo.keywords,\n category: SeoInfo.title,\n ...(SeoInfo.manifestUrl ? { manifest: SeoInfo.manifestUrl } : {}),\n robots: SeoInfo.noindex\n ? { index: false, follow: true }\n : { index: true, follow: true },\n authors: { name: SeoInfo.siteName },\n referrer: \"origin\",\n abstract: SeoInfo.description,\n alternates: { canonical: SeoInfo.url },\n openGraph: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n url: SeoInfo.url,\n siteName: SeoInfo.siteName,\n locale: \"en_US\",\n type: \"website\",\n ...(SeoInfo.image ? { images: [{ url: SeoInfo.image }] } : {}),\n },\n twitter: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n site: SeoInfo.twitter || undefined,\n card: SeoInfo.image ? \"summary_large_image\" : \"summary\",\n ...(SeoInfo.image ? { images: [SeoInfo.image] } : {}),\n },\n };\n}\n\n/** Generic page metadata; landing pages, marketing pages, etc. */\nexport async function generatePageSeoMetadata(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): Promise<Metadata> {\n const metadata = await generateSeoMetadata(buildPageSeoValues(config, options));\n if (options.ogType === \"article\") {\n return { ...metadata, openGraph: { ...metadata.openGraph, type: \"article\" } };\n }\n return metadata;\n}\n\nexport async function generateArticleSeoMetadata<\n TPost extends {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n },\n>(post: TPost, config: AsteroidSeoConfig, slug: string): Promise<Metadata> {\n const seoValues = buildArticleSeoValues(post, config, slug);\n const metadata = await generateSeoMetadata(seoValues);\n return {\n ...metadata,\n openGraph: { ...metadata.openGraph, type: \"article\" },\n };\n}\n\nexport async function generateArticleListingSeoMetadata(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string },\n): Promise<Metadata> {\n return generateSeoMetadata(buildArticleListingSeoValues(config, options));\n}\n\nexport function SEOHeadComponent({ SeoInfo }: { SeoInfo: ISeoValues }) {\n return (\n <Head>\n <title>{SeoInfo.title}</title>\n <meta charSet=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"description\" content={SeoInfo.description} />\n <link rel=\"canonical\" href={SeoInfo.url} />\n <meta name=\"keywords\" content={SeoInfo.keywords} />\n <meta property=\"og:locale\" content=\"en_US\" />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:title\" content={SeoInfo.title} />\n <meta property=\"og:description\" content={SeoInfo.description} />\n <meta property=\"og:url\" content={SeoInfo.url} />\n <meta property=\"og:site_name\" content={SeoInfo.siteName} />\n {SeoInfo.image ? <meta property=\"og:image\" content={SeoInfo.image} /> : null}\n <meta\n name=\"twitter:card\"\n content={SeoInfo.image ? \"summary_large_image\" : \"summary\"}\n />\n <meta name=\"twitter:title\" content={SeoInfo.title} />\n <meta name=\"twitter:description\" content={SeoInfo.description} />\n {SeoInfo.twitter ? <meta name=\"twitter:site\" content={SeoInfo.twitter} /> : null}\n {SeoInfo.image ? <meta name=\"twitter:image\" content={SeoInfo.image} /> : null}\n <meta name=\"referrer\" content=\"origin\" />\n {SeoInfo.manifestUrl ? <link rel=\"manifest\" href={SeoInfo.manifestUrl} crossOrigin=\"use-credentials\" /> : null}\n <meta name=\"category\" content={SeoInfo.title} />\n <meta name=\"robots\" content={SeoInfo.noindex ? \"noindex\" : \"index\"} />\n <meta name=\"author\" content={SeoInfo.siteName} />\n <meta name=\"revisit-after\" content=\"3 month\" />\n </Head>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/cmsImage.ts","../src/seo/seo.builders.ts","../src/seo/next.tsx"],"names":["Head","jsx"],"mappings":"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","file":"next.cjs","sourcesContent":["import { useAsteroidCMSConfig } from \"../provider/context\";\n\n/**\n * Build a canonical media URL from an asset id. Pass `cmsUrl` explicitly when\n * calling outside of React (e.g. SSR loaders, scripts). Inside components,\n * prefer `useCmsImage()`.\n */\nexport function cmsImage(\n id: string | undefined,\n options: { cmsUrl: string; mediaPath?: string },\n): string {\n if (!id) return \"\";\n const base = options.cmsUrl.replace(/\\/+$/, \"\");\n const path = (options.mediaPath ?? \"/media/canonical\").replace(/^\\/?/, \"/\");\n return `${base}${path}/${id}`;\n}\n\n/** Hook variant that pulls `cmsUrl`/`mediaPath` from the provider. */\nexport function useCmsImage(): (id?: string) => string {\n const { cmsUrl, mediaPath } = useAsteroidCMSConfig();\n return (id?: string) => cmsImage(id, { cmsUrl, mediaPath });\n}\n\n/**\n * Build a runtime-agnostic image resolver. Passes absolute http(s) URLs\n * through unchanged; otherwise resolves a CMS asset id to a canonical media\n * URL. Returns \"\" when input is empty or no `cmsUrl` is configured.\n */\nexport function createImageResolver(options: {\n cmsUrl?: string;\n mediaPath?: string;\n}): (idOrUrl?: string) => string {\n return (idOrUrl?: string) => {\n if (!idOrUrl) return \"\";\n if (/^https?:\\/\\//i.test(idOrUrl)) return idOrUrl;\n if (!options.cmsUrl) return \"\";\n return cmsImage(idOrUrl, { cmsUrl: options.cmsUrl, mediaPath: options.mediaPath });\n };\n}\n","// Pure builders that turn CMS posts + config into SEO values. Server-safe.\n\nimport { cmsImage } from \"../utils/cmsImage\";\nimport type {\n AsteroidOgImageParams,\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n SeoClientProps,\n} from \"./seo.config\";\n\n/** Apply the configured title template, defaulting to `${title} | ${siteName}`. */\nexport function applyTitleTemplate(\n config: AsteroidSeoConfig,\n title: string,\n): string {\n return config.titleTemplate\n ? config.titleTemplate(title)\n : `${title} | ${config.siteName}`;\n}\n\nexport function buildOgImageUrl(\n config: AsteroidSeoConfig,\n params: AsteroidOgImageParams,\n): string | undefined {\n if (config.getOgImageUrl) {\n return config.getOgImageUrl(params);\n }\n\n const palette = config.ogImage?.palette;\n if (!palette) return undefined;\n\n const apiPath = config.ogImage?.apiPath ?? \"/api/og\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const searchParams = new URLSearchParams({\n title: params.title,\n type: params.type ?? \"article\",\n siteName: config.siteName,\n bg: palette.background,\n fg: palette.foreground,\n accent: palette.accent,\n });\n\n if (params.subtitle?.trim()) searchParams.set(\"subtitle\", params.subtitle.trim());\n if (params.eyebrow?.trim()) searchParams.set(\"eyebrow\", params.eyebrow.trim());\n if (palette.accentMuted) searchParams.set(\"accentMuted\", palette.accentMuted);\n if (palette.mutedText) searchParams.set(\"muted\", palette.mutedText);\n\n return `${base}${apiPath}?${searchParams.toString()}`;\n}\n\ntype ArticleLike = {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n};\n\n/**\n * Generic per-page SEO builder. Use it directly for landing/marketing pages, or\n * as the base for the article/listing wrappers below. Content-type agnostic.\n */\nexport function buildPageSeoValues(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): ISeoValues {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const path = options.path ?? \"/\";\n const url = `${base}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const description =\n options.description?.trim() ||\n config.defaultDescription ||\n `${options.title} - ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, options.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: options.keywords ?? config.defaultKeywords ?? options.title,\n image:\n options.image ??\n buildOgImageUrl(config, {\n title: options.title,\n subtitle: description,\n eyebrow: options.eyebrow,\n type: options.ogType === \"article\" ? \"article\" : \"listing\",\n }),\n noindex: options.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nfunction resolveArticleImage<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n): string | undefined {\n // cmsUrl is required to resolve a real featured image. Without it we fall\n // back to the generated OG image rather than throwing; server builders must\n // never crash a render.\n const featuredImage = config.cmsUrl\n ? cmsImage(post.featured_image, { cmsUrl: config.cmsUrl })\n : \"\";\n\n if (featuredImage) return featuredImage;\n\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription;\n\n return buildOgImageUrl(config, {\n title: post.title,\n subtitle: description,\n eyebrow: config.contentLabel ?? \"Article\",\n type: \"article\",\n });\n}\n\n/** SEO for a single article; works for news, articles, or docs pages. */\nexport function buildArticleSeoValues<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n slug: string,\n options?: { noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}${articlePath}/${slug}`;\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription ||\n `Read the latest from ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, post.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: config.defaultKeywords ?? post.title,\n image: resolveArticleImage(post, config),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\n/** SEO for an article collection / category listing (any content type). */\nexport function buildArticleListingSeoValues(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string; noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const label = config.contentLabel ?? \"Articles\";\n const categoryName = options?.categoryName?.trim();\n const categorySlug = options?.categorySlug?.trim();\n\n const titleText = categoryName ? `${categoryName} ${label}` : label;\n\n const description = categoryName\n ? `Explore ${categoryName} ${label.toLowerCase()}, guides, and the latest updates from ${config.siteName}.`\n : config.defaultDescription ||\n `Browse ${label.toLowerCase()}, insights, and the latest updates from ${config.siteName}.`;\n\n const url = categorySlug\n ? `${base}${articlePath}/category/${categorySlug}`\n : `${base}${articlePath}`;\n\n return {\n title: applyTitleTemplate(config, titleText),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords:\n config.defaultKeywords ??\n (categoryName\n ? `${categoryName}, ${config.siteName}`\n : `${config.siteName} ${label.toLowerCase()}`),\n image: buildOgImageUrl(config, {\n title: titleText,\n subtitle: description,\n eyebrow: categoryName ? \"Category\" : label,\n type: \"listing\",\n }),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nexport function seoValuesToClientProps(values: ISeoValues): SeoClientProps {\n return {\n title: values.title,\n description: values.description,\n url: values.url,\n siteName: values.siteName,\n keywords: values.keywords,\n twitter: values.twitter,\n image: values.image,\n noindex: values.noindex,\n };\n}\n","// Next.js-only SEO helpers. Imports `next`; this module is exposed only via\n// the `@asteroidcms/core-utils/next` subpath so non-Next bundlers never resolve it.\n\nimport type { Metadata } from \"next\";\nimport Head from \"next/head\";\nimport {\n buildArticleListingSeoValues,\n buildArticleSeoValues,\n buildPageSeoValues,\n} from \"./seo.builders\";\nimport type {\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n} from \"./seo.config\";\n\nexport async function generateSeoMetadata(\n SeoInfo: ISeoValues,\n): Promise<Metadata> {\n return {\n title: SeoInfo.title,\n description: SeoInfo.description,\n publisher: SeoInfo.siteName,\n keywords: SeoInfo.keywords,\n category: SeoInfo.title,\n ...(SeoInfo.manifestUrl ? { manifest: SeoInfo.manifestUrl } : {}),\n robots: SeoInfo.noindex\n ? { index: false, follow: true }\n : { index: true, follow: true },\n authors: { name: SeoInfo.siteName },\n referrer: \"origin\",\n abstract: SeoInfo.description,\n alternates: { canonical: SeoInfo.url },\n openGraph: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n url: SeoInfo.url,\n siteName: SeoInfo.siteName,\n locale: \"en_US\",\n type: \"website\",\n ...(SeoInfo.image ? { images: [{ url: SeoInfo.image }] } : {}),\n },\n twitter: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n site: SeoInfo.twitter || undefined,\n card: SeoInfo.image ? \"summary_large_image\" : \"summary\",\n ...(SeoInfo.image ? { images: [SeoInfo.image] } : {}),\n },\n };\n}\n\n/** Generic page metadata; landing pages, marketing pages, etc. */\nexport async function generatePageSeoMetadata(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): Promise<Metadata> {\n const metadata = await generateSeoMetadata(buildPageSeoValues(config, options));\n if (options.ogType === \"article\") {\n return { ...metadata, openGraph: { ...metadata.openGraph, type: \"article\" } };\n }\n return metadata;\n}\n\nexport async function generateArticleSeoMetadata<\n TPost extends {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n },\n>(post: TPost, config: AsteroidSeoConfig, slug: string): Promise<Metadata> {\n const seoValues = buildArticleSeoValues(post, config, slug);\n const metadata = await generateSeoMetadata(seoValues);\n return {\n ...metadata,\n openGraph: { ...metadata.openGraph, type: \"article\" },\n };\n}\n\nexport async function generateArticleListingSeoMetadata(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string },\n): Promise<Metadata> {\n return generateSeoMetadata(buildArticleListingSeoValues(config, options));\n}\n\nexport function SEOHeadComponent({ SeoInfo }: { SeoInfo: ISeoValues }) {\n return (\n <Head>\n <title>{SeoInfo.title}</title>\n <meta charSet=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"description\" content={SeoInfo.description} />\n <link rel=\"canonical\" href={SeoInfo.url} />\n <meta name=\"keywords\" content={SeoInfo.keywords} />\n <meta property=\"og:locale\" content=\"en_US\" />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:title\" content={SeoInfo.title} />\n <meta property=\"og:description\" content={SeoInfo.description} />\n <meta property=\"og:url\" content={SeoInfo.url} />\n <meta property=\"og:site_name\" content={SeoInfo.siteName} />\n {SeoInfo.image ? <meta property=\"og:image\" content={SeoInfo.image} /> : null}\n <meta\n name=\"twitter:card\"\n content={SeoInfo.image ? \"summary_large_image\" : \"summary\"}\n />\n <meta name=\"twitter:title\" content={SeoInfo.title} />\n <meta name=\"twitter:description\" content={SeoInfo.description} />\n {SeoInfo.twitter ? <meta name=\"twitter:site\" content={SeoInfo.twitter} /> : null}\n {SeoInfo.image ? <meta name=\"twitter:image\" content={SeoInfo.image} /> : null}\n <meta name=\"referrer\" content=\"origin\" />\n {SeoInfo.manifestUrl ? <link rel=\"manifest\" href={SeoInfo.manifestUrl} crossOrigin=\"use-credentials\" /> : null}\n <meta name=\"category\" content={SeoInfo.title} />\n <meta name=\"robots\" content={SeoInfo.noindex ? \"noindex\" : \"index\"} />\n <meta name=\"author\" content={SeoInfo.siteName} />\n <meta name=\"revisit-after\" content=\"3 month\" />\n </Head>\n );\n}\n"]}
package/dist/next.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/cmsImage.ts","../src/seo/seo.builders.ts","../src/seo/next.tsx"],"names":[],"mappings":"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","file":"next.js","sourcesContent":["import { useAsteroidCMSConfig } from \"../provider/context\";\n\n/**\n * Build a canonical media URL from an asset id. Pass `cmsUrl` explicitly when\n * calling outside of React (e.g. SSR loaders, scripts). Inside components,\n * prefer `useCmsImage()`.\n */\nexport function cmsImage(\n id: string | undefined,\n options: { cmsUrl: string; mediaPath?: string },\n): string {\n if (!id) return \"\";\n const base = options.cmsUrl.replace(/\\/+$/, \"\");\n const path = (options.mediaPath ?? \"/media/canonical\").replace(/^\\/?/, \"/\");\n return `${base}${path}/${id}`;\n}\n\n/** Hook variant that pulls `cmsUrl`/`mediaPath` from the provider. */\nexport function useCmsImage(): (id?: string) => string {\n const { cmsUrl, mediaPath } = useAsteroidCMSConfig();\n return (id?: string) => cmsImage(id, { cmsUrl, mediaPath });\n}\n","// Pure builders that turn CMS posts + config into SEO values. Server-safe.\n\nimport { cmsImage } from \"../utils/cmsImage\";\nimport type {\n AsteroidOgImageParams,\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n SeoClientProps,\n} from \"./seo.config\";\n\n/** Apply the configured title template, defaulting to `${title} | ${siteName}`. */\nexport function applyTitleTemplate(\n config: AsteroidSeoConfig,\n title: string,\n): string {\n return config.titleTemplate\n ? config.titleTemplate(title)\n : `${title} | ${config.siteName}`;\n}\n\nexport function buildOgImageUrl(\n config: AsteroidSeoConfig,\n params: AsteroidOgImageParams,\n): string | undefined {\n if (config.getOgImageUrl) {\n return config.getOgImageUrl(params);\n }\n\n const palette = config.ogImage?.palette;\n if (!palette) return undefined;\n\n const apiPath = config.ogImage?.apiPath ?? \"/api/og\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const searchParams = new URLSearchParams({\n title: params.title,\n type: params.type ?? \"article\",\n siteName: config.siteName,\n bg: palette.background,\n fg: palette.foreground,\n accent: palette.accent,\n });\n\n if (params.subtitle?.trim()) searchParams.set(\"subtitle\", params.subtitle.trim());\n if (params.eyebrow?.trim()) searchParams.set(\"eyebrow\", params.eyebrow.trim());\n if (palette.accentMuted) searchParams.set(\"accentMuted\", palette.accentMuted);\n if (palette.mutedText) searchParams.set(\"muted\", palette.mutedText);\n\n return `${base}${apiPath}?${searchParams.toString()}`;\n}\n\ntype ArticleLike = {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n};\n\n/**\n * Generic per-page SEO builder. Use it directly for landing/marketing pages, or\n * as the base for the article/listing wrappers below. Content-type agnostic.\n */\nexport function buildPageSeoValues(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): ISeoValues {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const path = options.path ?? \"/\";\n const url = `${base}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const description =\n options.description?.trim() ||\n config.defaultDescription ||\n `${options.title} - ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, options.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: options.keywords ?? config.defaultKeywords ?? options.title,\n image:\n options.image ??\n buildOgImageUrl(config, {\n title: options.title,\n subtitle: description,\n eyebrow: options.eyebrow,\n type: options.ogType === \"article\" ? \"article\" : \"listing\",\n }),\n noindex: options.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nfunction resolveArticleImage<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n): string | undefined {\n // cmsUrl is required to resolve a real featured image. Without it we fall\n // back to the generated OG image rather than throwing; server builders must\n // never crash a render.\n const featuredImage = config.cmsUrl\n ? cmsImage(post.featured_image, { cmsUrl: config.cmsUrl })\n : \"\";\n\n if (featuredImage) return featuredImage;\n\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription;\n\n return buildOgImageUrl(config, {\n title: post.title,\n subtitle: description,\n eyebrow: config.contentLabel ?? \"Article\",\n type: \"article\",\n });\n}\n\n/** SEO for a single article; works for news, articles, or docs pages. */\nexport function buildArticleSeoValues<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n slug: string,\n options?: { noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}${articlePath}/${slug}`;\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription ||\n `Read the latest from ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, post.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: config.defaultKeywords ?? post.title,\n image: resolveArticleImage(post, config),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\n/** SEO for an article collection / category listing (any content type). */\nexport function buildArticleListingSeoValues(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string; noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const label = config.contentLabel ?? \"Articles\";\n const categoryName = options?.categoryName?.trim();\n const categorySlug = options?.categorySlug?.trim();\n\n const titleText = categoryName ? `${categoryName} ${label}` : label;\n\n const description = categoryName\n ? `Explore ${categoryName} ${label.toLowerCase()}, guides, and the latest updates from ${config.siteName}.`\n : config.defaultDescription ||\n `Browse ${label.toLowerCase()}, insights, and the latest updates from ${config.siteName}.`;\n\n const url = categorySlug\n ? `${base}${articlePath}/category/${categorySlug}`\n : `${base}${articlePath}`;\n\n return {\n title: applyTitleTemplate(config, titleText),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords:\n config.defaultKeywords ??\n (categoryName\n ? `${categoryName}, ${config.siteName}`\n : `${config.siteName} ${label.toLowerCase()}`),\n image: buildOgImageUrl(config, {\n title: titleText,\n subtitle: description,\n eyebrow: categoryName ? \"Category\" : label,\n type: \"listing\",\n }),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nexport function seoValuesToClientProps(values: ISeoValues): SeoClientProps {\n return {\n title: values.title,\n description: values.description,\n url: values.url,\n siteName: values.siteName,\n keywords: values.keywords,\n twitter: values.twitter,\n image: values.image,\n noindex: values.noindex,\n };\n}\n","// Next.js-only SEO helpers. Imports `next`; this module is exposed only via\n// the `@asteroidcms/core-utils/next` subpath so non-Next bundlers never resolve it.\n\nimport type { Metadata } from \"next\";\nimport Head from \"next/head\";\nimport {\n buildArticleListingSeoValues,\n buildArticleSeoValues,\n buildPageSeoValues,\n} from \"./seo.builders\";\nimport type {\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n} from \"./seo.config\";\n\nexport async function generateSeoMetadata(\n SeoInfo: ISeoValues,\n): Promise<Metadata> {\n return {\n title: SeoInfo.title,\n description: SeoInfo.description,\n publisher: SeoInfo.siteName,\n keywords: SeoInfo.keywords,\n category: SeoInfo.title,\n ...(SeoInfo.manifestUrl ? { manifest: SeoInfo.manifestUrl } : {}),\n robots: SeoInfo.noindex\n ? { index: false, follow: true }\n : { index: true, follow: true },\n authors: { name: SeoInfo.siteName },\n referrer: \"origin\",\n abstract: SeoInfo.description,\n alternates: { canonical: SeoInfo.url },\n openGraph: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n url: SeoInfo.url,\n siteName: SeoInfo.siteName,\n locale: \"en_US\",\n type: \"website\",\n ...(SeoInfo.image ? { images: [{ url: SeoInfo.image }] } : {}),\n },\n twitter: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n site: SeoInfo.twitter || undefined,\n card: SeoInfo.image ? \"summary_large_image\" : \"summary\",\n ...(SeoInfo.image ? { images: [SeoInfo.image] } : {}),\n },\n };\n}\n\n/** Generic page metadata; landing pages, marketing pages, etc. */\nexport async function generatePageSeoMetadata(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): Promise<Metadata> {\n const metadata = await generateSeoMetadata(buildPageSeoValues(config, options));\n if (options.ogType === \"article\") {\n return { ...metadata, openGraph: { ...metadata.openGraph, type: \"article\" } };\n }\n return metadata;\n}\n\nexport async function generateArticleSeoMetadata<\n TPost extends {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n },\n>(post: TPost, config: AsteroidSeoConfig, slug: string): Promise<Metadata> {\n const seoValues = buildArticleSeoValues(post, config, slug);\n const metadata = await generateSeoMetadata(seoValues);\n return {\n ...metadata,\n openGraph: { ...metadata.openGraph, type: \"article\" },\n };\n}\n\nexport async function generateArticleListingSeoMetadata(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string },\n): Promise<Metadata> {\n return generateSeoMetadata(buildArticleListingSeoValues(config, options));\n}\n\nexport function SEOHeadComponent({ SeoInfo }: { SeoInfo: ISeoValues }) {\n return (\n <Head>\n <title>{SeoInfo.title}</title>\n <meta charSet=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"description\" content={SeoInfo.description} />\n <link rel=\"canonical\" href={SeoInfo.url} />\n <meta name=\"keywords\" content={SeoInfo.keywords} />\n <meta property=\"og:locale\" content=\"en_US\" />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:title\" content={SeoInfo.title} />\n <meta property=\"og:description\" content={SeoInfo.description} />\n <meta property=\"og:url\" content={SeoInfo.url} />\n <meta property=\"og:site_name\" content={SeoInfo.siteName} />\n {SeoInfo.image ? <meta property=\"og:image\" content={SeoInfo.image} /> : null}\n <meta\n name=\"twitter:card\"\n content={SeoInfo.image ? \"summary_large_image\" : \"summary\"}\n />\n <meta name=\"twitter:title\" content={SeoInfo.title} />\n <meta name=\"twitter:description\" content={SeoInfo.description} />\n {SeoInfo.twitter ? <meta name=\"twitter:site\" content={SeoInfo.twitter} /> : null}\n {SeoInfo.image ? <meta name=\"twitter:image\" content={SeoInfo.image} /> : null}\n <meta name=\"referrer\" content=\"origin\" />\n {SeoInfo.manifestUrl ? <link rel=\"manifest\" href={SeoInfo.manifestUrl} crossOrigin=\"use-credentials\" /> : null}\n <meta name=\"category\" content={SeoInfo.title} />\n <meta name=\"robots\" content={SeoInfo.noindex ? \"noindex\" : \"index\"} />\n <meta name=\"author\" content={SeoInfo.siteName} />\n <meta name=\"revisit-after\" content=\"3 month\" />\n </Head>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/cmsImage.ts","../src/seo/seo.builders.ts","../src/seo/next.tsx"],"names":[],"mappings":"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","file":"next.js","sourcesContent":["import { useAsteroidCMSConfig } from \"../provider/context\";\n\n/**\n * Build a canonical media URL from an asset id. Pass `cmsUrl` explicitly when\n * calling outside of React (e.g. SSR loaders, scripts). Inside components,\n * prefer `useCmsImage()`.\n */\nexport function cmsImage(\n id: string | undefined,\n options: { cmsUrl: string; mediaPath?: string },\n): string {\n if (!id) return \"\";\n const base = options.cmsUrl.replace(/\\/+$/, \"\");\n const path = (options.mediaPath ?? \"/media/canonical\").replace(/^\\/?/, \"/\");\n return `${base}${path}/${id}`;\n}\n\n/** Hook variant that pulls `cmsUrl`/`mediaPath` from the provider. */\nexport function useCmsImage(): (id?: string) => string {\n const { cmsUrl, mediaPath } = useAsteroidCMSConfig();\n return (id?: string) => cmsImage(id, { cmsUrl, mediaPath });\n}\n\n/**\n * Build a runtime-agnostic image resolver. Passes absolute http(s) URLs\n * through unchanged; otherwise resolves a CMS asset id to a canonical media\n * URL. Returns \"\" when input is empty or no `cmsUrl` is configured.\n */\nexport function createImageResolver(options: {\n cmsUrl?: string;\n mediaPath?: string;\n}): (idOrUrl?: string) => string {\n return (idOrUrl?: string) => {\n if (!idOrUrl) return \"\";\n if (/^https?:\\/\\//i.test(idOrUrl)) return idOrUrl;\n if (!options.cmsUrl) return \"\";\n return cmsImage(idOrUrl, { cmsUrl: options.cmsUrl, mediaPath: options.mediaPath });\n };\n}\n","// Pure builders that turn CMS posts + config into SEO values. Server-safe.\n\nimport { cmsImage } from \"../utils/cmsImage\";\nimport type {\n AsteroidOgImageParams,\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n SeoClientProps,\n} from \"./seo.config\";\n\n/** Apply the configured title template, defaulting to `${title} | ${siteName}`. */\nexport function applyTitleTemplate(\n config: AsteroidSeoConfig,\n title: string,\n): string {\n return config.titleTemplate\n ? config.titleTemplate(title)\n : `${title} | ${config.siteName}`;\n}\n\nexport function buildOgImageUrl(\n config: AsteroidSeoConfig,\n params: AsteroidOgImageParams,\n): string | undefined {\n if (config.getOgImageUrl) {\n return config.getOgImageUrl(params);\n }\n\n const palette = config.ogImage?.palette;\n if (!palette) return undefined;\n\n const apiPath = config.ogImage?.apiPath ?? \"/api/og\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const searchParams = new URLSearchParams({\n title: params.title,\n type: params.type ?? \"article\",\n siteName: config.siteName,\n bg: palette.background,\n fg: palette.foreground,\n accent: palette.accent,\n });\n\n if (params.subtitle?.trim()) searchParams.set(\"subtitle\", params.subtitle.trim());\n if (params.eyebrow?.trim()) searchParams.set(\"eyebrow\", params.eyebrow.trim());\n if (palette.accentMuted) searchParams.set(\"accentMuted\", palette.accentMuted);\n if (palette.mutedText) searchParams.set(\"muted\", palette.mutedText);\n\n return `${base}${apiPath}?${searchParams.toString()}`;\n}\n\ntype ArticleLike = {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n};\n\n/**\n * Generic per-page SEO builder. Use it directly for landing/marketing pages, or\n * as the base for the article/listing wrappers below. Content-type agnostic.\n */\nexport function buildPageSeoValues(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): ISeoValues {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const path = options.path ?? \"/\";\n const url = `${base}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const description =\n options.description?.trim() ||\n config.defaultDescription ||\n `${options.title} - ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, options.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: options.keywords ?? config.defaultKeywords ?? options.title,\n image:\n options.image ??\n buildOgImageUrl(config, {\n title: options.title,\n subtitle: description,\n eyebrow: options.eyebrow,\n type: options.ogType === \"article\" ? \"article\" : \"listing\",\n }),\n noindex: options.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nfunction resolveArticleImage<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n): string | undefined {\n // cmsUrl is required to resolve a real featured image. Without it we fall\n // back to the generated OG image rather than throwing; server builders must\n // never crash a render.\n const featuredImage = config.cmsUrl\n ? cmsImage(post.featured_image, { cmsUrl: config.cmsUrl })\n : \"\";\n\n if (featuredImage) return featuredImage;\n\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription;\n\n return buildOgImageUrl(config, {\n title: post.title,\n subtitle: description,\n eyebrow: config.contentLabel ?? \"Article\",\n type: \"article\",\n });\n}\n\n/** SEO for a single article; works for news, articles, or docs pages. */\nexport function buildArticleSeoValues<TPost extends ArticleLike>(\n post: TPost,\n config: AsteroidSeoConfig,\n slug: string,\n options?: { noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}${articlePath}/${slug}`;\n const description =\n post.meta_description?.trim() ||\n post.description?.trim() ||\n config.defaultDescription ||\n `Read the latest from ${config.siteName}.`;\n\n return {\n title: applyTitleTemplate(config, post.title),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords: config.defaultKeywords ?? post.title,\n image: resolveArticleImage(post, config),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\n/** SEO for an article collection / category listing (any content type). */\nexport function buildArticleListingSeoValues(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string; noindex?: boolean },\n): ISeoValues {\n const articlePath = config.articlePath ?? \"/blog\";\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const label = config.contentLabel ?? \"Articles\";\n const categoryName = options?.categoryName?.trim();\n const categorySlug = options?.categorySlug?.trim();\n\n const titleText = categoryName ? `${categoryName} ${label}` : label;\n\n const description = categoryName\n ? `Explore ${categoryName} ${label.toLowerCase()}, guides, and the latest updates from ${config.siteName}.`\n : config.defaultDescription ||\n `Browse ${label.toLowerCase()}, insights, and the latest updates from ${config.siteName}.`;\n\n const url = categorySlug\n ? `${base}${articlePath}/category/${categorySlug}`\n : `${base}${articlePath}`;\n\n return {\n title: applyTitleTemplate(config, titleText),\n siteName: config.siteName,\n twitter: config.twitter ?? \"\",\n description,\n url,\n keywords:\n config.defaultKeywords ??\n (categoryName\n ? `${categoryName}, ${config.siteName}`\n : `${config.siteName} ${label.toLowerCase()}`),\n image: buildOgImageUrl(config, {\n title: titleText,\n subtitle: description,\n eyebrow: categoryName ? \"Category\" : label,\n type: \"listing\",\n }),\n noindex: options?.noindex ?? config.noindex,\n manifestUrl: config.manifestUrl,\n };\n}\n\nexport function seoValuesToClientProps(values: ISeoValues): SeoClientProps {\n return {\n title: values.title,\n description: values.description,\n url: values.url,\n siteName: values.siteName,\n keywords: values.keywords,\n twitter: values.twitter,\n image: values.image,\n noindex: values.noindex,\n };\n}\n","// Next.js-only SEO helpers. Imports `next`; this module is exposed only via\n// the `@asteroidcms/core-utils/next` subpath so non-Next bundlers never resolve it.\n\nimport type { Metadata } from \"next\";\nimport Head from \"next/head\";\nimport {\n buildArticleListingSeoValues,\n buildArticleSeoValues,\n buildPageSeoValues,\n} from \"./seo.builders\";\nimport type {\n AsteroidPageSeoOptions,\n AsteroidSeoConfig,\n ISeoValues,\n} from \"./seo.config\";\n\nexport async function generateSeoMetadata(\n SeoInfo: ISeoValues,\n): Promise<Metadata> {\n return {\n title: SeoInfo.title,\n description: SeoInfo.description,\n publisher: SeoInfo.siteName,\n keywords: SeoInfo.keywords,\n category: SeoInfo.title,\n ...(SeoInfo.manifestUrl ? { manifest: SeoInfo.manifestUrl } : {}),\n robots: SeoInfo.noindex\n ? { index: false, follow: true }\n : { index: true, follow: true },\n authors: { name: SeoInfo.siteName },\n referrer: \"origin\",\n abstract: SeoInfo.description,\n alternates: { canonical: SeoInfo.url },\n openGraph: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n url: SeoInfo.url,\n siteName: SeoInfo.siteName,\n locale: \"en_US\",\n type: \"website\",\n ...(SeoInfo.image ? { images: [{ url: SeoInfo.image }] } : {}),\n },\n twitter: {\n title: SeoInfo.title,\n description: SeoInfo.description,\n site: SeoInfo.twitter || undefined,\n card: SeoInfo.image ? \"summary_large_image\" : \"summary\",\n ...(SeoInfo.image ? { images: [SeoInfo.image] } : {}),\n },\n };\n}\n\n/** Generic page metadata; landing pages, marketing pages, etc. */\nexport async function generatePageSeoMetadata(\n config: AsteroidSeoConfig,\n options: AsteroidPageSeoOptions,\n): Promise<Metadata> {\n const metadata = await generateSeoMetadata(buildPageSeoValues(config, options));\n if (options.ogType === \"article\") {\n return { ...metadata, openGraph: { ...metadata.openGraph, type: \"article\" } };\n }\n return metadata;\n}\n\nexport async function generateArticleSeoMetadata<\n TPost extends {\n title: string;\n description?: string;\n meta_description?: string;\n featured_image?: string;\n },\n>(post: TPost, config: AsteroidSeoConfig, slug: string): Promise<Metadata> {\n const seoValues = buildArticleSeoValues(post, config, slug);\n const metadata = await generateSeoMetadata(seoValues);\n return {\n ...metadata,\n openGraph: { ...metadata.openGraph, type: \"article\" },\n };\n}\n\nexport async function generateArticleListingSeoMetadata(\n config: AsteroidSeoConfig,\n options?: { categoryName?: string; categorySlug?: string },\n): Promise<Metadata> {\n return generateSeoMetadata(buildArticleListingSeoValues(config, options));\n}\n\nexport function SEOHeadComponent({ SeoInfo }: { SeoInfo: ISeoValues }) {\n return (\n <Head>\n <title>{SeoInfo.title}</title>\n <meta charSet=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"description\" content={SeoInfo.description} />\n <link rel=\"canonical\" href={SeoInfo.url} />\n <meta name=\"keywords\" content={SeoInfo.keywords} />\n <meta property=\"og:locale\" content=\"en_US\" />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:title\" content={SeoInfo.title} />\n <meta property=\"og:description\" content={SeoInfo.description} />\n <meta property=\"og:url\" content={SeoInfo.url} />\n <meta property=\"og:site_name\" content={SeoInfo.siteName} />\n {SeoInfo.image ? <meta property=\"og:image\" content={SeoInfo.image} /> : null}\n <meta\n name=\"twitter:card\"\n content={SeoInfo.image ? \"summary_large_image\" : \"summary\"}\n />\n <meta name=\"twitter:title\" content={SeoInfo.title} />\n <meta name=\"twitter:description\" content={SeoInfo.description} />\n {SeoInfo.twitter ? <meta name=\"twitter:site\" content={SeoInfo.twitter} /> : null}\n {SeoInfo.image ? <meta name=\"twitter:image\" content={SeoInfo.image} /> : null}\n <meta name=\"referrer\" content=\"origin\" />\n {SeoInfo.manifestUrl ? <link rel=\"manifest\" href={SeoInfo.manifestUrl} crossOrigin=\"use-credentials\" /> : null}\n <meta name=\"category\" content={SeoInfo.title} />\n <meta name=\"robots\" content={SeoInfo.noindex ? \"noindex\" : \"index\"} />\n <meta name=\"author\" content={SeoInfo.siteName} />\n <meta name=\"revisit-after\" content=\"3 month\" />\n </Head>\n );\n}\n"]}