UNPKG

next-blog-ai

Version:

AI-powered blog generation and content delivery for Next.js and other frameworks

794 lines (788 loc) 26.2 kB
/** * Configuration options for NextBlogAI client */ interface NextBlogAIConfig { /** * API key for authentication with Next-Blog-AI service */ apiKey: string; /** * Default format for content responses * @default 'html' */ defaultFormat?: ContentFormat; /** * Default display format for blog lists * @default 'grid' */ defaultBlogListDisplay?: BlogListDisplayFormat; /** * Default TTL for cache in seconds * @default 3600 (1 hour) */ defaultCacheTTL?: number; /** * Retry options for failed requests */ retry?: RetryOptions; /** * Custom CSS styles for HTML content */ styles?: { /** * Custom CSS for blog post detail content */ blogContent?: string; /** * Custom CSS for blog listing pages */ blogList?: string; }; /** * Default fetch options to apply to all requests * Useful for Next.js App Router to control caching behavior */ defaultFetchOptions?: { /** * Fetch cache mode: 'default', 'no-store', 'reload', 'force-cache', etc. * Must be one of the valid RequestCache types from the Fetch API */ cache?: RequestCache; /** * Next.js specific options for fetch */ next?: { /** * Revalidation time in seconds */ revalidate?: number; }; /** * Any other fetch options */ [key: string]: any; }; } /** * Format for content responses */ type ContentFormat = 'html' | 'json'; /** * Display format for blog lists */ type BlogListDisplayFormat = 'grid' | 'list'; /** * Options for caching */ interface CacheOptions { /** * Time to live in seconds */ ttl?: number; /** * Whether to bypass the cache and force a fresh fetch */ bypassCache?: boolean; /** * Framework-specific fetch options to be passed directly to the fetch API * For Next.js, use: { cache: 'no-store' } to force dynamic rendering, * or { next: { revalidate: seconds } } for incremental static regeneration */ fetchOptions?: { /** * Fetch cache mode: 'default', 'no-store', 'reload', 'force-cache', etc. * Must be one of the valid RequestCache types from the Fetch API */ cache?: RequestCache; /** * Next.js specific options for fetch */ next?: { /** * Revalidation time in seconds */ revalidate?: number; }; /** * Any other fetch options */ [key: string]: any; }; /** * Framework-specific caching options */ [key: string]: any; } /** * Error response from the API */ interface ErrorResponse { /** * Error message */ message: string; /** * HTTP status code */ status: number; /** * Error code * Common error codes: * - 'INVALID_API_KEY': API key is invalid or missing * - 'RATE_LIMITED': Rate limit exceeded * - 'NETWORK_ERROR': Network connectivity issues * - 'HTTP_404': Resource not found * - 'HTTP_500': Server error */ code?: string; } /** * Blog list options */ interface BlogListOptions { /** * Page number * @default 1 */ page?: number; /** * Number of posts per page * @default 10 */ perPage?: number; /** * Format for response */ format?: ContentFormat; /** * Display format for the blog list (only applies to HTML format) * @default 'grid' */ display?: BlogListDisplayFormat; /** * Cache options */ cache?: CacheOptions; } /** * Blog post options */ interface BlogPostOptions { /** * Format for response */ format?: ContentFormat; /** * Cache options */ cache?: CacheOptions; } /** * Comment submission data */ interface CommentData { /** * ID of the blog post to comment on */ postId: string; /** * Name of the comment author */ authorName: string; /** * Email of the comment author (optional) */ authorEmail?: string; /** * Content of the comment */ content: string; } /** * Base response from the API */ interface ApiResponse<T> { /** * Response data */ data?: T; /** * Error information (if any) */ error?: ErrorResponse; } /** * Pagination information */ interface Pagination { /** * Total number of posts */ totalPosts: number; /** * Total number of pages */ totalPages: number; /** * Current page number */ currentPage: number; /** * Number of posts per page */ perPage: number; } /** * Blog post summary (for list view) */ interface BlogPostSummary { /** * Post ID */ id: string; /** * Post title */ title: string; /** * Post slug */ slug: string; /** * Post excerpt */ excerpt: string; /** * URL to featured image */ featuredImageUrl?: string; /** * Published date */ publishedAt: string; /** * Estimated reading time in minutes */ readingTime: number; /** * Comment count */ commentCount: number; /** * Language code (ISO 639-1) */ language: string; /** * Publisher name */ publisherName?: string; } /** * SEO metadata */ interface SEOMetadata { /** * Page title */ title: string; /** * Page description */ description: string; /** * Keywords */ keywords: string[]; /** * JSON-LD structured data for Schema.org */ structuredData: string | object; /** * Featured image for social sharing (Open Graph, Twitter cards) */ featuredImage?: { /** * URL of the featured image */ url: string; /** * Alt text for the featured image */ alt: string; }; } /** * Blog list response in HTML format */ interface BlogListHtmlResponse { /** * Response format */ format: 'html'; /** * HTML content with inline styles */ content: string; /** * SEO metadata */ seo: SEOMetadata; /** * Pagination information */ pagination: Pagination; } /** * Blog list response in JSON format */ interface BlogListJsonResponse { /** * Response format */ format: 'json'; /** * List of blog posts */ posts: BlogPostSummary[]; /** * SEO metadata */ seo: SEOMetadata; /** * Pagination information */ pagination: Pagination; } /** * Combined blog list response type */ type BlogListResponse = BlogListHtmlResponse | BlogListJsonResponse; /** * Full blog post */ interface BlogPost { /** * Post ID */ id: string; /** * Post title */ title: string; /** * Post slug */ slug: string; /** * Full post content */ content: string; /** * Post excerpt */ excerpt: string; /** * URL to featured image */ featuredImageUrl?: string; /** * Published date */ publishedAt: string; /** * Estimated reading time in minutes */ readingTime: number; /** * Language code (ISO 639-1) */ language: string; } /** * Comment on a blog post */ interface Comment { /** * Comment ID */ id: string; /** * Name of the comment author */ authorName: string; /** * Content of the comment */ content: string; /** * Created date */ createdAt: string; } /** * Blog post response in HTML format */ interface BlogPostHtmlResponse { /** * Response format */ format: 'html'; /** * HTML content with inline styles */ content: string; /** * HTML for comment form */ commentForm: string; /** * HTML for comments */ comments: string; /** * SEO metadata */ seo: SEOMetadata; } /** * Blog post response in JSON format */ interface BlogPostJsonResponse { /** * Response format */ format: 'json'; /** * Blog post data */ post: BlogPost; /** * Comments on the post */ comments: Comment[]; /** * SEO metadata */ seo: SEOMetadata; } /** * Combined blog post response type */ type BlogPostResponse = BlogPostHtmlResponse | BlogPostJsonResponse; /** * Comment submission response */ interface CommentResponse { /** * Success flag */ success: boolean; /** * Response message */ message: string; /** * Comment data */ comment?: Comment; } /** * Options for controlling retry behavior */ interface RetryOptions { /** * Maximum number of retry attempts * @default 3 */ maxRetries?: number; /** * Initial delay before first retry (in milliseconds) * @default 300 */ initialDelay?: number; /** * Factor by which to increase delay after each retry * @default 2 */ backoffFactor?: number; /** * Maximum delay between retries (in milliseconds) * @default 10000 (10 seconds) */ maxDelay?: number; /** * Whether to add jitter to retry delays to prevent thundering herd problem * @default true */ jitter?: boolean; } /** * Options for fetching only SEO metadata */ interface SEOOptions { /** * Cache options */ cache?: CacheOptions; } /** * SEO metadata response */ interface SEOResponse { /** * SEO metadata */ seo: SEOMetadata; } /** * Options for fetching only blog list SEO metadata */ interface BlogListSEOOptions { /** * Page number * @default 1 */ page?: number; /** * Number of posts per page * @default 10 */ perPage?: number; /** * Cache options */ cache?: CacheOptions; } /** * Blog list SEO metadata response */ interface BlogListSEOResponse { /** * SEO metadata */ seo: SEOMetadata; } /** * Options for fetching all blog slugs */ interface BlogSlugsOptions { /** * Cache options */ cache?: CacheOptions; } /** * Response containing all blog slugs */ interface BlogSlugsResponse { /** * Array of blog post slugs */ slugs: string[]; } /** * NextBlogAI Client * Main class for interacting with the Next-Blog-AI API */ declare class NextBlogAI { private apiKey; private apiUrl; private defaultFormat; private defaultBlogListDisplay; private defaultCacheTTL; private cache; private retryOptions; private pendingRequests; private customStyles; private defaultFetchOptions?; /** * Default retry options */ private static readonly DEFAULT_RETRY_OPTIONS; /** * Create a new instance of NextBlogAI client */ constructor(config: NextBlogAIConfig); /** * Generate a cache key from the request parameters */ private generateCacheKey; /** * Get data from cache if available and not expired */ private getFromCache; /** * Store data in cache */ private storeInCache; /** * Calculate retry delay with exponential backoff and optional jitter */ private getRetryDelay; /** * Sleep for specified milliseconds */ private sleep; /** * Make API request with proper error handling and retry mechanism */ private makeRequest; /** * Execute the actual API request with retries */ private executeRequest; /** * Get a list of blog posts */ getBlogPosts(options?: BlogListOptions): Promise<ApiResponse<BlogListResponse>>; /** * Get a single blog post by slug */ getBlogPost(slug: string, options?: BlogPostOptions): Promise<ApiResponse<BlogPostResponse>>; /** * Submit a comment on a blog post */ submitComment(data: CommentData): Promise<ApiResponse<CommentResponse>>; /** * Get only SEO metadata for a blog post by slug * Optimized version that doesn't fetch the full content */ getBlogPostSEO(slug: string, options?: SEOOptions): Promise<ApiResponse<SEOResponse>>; /** * Get only SEO metadata for blog list * Optimized version that doesn't fetch the full content */ getBlogListSEO(options?: BlogListSEOOptions): Promise<ApiResponse<BlogListSEOResponse>>; /** * Get all blog post slugs * Useful for static site generation in frameworks like Next.js */ getAllBlogSlugs(options?: BlogSlugsOptions): Promise<ApiResponse<BlogSlugsResponse>>; /** * Clear the entire cache */ clearCache(): void; /** * Clear a specific item from the cache */ clearCacheItem(endpoint: string, params: Record<string, any>): void; /** * Set custom styles for HTML content */ setStyles(styles: { blogContent?: string; blogList?: string; }): void; } /** * Factory function to create a new NextBlogAI instance */ declare function createNextBlogAI(config: NextBlogAIConfig): NextBlogAI; /** * Next.js specific caching options */ interface NextCacheOptions { /** * Next.js revalidation time in seconds * When set to 0, cache will be bypassed completely (equivalent to dynamic: true) */ revalidate?: number; /** * Force dynamic rendering without caching */ dynamic?: boolean; } /** * Blog list options with Next.js specific caching */ interface NextBlogListOptions extends Omit<BlogListOptions, 'cache'> { /** * Next.js specific caching options */ next?: NextCacheOptions; } /** * Blog post options with Next.js specific caching */ interface NextBlogPostOptions extends Omit<BlogPostOptions, 'cache'> { /** * Next.js specific caching options */ next?: NextCacheOptions; } /** * SEO options with Next.js specific caching */ interface NextSEOOptions extends Omit<SEOOptions, 'cache'> { /** * Next.js specific caching options */ next?: NextCacheOptions; } /** * Blog list SEO options with Next.js specific caching */ interface NextBlogListSEOOptions extends Omit<BlogListSEOOptions, 'cache'> { /** * Next.js specific caching options */ next?: NextCacheOptions; } /** * Blog slugs options with Next.js specific caching */ interface NextBlogSlugsOptions extends Omit<BlogSlugsOptions, 'cache'> { /** * Next.js specific caching options */ next?: NextCacheOptions; } /** * Higher-order function that wraps a NextBlogAI method with Next.js caching */ declare function withNextCache<T, O extends object>(fn: (client: NextBlogAI, ...args: any[]) => Promise<ApiResponse<T>>): (client: NextBlogAI, ...args: any[]) => Promise<ApiResponse<T>>; /** * Get blog posts with Next.js caching */ declare function getBlogPostsWithNextCache(client: NextBlogAI, options?: NextBlogListOptions): Promise<ApiResponse<BlogListResponse>>; /** * Get a blog post with Next.js caching */ declare function getBlogPostWithNextCache(client: NextBlogAI, slug: string, options?: NextBlogPostOptions): Promise<ApiResponse<BlogPostResponse>>; /** * Get blog post SEO metadata with Next.js caching */ declare function getBlogPostSEOWithNextCache(client: NextBlogAI, slug: string, options?: NextSEOOptions): Promise<ApiResponse<SEOResponse>>; /** * Get blog list SEO metadata with Next.js caching */ declare function getBlogListSEOWithNextCache(client: NextBlogAI, options?: NextBlogListSEOOptions): Promise<ApiResponse<BlogListSEOResponse>>; /** * Get all blog slugs with Next.js caching */ declare function getAllBlogSlugsWithNextCache(client: NextBlogAI, options?: NextBlogSlugsOptions): Promise<ApiResponse<BlogSlugsResponse>>; declare function createNextBlogAIForNextJs(apiKey: string, defaultCacheOptions?: NextCacheOptions): { client: NextBlogAI; getBlogPosts: (options?: NextBlogListOptions) => Promise<ApiResponse<BlogListResponse>>; getBlogPost: (slug: string, options?: NextBlogPostOptions) => Promise<ApiResponse<BlogPostResponse>>; getBlogPostSEO: (slug: string, options?: NextSEOOptions) => Promise<ApiResponse<SEOResponse>>; getBlogListSEO: (options?: NextBlogListSEOOptions) => Promise<ApiResponse<BlogListSEOResponse>>; getAllBlogSlugs: (options?: NextBlogSlugsOptions) => Promise<ApiResponse<BlogSlugsResponse>>; }; /** * Default CSS styles for blog content */ declare const DEFAULT_BLOG_STYLES = "\n/* Base styles */\n.next-blog-ai-content {\n line-height: 1.6;\n color: inherit;\n max-width: 100%;\n margin: 0 auto;\n}\n\n/* Headings */\n.next-blog-ai-content h1,\n.next-blog-ai-content h2,\n.next-blog-ai-content h3,\n.next-blog-ai-content h4,\n.next-blog-ai-content h5,\n.next-blog-ai-content h6 {\n margin-top: 2rem;\n margin-bottom: 1rem;\n font-weight: 600;\n line-height: 1.25;\n color: inherit;\n}\n\n.next-blog-ai-content h1 {\n font-size: 2.25rem;\n}\n\n.next-blog-ai-content h2 {\n font-size: 1.75rem;\n border-bottom: 1px solid #eee;\n padding-bottom: 0.3rem;\n}\n\n.next-blog-ai-content h3 {\n font-size: 1.5rem;\n}\n\n.next-blog-ai-content h4 {\n font-size: 1.25rem;\n}\n\n.next-blog-ai-content h5, .next-blog-ai-content h6 {\n font-size: 1rem;\n}\n\n/* Paragraphs and text */\n.next-blog-ai-content p {\n margin-top: 0;\n margin-bottom: 1.5rem;\n}\n\n.next-blog-ai-content strong {\n font-weight: 600;\n}\n\n.next-blog-ai-content em {\n font-style: italic;\n}\n\n/* Lists */\n.next-blog-ai-content ul,\n.next-blog-ai-content ol {\n margin-top: 0;\n margin-bottom: 1.5rem;\n padding-left: 2rem;\n}\n\n.next-blog-ai-content li {\n margin-bottom: 0.5rem;\n}\n\n.next-blog-ai-content li > ul,\n.next-blog-ai-content li > ol {\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n}\n\n/* Links */\n.next-blog-ai-content a {\n color: #0070f3;\n text-decoration: none;\n}\n\n.next-blog-ai-content a:hover {\n text-decoration: underline;\n}\n\n/* Blockquotes */\n.next-blog-ai-content blockquote {\n margin: 1.5rem 0;\n padding: 0.5rem 1rem;\n border-left: 4px solid #ddd;\n color: #666;\n background-color: #f9f9f9;\n}\n\n.next-blog-ai-content blockquote > :first-child {\n margin-top: 0;\n}\n\n.next-blog-ai-content blockquote > :last-child {\n margin-bottom: 0;\n}\n\n/* Code blocks */\n.next-blog-ai-content pre {\n margin: 1.5rem 0;\n padding: 1rem;\n overflow: auto;\n background-color: #f6f8fa;\n border-radius: 3px;\n font-size: 0.875rem;\n}\n\n.next-blog-ai-content code {\n font-size: 0.875rem;\n padding: 0.2em 0.4em;\n background-color: rgba(27, 31, 35, 0.05);\n border-radius: 3px;\n}\n\n.next-blog-ai-content pre code {\n padding: 0;\n background-color: transparent;\n}\n\n/* Tables */\n.next-blog-ai-content table {\n width: 100%;\n border-collapse: collapse;\n margin: 1.5rem 0;\n}\n\n.next-blog-ai-content table th,\n.next-blog-ai-content table td {\n padding: 0.5rem 1rem;\n border: 1px solid #e1e4e8;\n}\n\n.next-blog-ai-content table th {\n background-color: #f6f8fa;\n font-weight: 600;\n text-align: left;\n}\n\n.next-blog-ai-content table tr:nth-child(even) {\n background-color: #f7f7f7;\n}\n\n/* Images */\n.next-blog-ai-content img {\n max-width: 100%;\n height: auto;\n display: block;\n margin: 1.5rem auto;\n}\n\n.next-blog-ai-content figure {\n margin: 1.5rem auto;\n text-align: center;\n}\n\n.next-blog-ai-content figcaption {\n font-size: 0.875rem;\n color: #666;\n margin-top: 0.5rem;\n}\n\n/* Comments */\n.next-blog-ai-comments {\n margin-top: 3rem;\n border-top: 1px solid #eee;\n padding-top: 2rem;\n}\n\n.next-blog-ai-comment {\n margin-bottom: 2rem;\n padding: 1rem;\n background-color: #f9f9f9;\n border-radius: 4px;\n}\n\n.next-blog-ai-comment-header {\n display: flex;\n justify-content: space-between;\n margin-bottom: 0.5rem;\n}\n\n.next-blog-ai-comment-author {\n font-weight: 600;\n}\n\n.next-blog-ai-comment-date {\n color: #666;\n font-size: 0.875rem;\n}\n\n.next-blog-ai-comment-content {\n line-height: 1.5;\n}\n\n/* Comment form */\n.next-blog-ai-comment-form {\n margin-top: 2rem;\n}\n\n.next-blog-ai-comment-form label {\n display: block;\n margin-bottom: 0.5rem;\n font-weight: 600;\n}\n\n.next-blog-ai-comment-form input,\n.next-blog-ai-comment-form textarea {\n width: 100%;\n padding: 0.5rem;\n margin-bottom: 1rem;\n border: 1px solid #ddd;\n border-radius: 4px;\n}\n\n.next-blog-ai-comment-form textarea {\n min-height: 6rem;\n}\n\n.next-blog-ai-comment-form button {\n background-color: #0070f3;\n color: white;\n border: none;\n padding: 0.5rem 1rem;\n border-radius: 4px;\n cursor: pointer;\n font-weight: 500;\n}\n\n.next-blog-ai-comment-form button:hover {\n background-color: #0060df;\n}\n"; /** * Default CSS styles for blog list */ declare const DEFAULT_BLOG_LIST_STYLES = "\n/* Blog post list - Grid View (Default) */\n.next-blog-ai-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 2rem;\n margin: 2rem 0;\n}\n\n@media (max-width: 768px) {\n .next-blog-ai-list {\n grid-template-columns: 1fr;\n }\n}\n\n/* Post content padding for grid view */\n.next-blog-ai-post-content {\n padding: 1.5rem;\n display: flex;\n flex-direction: column;\n}\n\n/* List View Styles */\n.next-blog-ai-list.list-view {\n display: block;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-card {\n display: flex;\n flex-direction: row;\n margin-bottom: 2rem;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-card:hover {\n transform: translateY(-4px);\n box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-image {\n width: 250px;\n min-width: 250px;\n height: 180px;\n padding-bottom: 0;\n position: relative;\n background-color: #f0f0f0;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-image img {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-content {\n flex: 1;\n padding: 1.5rem;\n display: flex;\n flex-direction: column;\n}\n\n/* Make sure grid view items display correctly */\n.next-blog-ai-list:not(.list-view) .next-blog-ai-post-card {\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n/* Responsive adjustments for list view */\n@media (max-width: 768px) {\n .next-blog-ai-list.list-view .next-blog-ai-post-card {\n flex-direction: column;\n }\n \n .next-blog-ai-list.list-view .next-blog-ai-post-image {\n width: 100%;\n height: 0;\n padding-bottom: 56.25%; /* 16:9 aspect ratio */\n }\n}\n\n.next-blog-ai-post-card {\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.next-blog-ai-post-title {\n font-size: 1.25rem;\n font-weight: 600;\n margin-top: 0;\n margin-bottom: 0.5rem;\n color: #111;\n}\n\n.next-blog-ai-post-title a {\n color: inherit;\n text-decoration: none;\n}\n\n.next-blog-ai-post-title a:hover {\n color: #0070f3;\n}\n\n.next-blog-ai-post-meta {\n font-size: 0.875rem;\n color: #666;\n margin-bottom: 1rem;\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.next-blog-ai-post-excerpt {\n margin-bottom: 1.5rem;\n flex-grow: 1;\n}\n\n.next-blog-ai-post-footer {\n margin-top: auto;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.next-blog-ai-read-more {\n color: #0070f3;\n text-decoration: none;\n font-weight: 500;\n font-size: 0.875rem;\n}\n\n.next-blog-ai-read-more:hover {\n text-decoration: underline;\n}\n\n.next-blog-ai-comments-count {\n font-size: 0.875rem;\n color: #666;\n}\n\n/* Pagination */\n.next-blog-ai-pagination {\n display: flex;\n justify-content: center;\n margin: 3rem 0;\n gap: 0.5rem;\n}\n\n.next-blog-ai-pagination-item {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 2.5rem;\n height: 2.5rem;\n padding: 0 0.75rem;\n border-radius: 4px;\n background-color: #f0f0f0;\n color: #333;\n text-decoration: none;\n font-weight: 500;\n}\n\n.next-blog-ai-pagination-item:hover {\n background-color: #e0e0e0;\n}\n\n.next-blog-ai-pagination-item.active {\n background-color: #0070f3;\n color: white;\n}\n\n.next-blog-ai-pagination-item.disabled {\n color: #999;\n pointer-events: none;\n}\n"; /** * Deep transforms object keys from snake_case to camelCase */ declare function normalizeKeys<T>(obj: any): T; /** * Add HTML styles for content rendering */ declare function addHtmlStyles(html: string, styles: string): string; export { ApiResponse, BlogListHtmlResponse, BlogListJsonResponse, BlogListOptions, BlogListResponse, BlogListSEOOptions, BlogListSEOResponse, BlogPost, BlogPostHtmlResponse, BlogPostJsonResponse, BlogPostOptions, BlogPostResponse, BlogPostSummary, BlogSlugsOptions, BlogSlugsResponse, CacheOptions, Comment, CommentData, CommentResponse, ContentFormat, DEFAULT_BLOG_LIST_STYLES, DEFAULT_BLOG_STYLES, ErrorResponse, NextBlogAI, NextBlogAIConfig, NextBlogListOptions, NextBlogListSEOOptions, NextBlogPostOptions, NextBlogSlugsOptions, NextSEOOptions, Pagination, RetryOptions, SEOMetadata, SEOOptions, SEOResponse, addHtmlStyles, createNextBlogAI, createNextBlogAIForNextJs, getAllBlogSlugsWithNextCache, getBlogListSEOWithNextCache, getBlogPostSEOWithNextCache, getBlogPostWithNextCache, getBlogPostsWithNextCache, normalizeKeys, withNextCache };