@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/README.md +167 -0
- package/dist/client.cjs +208 -172
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +135 -171
- package/dist/client.d.ts +135 -171
- package/dist/client.js +208 -173
- package/dist/client.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/next.cjs.map +1 -1
- package/dist/next.js.map +1 -1
- package/dist/server.cjs +699 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +342 -0
- package/dist/server.d.ts +342 -0
- package/dist/server.js +669 -0
- package/dist/server.js.map +1 -0
- package/package.json +14 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apollo/errorLink.ts","../src/apollo/createApolloClient.ts","../src/server/cmsServerClient.ts","../src/build-query.ts","../src/fetchCmsContent.ts","../src/server/defineArticleSource.ts","../src/seo/jsonld.ts","../src/utils/cmsImage.ts","../src/components/articles/articles.state.ts","../src/components/articles/articles.view.tsx","../src/components/articles/AsteroidArticlesListingServer.tsx","../src/seo/seo.builders.ts","../src/components/articles/article.view.tsx","../src/components/articles/AsteroidArticlePageServer.tsx","../src/server/articleMetadata.ts"],"names":["alias","cmsImage","Fragment","jsx","jsxs"],"mappings":"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","file":"server.js","sourcesContent":["import { CombinedGraphQLErrors, CombinedProtocolErrors } from \"@apollo/client\";\nimport { ErrorLink } from \"@apollo/client/link/error\";\n\ntype OnError = (error: unknown) => void;\n\n/**\n * Lightweight error link. Forwards every error to the consumer-supplied\n * `onError` handler (configured on the provider). No toasts, no auth, no\n * token refresh — the package is auth-key only.\n */\nexport function createErrorLink(onError?: OnError) {\n return new ErrorLink(({ error }) => {\n if (!onError) return;\n if (CombinedGraphQLErrors.is(error)) {\n error.errors.forEach((e) => onError(e));\n } else if (CombinedProtocolErrors.is(error)) {\n error.errors.forEach((e) => onError(e));\n } else {\n onError(error);\n }\n });\n}\n","import {\n ApolloClient,\n ApolloLink,\n HttpLink,\n InMemoryCache,\n} from \"@apollo/client\";\nimport { SetContextLink } from \"@apollo/client/link/context\";\nimport { createErrorLink } from \"./errorLink\";\nimport type { AsteroidCMSConfig, ResolvedAsteroidCMSConfig } from \"../provider/types\";\n\ndeclare module \"@apollo/client\" {\n namespace ApolloClient.DeclareDefaultOptions {\n interface WatchQuery {\n errorPolicy: \"all\";\n returnPartialData: false;\n }\n interface Query {\n errorPolicy: \"all\";\n }\n interface Mutate {\n errorPolicy: \"none\";\n }\n }\n}\n\nconst trimTrailingSlash = (s: string) => s.replace(/\\/+$/, \"\");\nconst ensureLeadingSlash = (s: string) => (s.startsWith(\"/\") ? s : `/${s}`);\n\nexport function resolveConfig(config: AsteroidCMSConfig): ResolvedAsteroidCMSConfig {\n if (!config.cmsUrl) throw new Error(\"AsteroidCMSProvider: `cmsUrl` is required.\");\n if (!config.apiKey) throw new Error(\"AsteroidCMSProvider: `apiKey` is required.\");\n\n return {\n cmsUrl: trimTrailingSlash(config.cmsUrl),\n apiKey: config.apiKey,\n graphqlPath: ensureLeadingSlash(config.graphqlPath ?? \"/graphql\"),\n mediaPath: ensureLeadingSlash(config.mediaPath ?? \"/media/canonical\"),\n headers: config.headers ?? {},\n onError: config.onError,\n };\n}\n\nexport function createApolloClient(config: AsteroidCMSConfig): ApolloClient {\n if (config.client) return config.client;\n\n const resolved = resolveConfig(config);\n const uri = `${resolved.cmsUrl}${resolved.graphqlPath}`;\n\n const authLink = new SetContextLink((_op, prevContext) => {\n const prevHeaders = (prevContext as { headers?: Record<string, string> }).headers ?? {};\n return {\n ...prevContext,\n headers: {\n ...prevHeaders,\n \"x-api-key\": resolved.apiKey,\n ...resolved.headers,\n },\n };\n });\n\n const httpLink = new HttpLink({ uri });\n\n return new ApolloClient({\n link: ApolloLink.from([createErrorLink(resolved.onError), authLink, httpLink]),\n cache: new InMemoryCache(config.cacheConfig),\n defaultOptions: {\n watchQuery: {\n fetchPolicy: \"cache-and-network\",\n errorPolicy: \"all\",\n returnPartialData: false,\n },\n query: { fetchPolicy: \"network-only\", errorPolicy: \"all\" },\n mutate: { errorPolicy: \"none\" },\n },\n ...config.apolloOptions,\n });\n}\n","// src/server/cmsServerClient.ts\nimport type { ApolloClient } from \"@apollo/client\";\nimport * as React from \"react\";\nimport { createApolloClient, resolveConfig } from \"../apollo/createApolloClient\";\n\n// React.cache exists in React 19 / RSC (and Next's bundled React); it is absent\n// in stable React 18. Fall back to an identity wrapper so the factory still works\n// (without per-request dedup) outside an RSC runtime.\ntype CacheFn = <A extends unknown[], R>(fn: (...args: A) => R) => (...args: A) => R;\nconst reactCache: CacheFn =\n (React as unknown as { cache?: CacheFn }).cache ?? ((fn) => fn);\n\nexport interface CmsServerClientConfig {\n cmsUrl: string;\n apiKey: string;\n graphqlPath?: string;\n headers?: Record<string, string>;\n /** Next.js ISR revalidate seconds, applied to the GraphQL fetch. */\n revalidate?: number;\n /** Next.js cache tags for on-demand revalidation. */\n tags?: string[];\n /** Escape hatch: provide a pre-built client (e.g. registerApolloClient). */\n getClient?: () => ApolloClient;\n}\n\nexport interface CmsServerClient {\n getClient: () => ApolloClient;\n cmsUrl: string;\n}\n\n/**\n * Build a server-only CMS client for use with `fetchCmsContent` / `cmsMutate`.\n * The API key stays on the server. The client is memoized per-request via\n * React `cache()` for query deduplication.\n */\nexport function createCmsServerClient(config: CmsServerClientConfig): CmsServerClient {\n // resolveConfig validates cmsUrl + apiKey and normalizes the URL.\n const resolved = resolveConfig({\n cmsUrl: config.cmsUrl,\n apiKey: config.apiKey,\n graphqlPath: config.graphqlPath,\n headers: config.headers,\n });\n\n const next =\n config.revalidate !== undefined || config.tags !== undefined\n ? { revalidate: config.revalidate, tags: config.tags }\n : undefined;\n\n const factory =\n config.getClient ??\n (() =>\n createApolloClient({\n cmsUrl: resolved.cmsUrl,\n apiKey: resolved.apiKey,\n graphqlPath: resolved.graphqlPath,\n headers: resolved.headers,\n ...(next\n ? { apolloOptions: { defaultContext: { fetchOptions: { next } } } as never }\n : {}),\n }));\n\n return { getClient: reactCache(factory), cmsUrl: resolved.cmsUrl };\n}\n","import { DocumentNode, gql } from \"@apollo/client\";\n\nexport type FieldSelector = string | { field: string; as?: string };\n\nexport type ReferenceExpansion = {\n field: string;\n as?: string;\n single?: boolean;\n select?: readonly (FieldSelector | ReferenceExpansion)[];\n};\n\nexport type ContentStatus = \"DRAFT\" | \"PUBLISHED\" | \"ARCHIVED\";\n\nexport type CmsSearchCondition = {\n field: string;\n value: string;\n mode?: string;\n};\n\nexport type UseCmsContentOptions = {\n schema_slug: string;\n entrySlug?: string;\n select?: readonly (FieldSelector | ReferenceExpansion)[];\n fullData?: boolean;\n limit?: number;\n offset?: number;\n status?: ContentStatus;\n filter?: Record<string, string | number | boolean | null>;\n search?: CmsSearchCondition[];\n variables?: Record<string, unknown>;\n};\n\nfunction buildSelection(\n items: readonly (FieldSelector | ReferenceExpansion)[] = [],\n): string {\n const lines: string[] = [];\n\n items.forEach((item) => {\n if (typeof item === \"string\") {\n lines.push(`${item}: dataField(slug: \"${item}\")`);\n return;\n }\n\n if (\"field\" in item && typeof item.field === \"string\") {\n if (!(\"select\" in item)) {\n const alias = item.as || item.field;\n lines.push(`${alias}: dataField(slug: \"${item.field}\")`);\n return;\n }\n\n const alias = item.as || item.field;\n const resolver = item.single\n ? \"expandedReferenceObject\"\n : \"expandedReference\";\n\n const subSelection = item.select?.length\n ? buildSelection(item.select)\n : \"data { ... }\";\n\n lines.push(`\n ${alias}: ${resolver}(slug: \"${item.field}\") {\n ${subSelection}\n }\n `);\n }\n });\n\n return lines.join(\"\\n \").trim();\n}\n\nexport function buildCmsQuery({\n schema_slug,\n entrySlug,\n select = [],\n fullData = false,\n limit,\n offset,\n status = \"PUBLISHED\",\n filter,\n search,\n variables = {},\n}: UseCmsContentOptions): {\n query: DocumentNode;\n variables: Record<string, unknown>;\n isSingle: boolean;\n} {\n const isSingle = Boolean(entrySlug);\n const selectionParts: string[] = [];\n\n if (fullData) {\n selectionParts.push(\"data\");\n }\n\n if (select.length > 0) {\n const userSelection = buildSelection(select);\n if (userSelection) {\n selectionParts.push(userSelection);\n }\n }\n\n const selection = selectionParts.join(\"\\n \").trim() || \"id\";\n\n const queryVariables: Record<string, unknown> = {\n schema_slug,\n ...(entrySlug && { slug: entrySlug }),\n ...variables,\n };\n const fieldArgParts: string[] = [\"schema_slug: $schema_slug\"];\n\n if (!isSingle) {\n if (typeof limit === \"number\" && limit >= 0) {\n fieldArgParts.push(\"limit: $limit\");\n queryVariables.limit = limit;\n }\n if (typeof offset === \"number\" && offset >= 0) {\n fieldArgParts.push(\"offset: $offset\");\n queryVariables.offset = offset;\n }\n if (status) {\n const statuses = status;\n if (statuses.length > 0) {\n fieldArgParts.push(\"status: $status\");\n queryVariables.status = statuses;\n }\n }\n\n const hasSearch = Array.isArray(search) && search.length > 0;\n const hasFilter =\n filter && typeof filter === \"object\" && Object.keys(filter).length > 0;\n\n if (hasSearch || hasFilter) {\n const mergedFilter: Record<string, unknown> = hasFilter\n ? { ...filter }\n : {};\n\n if (hasSearch) {\n for (const condition of search!) {\n mergedFilter[condition.field] = {\n regex: true,\n value: condition.value,\n mode: condition.mode ?? \"i\",\n };\n }\n }\n\n fieldArgParts.push(\"data: $filter\");\n queryVariables.filter = mergedFilter;\n }\n }\n\n const varDecls: string[] = [\"$schema_slug: String!\"];\n\n if (\"limit\" in queryVariables) varDecls.push(\"$limit: Float\");\n if (\"offset\" in queryVariables) varDecls.push(\"$offset: Float\");\n if (\"status\" in queryVariables) varDecls.push(\"$status: ContentStatus\");\n if (\"filter\" in queryVariables) varDecls.push(\"$filter: JSONObject\");\n\n const varBlock =\n varDecls.length > 0 ? `(\\n ${varDecls.join(\"\\n \")}\\n)` : \"\";\n const contentFieldArgs = fieldArgParts.join(\", \");\n const queryStr = isSingle\n ? `\n query Get${schema_slug}Entry($schema_slug: String!, $slug: String!) {\n entry: contentEntry(schema_slug: $schema_slug, slug: $slug) {\n ${selection}\n }\n }\n `\n : `\n query Get${schema_slug}Entries${varBlock} {\n entries: contentEntries(${contentFieldArgs}) {\n ${selection}\n }\n }\n `;\n return {\n query: gql(queryStr) as DocumentNode,\n variables: queryVariables,\n isSingle,\n };\n}\n","import { buildCmsQuery, type UseCmsContentOptions } from \"./build-query\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyApolloClient = { query: (...args: any[]) => any };\n\nexport async function fetchCmsContent<T>(\n getClient: () => AnyApolloClient,\n opts: UseCmsContentOptions,\n): Promise<T> {\n const { query, variables, isSingle } = buildCmsQuery(opts);\n const { data } = await getClient().query({ query, variables });\n\n return (isSingle\n ? (data as { entry: T }).entry\n : (data as { entries: T }).entries) as T;\n}\n","// src/server/defineArticleSource.ts\nimport { fetchCmsContent } from \"../fetchCmsContent\";\nimport type {\n CmsSearchCondition,\n ContentStatus,\n UseCmsContentOptions,\n} from \"../build-query\";\nimport type { AsteroidSeoConfig } from \"../seo/seo.config\";\nimport type { ArticleJsonLdType } from \"../seo/jsonld\";\nimport type { AsteroidArticlePost } from \"../components/articles/articles.types\";\nimport type { AsteroidArticlePagePost } from \"../components/articles/article.view\";\nimport type { CmsServerClient } from \"./cmsServerClient\";\n\ntype Select = NonNullable<UseCmsContentOptions[\"select\"]>;\n\nexport interface ArticleSourceConfig<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n> {\n client: CmsServerClient;\n schemaSlug: string;\n listSelect: Select;\n detailSelect: Select;\n seo: AsteroidSeoConfig;\n searchFields?: string[];\n status?: ContentStatus;\n articleType?: ArticleJsonLdType;\n relatedLimit?: number;\n groupPostsByCategory?: (posts: TPost[]) => unknown;\n}\n\nexport interface ArticleSource<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n> {\n client: CmsServerClient;\n schemaSlug: string;\n listSelect: Select;\n detailSelect: Select;\n seo: AsteroidSeoConfig;\n searchFields: string[];\n status: ContentStatus;\n articleType: ArticleJsonLdType;\n relatedLimit: number;\n groupPostsByCategory?: (posts: TPost[]) => unknown;\n}\n\nexport function buildSearchConditions(\n fields: string[],\n query?: string,\n): CmsSearchCondition[] | undefined {\n const trimmed = query?.trim();\n if (!trimmed) return undefined;\n return fields.map((field) => ({ field, value: trimmed, mode: \"i\" }));\n}\n\nexport function defineArticleSource<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n>(config: ArticleSourceConfig<TPost, TDetail>): ArticleSource<TPost, TDetail> {\n return Object.freeze({\n client: config.client,\n schemaSlug: config.schemaSlug,\n listSelect: config.listSelect,\n detailSelect: config.detailSelect,\n seo: config.seo.cmsUrl ? config.seo : { ...config.seo, cmsUrl: config.client.cmsUrl },\n searchFields: config.searchFields ?? [\"title\", \"description\"],\n status: config.status ?? \"PUBLISHED\",\n articleType: config.articleType ?? \"Article\",\n relatedLimit: config.relatedLimit ?? 3,\n groupPostsByCategory: config.groupPostsByCategory,\n });\n}\n\nexport async function fetchArticles<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n>(\n source: ArticleSource<TPost>,\n opts: { searchQuery?: string; categorySlug?: string; limit?: number } = {},\n): Promise<TPost[]> {\n const search = buildSearchConditions(source.searchFields, opts.searchQuery);\n const data = await fetchCmsContent<TPost[]>(source.client.getClient, {\n schema_slug: source.schemaSlug,\n select: source.listSelect,\n status: source.status,\n ...(opts.limit !== undefined ? { limit: opts.limit } : {}),\n ...(opts.categorySlug ? { filter: { category: opts.categorySlug } } : {}),\n ...(search ? { search } : {}),\n });\n return Array.isArray(data) ? data : [];\n}\n\nexport async function fetchArticle<\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n>(source: ArticleSource<AsteroidArticlePost, TDetail>, slug: string): Promise<TDetail | null> {\n try {\n const data = await fetchCmsContent<TDetail>(source.client.getClient, {\n schema_slug: source.schemaSlug,\n entrySlug: slug,\n select: source.detailSelect,\n status: source.status,\n });\n return data ?? null;\n } catch {\n return null;\n }\n}\n\nexport async function fetchRelatedArticles<\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n>(\n source: ArticleSource<AsteroidArticlePost, TDetail>,\n post: TDetail,\n slug: string,\n): Promise<TDetail[]> {\n const categorySlug = post.category?.slug?.trim();\n if (!categorySlug || source.relatedLimit <= 0) return [];\n const data = await fetchCmsContent<TDetail[]>(source.client.getClient, {\n schema_slug: source.schemaSlug,\n select: source.listSelect,\n status: source.status,\n limit: source.relatedLimit + 1,\n filter: { category: categorySlug },\n });\n return (Array.isArray(data) ? data : [])\n .filter((p) => p.slug !== slug)\n .slice(0, source.relatedLimit);\n}\n","// Pure schema.org JSON-LD builders. Server-safe. No hardcoded site identity.\n\nimport type { AsteroidSeoConfig } from \"./seo.config\";\n\n/** Build the site-wide Organization + WebSite @graph from config. */\nexport function buildSiteJsonLd(config: AsteroidSeoConfig): object {\n const siteUrl = config.baseUrl.replace(/\\/$/, \"\");\n const org = config.organization;\n\n const organizationNode: Record<string, unknown> = {\n \"@type\": \"Organization\",\n \"@id\": `${siteUrl}/#organization`,\n name: config.siteName,\n legalName: config.siteName,\n url: siteUrl,\n };\n if (org?.logoUrl) {\n organizationNode.logo = { \"@type\": \"ImageObject\", url: org.logoUrl };\n }\n if (org?.contactPhone || org?.contactEmail) {\n organizationNode.contactPoint = {\n \"@type\": \"ContactPoint\",\n ...(org.contactPhone ? { telephone: org.contactPhone } : {}),\n ...(org.contactEmail ? { email: org.contactEmail } : {}),\n contactType: \"customer service\",\n };\n }\n if (org?.address) {\n organizationNode.address = {\n \"@type\": \"PostalAddress\",\n ...(org.address.street ? { streetAddress: org.address.street } : {}),\n ...(org.address.city ? { addressLocality: org.address.city } : {}),\n ...(org.address.country ? { addressCountry: org.address.country } : {}),\n };\n }\n if (org?.socials?.length) {\n organizationNode.sameAs = org.socials;\n }\n\n const websiteNode: Record<string, unknown> = {\n \"@type\": \"WebSite\",\n \"@id\": `${siteUrl}/#website`,\n url: siteUrl,\n name: config.siteName,\n publisher: { \"@id\": `${siteUrl}/#organization` },\n inLanguage: \"en-US\",\n };\n if (config.defaultDescription) {\n websiteNode.description = config.defaultDescription;\n }\n\n return {\n \"@context\": \"https://schema.org\",\n \"@graph\": [organizationNode, websiteNode, ...(config.extraJsonLdNodes ?? [])],\n };\n}\n\n/** schema.org Article subtypes; pick per content kind. */\nexport type ArticleJsonLdType =\n | \"Article\"\n | \"BlogPosting\"\n | \"NewsArticle\"\n | \"TechArticle\"\n | (string & {});\n\nexport type ArticleJsonLdProps = {\n title: string;\n description: string;\n url: string;\n /** Site name; used as the author fallback. */\n siteName: string;\n /** Normalized base URL (no trailing slash); used to reference the org/website @ids. */\n siteUrl: string;\n /** schema.org @type. Default: `\"Article\"`. */\n articleType?: ArticleJsonLdType;\n image?: string;\n authorName?: string;\n publishedTime?: string;\n tags?: string[];\n category?: string;\n};\n\nexport function buildArticleJsonLd(props: ArticleJsonLdProps): object {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": props.articleType ?? \"Article\",\n headline: props.title,\n description: props.description,\n url: props.url,\n ...(props.image ? { image: props.image } : {}),\n ...(props.publishedTime ? { datePublished: props.publishedTime } : {}),\n ...(props.category ? { articleSection: props.category } : {}),\n ...(props.tags && props.tags.length > 0\n ? { keywords: props.tags.join(\", \") }\n : {}),\n author: { \"@type\": \"Person\", name: props.authorName || props.siteName },\n publisher: { \"@id\": `${props.siteUrl}/#organization` },\n isPartOf: { \"@id\": `${props.siteUrl}/#website` },\n inLanguage: \"en-US\",\n };\n}\n\nexport type CollectionJsonLdProps = {\n name: string;\n description: string;\n url: string;\n /** Normalized base URL (no trailing slash); used to reference the org/website @ids. */\n siteUrl: string;\n};\n\nexport function buildCollectionJsonLd(props: CollectionJsonLdProps): object {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"CollectionPage\",\n name: props.name,\n description: props.description,\n url: props.url,\n isPartOf: { \"@id\": `${props.siteUrl}/#website` },\n publisher: { \"@id\": `${props.siteUrl}/#organization` },\n inLanguage: \"en-US\",\n };\n}\n\nexport type WebPageJsonLdProps = {\n name: string;\n description: string;\n url: string;\n /** Normalized base URL (no trailing slash); used to reference the org/website @ids. */\n siteUrl: string;\n};\n\n/** Generic WebPage node for landing/marketing pages with no article concept. */\nexport function buildWebPageJsonLd(props: WebPageJsonLdProps): object {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"WebPage\",\n name: props.name,\n description: props.description,\n url: props.url,\n isPartOf: { \"@id\": `${props.siteUrl}/#website` },\n publisher: { \"@id\": `${props.siteUrl}/#organization` },\n inLanguage: \"en-US\",\n };\n}\n","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","// src/components/articles/articles.state.ts\nimport type {\n AsteroidArticleCategoryGroup,\n AsteroidArticlePost,\n ArticlesViewState,\n} from \"./articles.types\";\n\nexport function defaultGetCategoryName(\n post: Pick<AsteroidArticlePost, \"category\">,\n): string | undefined {\n return post.category?.name?.trim() || undefined;\n}\n\nexport function defaultGroupPostsByCategory<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n>(posts: TPost[]): AsteroidArticleCategoryGroup<TPost>[] {\n const groups = new Map<string, AsteroidArticleCategoryGroup<TPost>>();\n\n for (const post of posts) {\n const categoryName = defaultGetCategoryName(post) || \"Other\";\n const categorySlug = post.category?.slug || \"other\";\n const existing = groups.get(categorySlug);\n\n if (existing) {\n existing.posts.push(post);\n } else {\n groups.set(categorySlug, { categoryName, categorySlug, posts: [post] });\n }\n }\n\n return Array.from(groups.values());\n}\n\nexport function applyPostFilters<TPost extends AsteroidArticlePost>(\n posts: TPost[],\n { categorySlug, articleSlug }: { categorySlug?: string; articleSlug?: string },\n): TPost[] {\n let filtered = posts;\n if (categorySlug) {\n filtered = filtered.filter((post) => post.category?.slug === categorySlug);\n }\n if (articleSlug) {\n filtered = filtered.filter((post) => post.slug === articleSlug);\n }\n return filtered;\n}\n\nexport function splitFeaturedAndRest<TPost extends AsteroidArticlePost>(\n posts: TPost[],\n): { featured: TPost | null; rest: TPost[] } {\n const featured = posts.find((post) => post.featured) ?? null;\n const rest = featured\n ? posts.filter((post) => post.slug !== featured.slug)\n : [...posts];\n return { featured, rest };\n}\n\nexport interface BuildArticlesViewStateOptions<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n> {\n categorySlug?: string;\n articleSlug?: string;\n searchQuery?: string;\n groupPostsByCategory?: (posts: TPost[]) => AsteroidArticleCategoryGroup<TPost>[];\n}\n\nexport function buildArticlesViewState<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n>(\n rawPosts: TPost[],\n options: BuildArticlesViewStateOptions<TPost>,\n): ArticlesViewState<TPost> {\n const {\n categorySlug,\n articleSlug,\n searchQuery = \"\",\n groupPostsByCategory = defaultGroupPostsByCategory,\n } = options;\n\n const posts = applyPostFilters(rawPosts, { categorySlug, articleSlug });\n const { featured, rest } = splitFeaturedAndRest(posts);\n const trimmedQuery = searchQuery.trim();\n const isSearching = trimmedQuery.length > 0;\n\n const categoryGroups = isSearching\n ? posts.length === 0\n ? []\n : [\n {\n categoryName: `Search results for \"${trimmedQuery}\"`,\n categorySlug: \"search-results\",\n posts,\n },\n ]\n : groupPostsByCategory(rest);\n\n return {\n posts,\n featured,\n rest,\n categoryGroups,\n isEmpty: !featured && rest.length === 0,\n isSearching,\n searchQuery: trimmedQuery,\n };\n}\n","// src/components/articles/articles.view.tsx\nimport { Fragment, type ReactNode } from \"react\";\nimport type {\n ArticleImageResolver,\n ArticlesViewState,\n AsteroidArticleCategoryGroup,\n AsteroidArticlePost,\n AsteroidArticlesCategoryGroupParams,\n AsteroidArticlesCategoryHeadingParams,\n AsteroidArticlesContentParams,\n AsteroidArticlesEmptyParams,\n AsteroidArticlesFeaturedCardParams,\n AsteroidArticlesHeaderParams,\n AsteroidArticlesPostCardParams,\n AsteroidArticlesPostGridParams,\n} from \"./articles.types\";\n\nexport interface ArticlesListingRenderProps<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n> {\n eyebrow?: ReactNode;\n title?: ReactNode;\n description?: ReactNode;\n renderRoot?: (params: { children: ReactNode }) => ReactNode;\n renderHeader?: (params: AsteroidArticlesHeaderParams) => ReactNode;\n renderFeaturedCard?: (params: AsteroidArticlesFeaturedCardParams<TPost>) => ReactNode;\n renderPostCard: (params: AsteroidArticlesPostCardParams<TPost>) => ReactNode;\n renderCategoryHeading?: (params: AsteroidArticlesCategoryHeadingParams<TPost>) => ReactNode;\n renderPostGrid?: (params: AsteroidArticlesPostGridParams<TPost>) => ReactNode;\n renderCategoryGroup?: (params: AsteroidArticlesCategoryGroupParams<TPost>) => ReactNode;\n renderSkeleton?: () => ReactNode;\n renderEmpty?: (params: AsteroidArticlesEmptyParams) => ReactNode;\n renderContent?: (params: AsteroidArticlesContentParams) => ReactNode;\n}\n\nexport interface RenderArticlesListingArgs<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n> {\n state: ArticlesViewState<TPost>;\n loading: boolean;\n hasError: boolean;\n error: unknown;\n cmsImage: ArticleImageResolver;\n searchNode: ReactNode;\n seoNode: ReactNode;\n jsonLdNode: ReactNode;\n renderProps: ArticlesListingRenderProps<TPost>;\n}\n\nexport function renderArticlesListingBody<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n>(args: RenderArticlesListingArgs<TPost>): ReactNode {\n const { state, loading, hasError, error, cmsImage, searchNode, seoNode, jsonLdNode, renderProps } = args;\n const {\n eyebrow,\n title,\n description,\n renderRoot,\n renderHeader,\n renderFeaturedCard,\n renderPostCard,\n renderCategoryHeading,\n renderPostGrid,\n renderCategoryGroup,\n renderSkeleton,\n renderEmpty,\n renderContent,\n } = renderProps;\n\n const headerNode = renderHeader\n ? renderHeader({ eyebrow, title, description, search: searchNode })\n : (\n <>\n {eyebrow}\n {title}\n {description}\n {searchNode}\n </>\n );\n\n const featuredNode =\n state.featured && !state.isSearching && renderFeaturedCard\n ? renderFeaturedCard({ post: state.featured, cmsImage })\n : null;\n\n const noSearchResultsNode =\n state.isSearching && !loading && state.posts.length === 0\n ? renderEmpty?.({ reason: \"no-results\", searchQuery: state.searchQuery }) ?? null\n : null;\n\n const groupsNode = noSearchResultsNode\n ? null\n : state.categoryGroups.map((group: AsteroidArticleCategoryGroup<TPost>) => {\n const postCards = group.posts.map((post, index) => (\n <Fragment key={post.slug ?? index}>\n {renderPostCard({ post, index, group, cmsImage })}\n </Fragment>\n ));\n\n const gridNode = renderPostGrid\n ? renderPostGrid({ posts: group.posts, group, children: postCards })\n : <>{postCards}</>;\n\n const headingNode = renderCategoryHeading\n ? renderCategoryHeading({ group })\n : group.categoryName;\n\n const defaultContent = (\n <>\n {headingNode}\n {gridNode}\n </>\n );\n\n return (\n <Fragment key={group.categorySlug}>\n {renderCategoryGroup ? renderCategoryGroup({ group, defaultContent }) : defaultContent}\n </Fragment>\n );\n });\n\n const contentNode =\n !loading && !hasError && (state.featured || state.rest.length > 0)\n ? renderContent\n ? renderContent({ featured: featuredNode, groups: groupsNode, noSearchResults: noSearchResultsNode })\n : (\n <>\n {featuredNode}\n {noSearchResultsNode}\n {groupsNode}\n </>\n )\n : null;\n\n const body = (\n <>\n {seoNode}\n {jsonLdNode}\n {headerNode}\n {loading ? renderSkeleton?.() : null}\n {!loading && (hasError || state.isEmpty)\n ? renderEmpty?.({\n reason: hasError ? \"error\" : state.isSearching ? \"no-results\" : \"no-posts\",\n searchQuery: state.searchQuery,\n error,\n })\n : null}\n {contentNode}\n </>\n );\n\n return renderRoot ? renderRoot({ children: body }) : <>{body}</>;\n}\n","// src/components/articles/AsteroidArticlesListingServer.tsx\nimport { type ReactNode } from \"react\";\nimport { ArticleSearchBox, type ArticleSearchBoxProps } from \"@asteroidcms/core-utils/client\";\nimport { buildCollectionJsonLd } from \"../../seo/jsonld\";\nimport { createImageResolver } from \"../../utils/cmsImage\";\nimport { fetchArticles, type ArticleSource } from \"../../server/defineArticleSource\";\nimport { buildArticlesViewState } from \"./articles.state\";\nimport { renderArticlesListingBody, type ArticlesListingRenderProps } from \"./articles.view\";\nimport type {\n ArticlesViewState,\n AsteroidArticleCategoryGroup,\n AsteroidArticlePost,\n AsteroidArticlesSearchParams,\n} from \"./articles.types\";\n\nexport interface AsteroidArticlesListingServerProps<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n> extends ArticlesListingRenderProps<TPost> {\n source: ArticleSource<TPost>;\n searchQuery?: string;\n categorySlug?: string;\n articleSlug?: string;\n searchParamKey?: string;\n limit?: number;\n noindex?: boolean;\n searchBoxProps?: Omit<ArticleSearchBoxProps, \"paramKey\">;\n renderSearch?: (params: AsteroidArticlesSearchParams) => ReactNode;\n renderJsonLd?: (state: ArticlesViewState<TPost>) => ReactNode;\n groupPostsByCategory?: (posts: TPost[]) => AsteroidArticleCategoryGroup<TPost>[];\n}\n\nexport async function AsteroidArticlesListingServer<\n TPost extends AsteroidArticlePost = AsteroidArticlePost,\n>(props: AsteroidArticlesListingServerProps<TPost>) {\n const {\n source,\n searchQuery = \"\",\n categorySlug,\n articleSlug,\n searchParamKey = \"q\",\n limit,\n noindex,\n searchBoxProps,\n renderSearch,\n renderJsonLd,\n groupPostsByCategory,\n ...renderProps\n } = props;\n\n let rawPosts: TPost[] = [];\n let hasError = false;\n let error: unknown = undefined;\n try {\n rawPosts = await fetchArticles(source, { searchQuery, categorySlug, limit });\n } catch (err) {\n hasError = true;\n error = err;\n }\n\n const state = buildArticlesViewState(rawPosts, {\n categorySlug,\n articleSlug,\n searchQuery,\n groupPostsByCategory,\n });\n\n const cmsImage = createImageResolver({ cmsUrl: source.seo.cmsUrl ?? source.client.cmsUrl });\n const categoryName = categorySlug ? state.posts[0]?.category?.name?.trim() : undefined;\n\n const collection = buildCollectionJsonLd({\n name: categoryName || `${source.seo.siteName} ${source.seo.contentLabel ?? \"Articles\"}`,\n description: source.seo.defaultDescription || \"\",\n url: `${(source.seo.baseUrl || \"\").replace(/\\/$/, \"\")}${source.seo.articlePath ?? \"/blog\"}${\n categorySlug ? `/category/${categorySlug}` : \"\"\n }`,\n siteUrl: (source.seo.baseUrl || \"\").replace(/\\/$/, \"\"),\n });\n const jsonLdNode =\n renderJsonLd?.(state) ?? (\n <script type=\"application/ld+json\" dangerouslySetInnerHTML={{ __html: JSON.stringify(collection) }} />\n );\n\n // On the SERVER, search is URL-driven: the default ArticleSearchBox (or custom client island)\n // writes the searchParamKey query param, and the page re-renders from searchParams.\n // A custom renderSearch should render its own client island to update the URL param;\n // the onChange/onSubmit stubs below are inert placeholders kept only for API shape compatibility.\n const searchNode = renderSearch\n ? renderSearch({ value: searchQuery, onChange: () => {}, onSubmit: (e) => e.preventDefault() })\n : <ArticleSearchBox paramKey={searchParamKey} {...searchBoxProps} />;\n\n return (\n <>\n {renderArticlesListingBody({\n state,\n loading: false,\n hasError,\n error,\n cmsImage,\n searchNode,\n seoNode: null,\n jsonLdNode,\n renderProps: renderProps as ArticlesListingRenderProps<TPost>,\n })}\n </>\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","// src/components/articles/article.view.tsx\nimport type { ReactNode } from \"react\";\nimport type { ArticleImageResolver } from \"./articles.types\";\n\nexport interface AsteroidArticlePagePost {\n slug: string;\n title: string;\n description?: string;\n content?: string;\n featured_image?: string;\n tags?: string;\n published_date?: string | null;\n category?: { slug: string; name: string };\n author?: { name: string; bio?: string };\n}\n\ntype Slot<TPost> = (params: { post: TPost; cmsImage: ArticleImageResolver }) => ReactNode;\n\nexport interface ArticleBodyRenderProps<\n TPost extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n> {\n backLink?: ReactNode;\n renderHeader?: Slot<TPost>;\n renderMeta?: Slot<TPost>;\n renderDescription?: Slot<TPost>;\n renderFeaturedImage?: Slot<TPost>;\n renderToc?: Slot<TPost>;\n renderContent?: Slot<TPost>;\n renderPreArticle?: Slot<TPost>;\n renderMidArticle?: Slot<TPost>;\n renderPostArticle?: Slot<TPost>;\n renderTags?: Slot<TPost>;\n renderAuthorDetails?: Slot<TPost>;\n renderRelatedPosts?: (params: {\n post: TPost;\n relatedPosts: TPost[];\n cmsImage: ArticleImageResolver;\n }) => ReactNode;\n renderCTA?: Slot<TPost>;\n}\n\nexport interface RenderArticleBodyArgs<\n TPost extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n> {\n post: TPost;\n cmsImage: ArticleImageResolver;\n relatedPosts: TPost[];\n seoNode: ReactNode;\n jsonLdNode: ReactNode;\n renderProps: ArticleBodyRenderProps<TPost>;\n}\n\nexport function renderArticleBody<\n TPost extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n>(args: RenderArticleBodyArgs<TPost>): ReactNode {\n const { post, cmsImage, relatedPosts, seoNode, jsonLdNode, renderProps: r } = args;\n const slot = { post, cmsImage };\n\n return (\n <>\n {seoNode}\n {jsonLdNode}\n {r.backLink}\n {r.renderPreArticle?.(slot)}\n {r.renderHeader?.(slot)}\n {r.renderMeta?.(slot)}\n {r.renderDescription?.(slot)}\n {r.renderFeaturedImage?.(slot)}\n {r.renderToc?.(slot)}\n {r.renderContent?.(slot)}\n {r.renderMidArticle?.(slot)}\n {r.renderTags?.(slot)}\n {r.renderAuthorDetails?.(slot)}\n {r.renderRelatedPosts?.({ post, relatedPosts, cmsImage })}\n {r.renderCTA?.(slot)}\n {r.renderPostArticle?.(slot)}\n </>\n );\n}\n","// src/components/articles/AsteroidArticlePageServer.tsx\nimport { type ReactNode } from \"react\";\nimport { buildArticleSeoValues } from \"../../seo/seo.builders\";\nimport { buildArticleJsonLd, type ArticleJsonLdType } from \"../../seo/jsonld\";\nimport { createImageResolver } from \"../../utils/cmsImage\";\nimport {\n fetchArticle,\n fetchRelatedArticles,\n type ArticleSource,\n} from \"../../server/defineArticleSource\";\nimport {\n renderArticleBody,\n type ArticleBodyRenderProps,\n type AsteroidArticlePagePost,\n} from \"./article.view\";\n\nexport interface AsteroidArticlePageServerProps<\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n> extends ArticleBodyRenderProps<TDetail> {\n source: ArticleSource<AsteroidArticlePagePost, TDetail>;\n slug: string;\n articleType?: ArticleJsonLdType;\n noindex?: boolean;\n renderError?: (params: { error?: unknown; reason: \"error\" | \"not-found\" }) => ReactNode;\n renderJsonLd?: (params: { post: TDetail }) => ReactNode;\n}\n\nexport async function AsteroidArticlePageServer<\n TDetail extends AsteroidArticlePagePost = AsteroidArticlePagePost,\n>(props: AsteroidArticlePageServerProps<TDetail>) {\n const { source, slug, articleType, noindex, renderError, renderJsonLd, ...bodyRenderProps } = props;\n\n const article = await fetchArticle(source, slug);\n if (!article) {\n return <>{renderError?.({ reason: \"not-found\" }) ?? null}</>;\n }\n\n const relatedPosts = await fetchRelatedArticles(source, article, slug);\n const cmsImage = createImageResolver({ cmsUrl: source.seo.cmsUrl ?? source.client.cmsUrl });\n const type = articleType ?? source.articleType;\n\n const seoValues = buildArticleSeoValues(article, source.seo, slug, { noindex });\n\n const articleLd = buildArticleJsonLd({\n title: article.title,\n description: article.description || source.seo.defaultDescription || \"\",\n url: `${(source.seo.baseUrl || \"\").replace(/\\/$/, \"\")}${source.seo.articlePath ?? \"/blog\"}/${slug}`,\n siteName: source.seo.siteName,\n siteUrl: (source.seo.baseUrl || \"\").replace(/\\/$/, \"\"),\n articleType: type,\n image: seoValues.image,\n authorName: article.author?.name,\n publishedTime: article.published_date || undefined,\n tags: article.tags?.split(\",\").map((t) => t.trim()).filter(Boolean),\n category: article.category?.name,\n });\n const jsonLdNode =\n renderJsonLd?.({ post: article }) ?? (\n <script type=\"application/ld+json\" dangerouslySetInnerHTML={{ __html: JSON.stringify(articleLd) }} />\n );\n\n return (\n <>\n {renderArticleBody({\n post: article,\n cmsImage,\n relatedPosts,\n seoNode: null,\n jsonLdNode,\n renderProps: bodyRenderProps as ArticleBodyRenderProps<TDetail>,\n })}\n </>\n );\n}\n","// src/server/articleMetadata.ts\nimport type { Metadata } from \"next\";\nimport {\n buildArticleListingSeoValues,\n buildArticleSeoValues,\n} from \"../seo/seo.builders\";\nimport type { ISeoValues } from \"../seo/seo.config\";\nimport { fetchArticle, type ArticleSource } from \"./defineArticleSource\";\nimport type { AsteroidArticlePagePost } from \"../components/articles/article.view\";\nimport type { AsteroidArticlePost } from \"../components/articles/articles.types\";\n\nexport function seoValuesToMetadata(\n v: ISeoValues,\n ogType: \"website\" | \"article\",\n): Metadata {\n return {\n title: v.title,\n description: v.description,\n publisher: v.siteName,\n keywords: v.keywords,\n category: v.title,\n ...(v.manifestUrl ? { manifest: v.manifestUrl } : {}),\n robots: v.noindex ? { index: false, follow: true } : { index: true, follow: true },\n authors: { name: v.siteName },\n referrer: \"origin\",\n abstract: v.description,\n alternates: { canonical: v.url },\n openGraph: {\n title: v.title,\n description: v.description,\n url: v.url,\n siteName: v.siteName,\n locale: \"en_US\",\n type: ogType,\n ...(v.image ? { images: [{ url: v.image }] } : {}),\n },\n twitter: {\n title: v.title,\n description: v.description,\n site: v.twitter || undefined,\n card: v.image ? \"summary_large_image\" : \"summary\",\n ...(v.image ? { images: [v.image] } : {}),\n },\n };\n}\n\nexport async function generateListingMetadata(\n source: ArticleSource,\n options?: { categoryName?: string; categorySlug?: string; noindex?: boolean },\n): Promise<Metadata> {\n return seoValuesToMetadata(buildArticleListingSeoValues(source.seo, options), \"website\");\n}\n\nexport async function generateArticleMetadata(\n source: ArticleSource<AsteroidArticlePost, AsteroidArticlePagePost>,\n paramsOrSlug: string | { slug: string } | Promise<{ slug: string }>,\n): Promise<Metadata> {\n const resolved = await paramsOrSlug;\n const slug = typeof resolved === \"string\" ? resolved : resolved.slug;\n const article = await fetchArticle(source, slug);\n if (!article) {\n return seoValuesToMetadata(buildArticleListingSeoValues(source.seo), \"website\");\n }\n return seoValuesToMetadata(buildArticleSeoValues(article, source.seo, slug), \"article\");\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asteroidcms/core-utils",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Seamless integration utilities for Asteroid CMS — Apollo provider, content hooks, and rich-text rendering.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"asteroidcms",
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
"types": "./dist/next.d.ts",
|
|
39
39
|
"import": "./dist/next.js",
|
|
40
40
|
"require": "./dist/next.cjs"
|
|
41
|
+
},
|
|
42
|
+
"./server": {
|
|
43
|
+
"types": "./dist/server.d.ts",
|
|
44
|
+
"import": "./dist/server.js",
|
|
45
|
+
"require": "./dist/server.cjs"
|
|
41
46
|
}
|
|
42
47
|
},
|
|
43
48
|
"files": [
|
|
@@ -52,6 +57,9 @@
|
|
|
52
57
|
"build": "tsup",
|
|
53
58
|
"dev": "tsup --watch",
|
|
54
59
|
"typecheck": "tsc --noEmit",
|
|
60
|
+
"lint": "eslint src",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest",
|
|
55
63
|
"prepublishOnly": "npm run build"
|
|
56
64
|
},
|
|
57
65
|
"peerDependencies": {
|
|
@@ -73,11 +81,15 @@
|
|
|
73
81
|
"@apollo/client": "^4.0.0",
|
|
74
82
|
"@types/react": "^18.3.0",
|
|
75
83
|
"@types/react-dom": "^18.3.0",
|
|
84
|
+
"eslint": "^10.5.0",
|
|
76
85
|
"graphql": "^16.9.0",
|
|
77
86
|
"next": "^16.2.9",
|
|
78
87
|
"react": "^18.3.0",
|
|
79
88
|
"react-dom": "^18.3.0",
|
|
89
|
+
"server-only": "^0.0.1",
|
|
80
90
|
"tsup": "^8.3.0",
|
|
81
|
-
"typescript": "^5.6.0"
|
|
91
|
+
"typescript": "^5.6.0",
|
|
92
|
+
"typescript-eslint": "^8.62.0",
|
|
93
|
+
"vitest": "^2.1.0"
|
|
82
94
|
}
|
|
83
95
|
}
|