/** * Configuration for the SEO Faster client */ interface SEOFasterConfig { /** Your SEO Faster API key (secret: cp_seof_sec_* for Next.js, public: cp_seof_pub_* for static sites) */ apiKey: string; /** Base URL for the API. Defaults to https://engine.seofaster.app */ baseUrl?: string; } /** * Featured image for an article */ interface FeaturedImage { url: string; alt?: string; } /** * FAQ item with question and answer */ interface FAQ { question: string; answer: string; } /** * Article content with markdown and optional HTML */ interface ArticleContent { /** Markdown content of the article */ markdown: string; /** HTML content (if available) */ html?: string; } /** * Article author information */ interface ArticleAuthor { name: string; title?: string; photo?: { url: string; alt?: string; }; } /** * Article returned from SEO Faster API */ interface Article { _id: string; title: string; slug: string; /** Article content in markdown/html format */ content: ArticleContent; metaDescription?: string; featuredImage?: FeaturedImage; faqs?: FAQ[]; author?: ArticleAuthor; seoScore?: number; locale?: string; status: 'draft' | 'published'; /** Category tag (B.15) — used by category-aware routes */ category?: string; publishedAt?: string; createdAt: string; updatedAt: string; /** * Locales this article exists in (B.15). Surfaced by * `GET /api/content/public/slug/:slug` for locale-switcher UIs that * need to disable unavailable locales rather than render dead links. */ availableLocales?: string[]; } /** * Response from getArticles API call */ interface ArticleListResponse { articles: Article[]; total: number; totalPages: number; page: number; limit: number; } /** * Slim article for card display (no HTML content) * Used by getRelatedArticles for better performance */ interface SlimArticle { _id: string; slug: string; title: string; metaDescription?: string; featuredImage?: FeaturedImage; publishedAt?: string; createdAt: string; locale?: string; category?: string; readingTime?: number; author?: { name: string; avatar?: string; }; } /** * Options for fetching related articles (slim payload) */ interface FetchRelatedArticlesOptions { /** Maximum number of articles to return. Defaults to 6, max 20 */ limit?: number; /** Filter by locale (e.g., 'en', 'es', 'fr') */ locale?: string; /** Exclude article with this slug (typically the current article) */ excludeSlug?: string; /** Next.js cache options for on-demand revalidation */ next?: NextCacheOptions; } /** * Next.js cache options for on-demand revalidation */ interface NextCacheOptions { /** Cache tags for selective revalidation via revalidateTag() */ tags?: string[]; /** Time-based revalidation in seconds */ revalidate?: number | false; } /** * Options for fetching articles */ interface FetchArticlesOptions { /** Page number (1-indexed). Defaults to 1 */ page?: number; /** Number of articles per page. Defaults to 10 */ limit?: number; /** Filter by locale (e.g., 'en', 'es', 'fr') */ locale?: string; /** Filter by article category (e.g., 'use-cases', 'comparisons'). B.5 */ category?: string; /** Next.js cache options for on-demand revalidation */ next?: NextCacheOptions; } /** * Options for fetching a single article */ interface FetchArticleOptions { /** Filter by locale (e.g., 'en', 'es', 'fr') */ locale?: string; /** Next.js cache options for on-demand revalidation */ next?: NextCacheOptions; } /** * Options for the bulk-by-slugs fetch (B.6) */ interface FetchBulkArticlesOptions { /** Filter by locale. Defaults to workspace default if omitted. */ locale?: string; /** Next.js cache options for on-demand revalidation */ next?: NextCacheOptions; } /** * Response shape from POST /api/content/public/batch */ interface BulkArticlesResponse { /** Articles found, in unspecified order */ articles: Article[]; /** Slugs from the request that didn't match a published article */ notFound: string[]; /** Number of articles found */ count: number; /** Locale that was actually queried (may differ from `locale` opt if invalid) */ returnedLocale: string; /** Locale that the caller originally requested */ requestedLocale: string | null; } /** * SEO Faster API client interface */ interface SEOFasterClient { /** * Fetch a list of published articles * @param options - Pagination, filter, and cache options * @returns Promise with articles array and pagination info */ getArticles(options?: FetchArticlesOptions): Promise; /** * Fetch a single article by its slug * @param slug - The article slug * @param options - Locale and cache options * @returns Promise with article or null if not found */ getArticleBySlug(slug: string, options?: FetchArticleOptions): Promise
; /** * Fetch related articles with slim payload (no HTML content) * Optimized for card display - ~90% smaller payload than getArticles * @param options - Filter and cache options * @returns Promise with slim articles array */ getRelatedArticles(options?: FetchRelatedArticlesOptions): Promise; /** * Probe backend health (B.17). * * Lightweight HEAD-style check that hits `/api/health`. Returns * `{ healthy, status, mongodb, redis }`. `healthy` is true iff the * backend reports `status: 'ok'`. Use in route handlers that can degrade * gracefully when the backend is having a bad time (return a cached * banner, skip optional fetches, etc.) — NOT in the hot path of every * request, since this is still a network round trip. */ isHealthy(): Promise<{ healthy: boolean; status: string; mongodb: string; redis: string; redisLatencyMs?: number; error?: string; }>; /** * Fetch many articles by slug list in a single request (B.6). * Backed by POST /api/content/public/batch (added in Aℓ.4). * * Cuts per-page fan-out from N parallel `getArticleBySlug` calls to one. * Cap: 50 slugs per request — split into multiple calls for larger sets. * * @param slugs - Array of slugs (1–50), strings ≤ 256 chars * @param options - Locale + Next.js cache options * @returns Promise with articles + a `notFound[]` list of slugs that didn't match */ getArticlesByBulk(slugs: string[], options?: FetchBulkArticlesOptions): Promise; } /** * Configuration for the cached client */ interface CachedClientConfig extends SEOFasterConfig { /** * Enable unstable_cache for cross-request persistence * @default true */ enableUnstableCache?: boolean; } /** * Cached client interface with dual-layer caching */ interface CachedClient { getArticleBySlug(slug: string, locale?: string): Promise
; getArticles(options?: FetchArticlesOptions): Promise; getRelatedArticles(options?: FetchRelatedArticlesOptions): Promise; _client: SEOFasterClient; } /** * Configuration for static params generator */ interface StaticParamsGeneratorConfig extends SEOFasterConfig { locales: string[]; fallbackLocale?: string; batchSize?: number; /** Delay in ms between paginated fetches (rate-limit cushion). Default 200. */ batchDelay?: number; maxPaginatedPages?: number; articlesPerPage?: number; /** * Generation mode (B.4): * 'full' — fetch all articles at build (default; pre-renders every slug) * 'empty' — return [] / empty maps synchronously; every page generates * on first visit and is then cached forever by Next.js ISR. * Pair with `dynamicParams: true` + `revalidate = false` on * the route. Build time drops to ~0 SEOFaster calls; first * visitor pays ~1s render, every subsequent visit hits the * cache. Webhooks invalidate per-article tags. */ mode?: 'full' | 'empty'; } /** * Result type for blog article static params */ interface BlogArticleParam { locale: string; slug: string; } /** * Result type for blog paginated static params */ interface BlogPaginatedParam { locale: string; page: string; } /** * Result type for blog list static params */ interface BlogListParam { locale: string; } /** * Static params generator result */ interface StaticParamsResult { blogArticle(): Promise; blogList(): Promise; blogPaginated(): Promise; getAllSlugs(): Promise>; _client: SEOFasterClient; _config: StaticParamsGeneratorConfig; } export type { Article as A, BlogArticleParam as B, CachedClientConfig as C, FetchArticlesOptions as F, SEOFasterConfig as S, SEOFasterClient as a, ArticleContent as b, ArticleAuthor as c, ArticleListResponse as d, FetchRelatedArticlesOptions as e, FeaturedImage as f, FAQ as g, SlimArticle as h, CachedClient as i, StaticParamsGeneratorConfig as j, StaticParamsResult as k, BlogPaginatedParam as l, BlogListParam as m };