@xexr/blog-platform 1.0.5 → 1.0.7

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.
@@ -2,7 +2,10 @@ import React from "react";
2
2
  import Image from "next/image";
3
3
  import Link from "next/link";
4
4
  import { MDXRemote } from "next-mdx-remote-client/rsc";
5
- import { type PublishedArticle } from "../../../types/contracts";
5
+ import {
6
+ type PublishedArticle,
7
+ type PublishedAuthor,
8
+ } from "../../../types/contracts";
6
9
  import { cn } from "../../../lib/utils";
7
10
  import { ArrowLeft, ArrowUpRight, Mail, Share2 } from "lucide-react";
8
11
  import { Badge } from "../../../components/ui/badge";
@@ -18,6 +21,7 @@ import { buildBlogPath, normalizeBlogBasePath } from "../../../lib/urls";
18
21
  import {
19
22
  type BlogTheme,
20
23
  extractTableOfContents,
24
+ formatTableOfContentsSummary,
21
25
  formatArticleDateMeta,
22
26
  getBlogThemeStyle,
23
27
  } from "../../../lib/article-ui";
@@ -145,6 +149,7 @@ export default function ArticlePage({
145
149
  {article.author && (
146
150
  <div className="flex items-center gap-2">
147
151
  <span className="sr-only">Author</span>
152
+ <AuthorAvatar author={article.author} size="md" />
148
153
  <span className="font-medium">{article.author.name}</span>
149
154
  {article.author.isGuest && (
150
155
  <Badge variant="outline" className="text-xs">
@@ -176,12 +181,35 @@ export default function ArticlePage({
176
181
 
177
182
  <div className="bg-border h-px w-6 sm:w-8" aria-hidden="true"></div>
178
183
 
179
- <span
180
- className="text-xs tracking-wider uppercase sm:text-sm"
181
- role="text"
182
- >
183
- From {article.site.name}
184
- </span>
184
+ {(article.topics ?? []).length > 0 ? (
185
+ <nav
186
+ aria-label="Article topics"
187
+ className="flex flex-wrap justify-center gap-2"
188
+ >
189
+ {(article.topics ?? []).map((topic) => (
190
+ <Link
191
+ key={topic.id}
192
+ href={buildBlogPath(
193
+ (navigation?.backToHome?.url ?? "/blog").replace(
194
+ /\/$/,
195
+ "",
196
+ ),
197
+ `topics/${topic.slug}`,
198
+ )}
199
+ className="rounded-full border border-[var(--blog-accent-border)] bg-[var(--blog-accent-bg)] px-3 py-1 text-xs font-medium text-[var(--blog-text-accent)] transition-colors hover:border-[var(--blog-text-accent)] hover:text-[var(--blog-text-accent-hover)]"
200
+ >
201
+ {topic.name}
202
+ </Link>
203
+ ))}
204
+ </nav>
205
+ ) : (
206
+ <span
207
+ className="text-xs tracking-wider uppercase sm:text-sm"
208
+ role="text"
209
+ >
210
+ From {article.site.name}
211
+ </span>
212
+ )}
185
213
  </div>
186
214
  </header>
187
215
 
@@ -227,11 +255,8 @@ export default function ArticlePage({
227
255
  <Separator className="mb-8" />
228
256
  <Card className="border-[var(--blog-accent-border)] bg-[var(--blog-accent-bg)]">
229
257
  <CardContent className="flex flex-col gap-4 p-5 sm:flex-row sm:items-start sm:p-6">
230
- <div
231
- className="flex size-12 shrink-0 items-center justify-center rounded-full bg-[var(--blog-accent)] text-lg font-semibold text-white"
232
- aria-hidden="true"
233
- >
234
- {article.author.name.slice(0, 1)}
258
+ <div className="shrink-0">
259
+ <AuthorAvatar author={article.author} size="lg" />
235
260
  </div>
236
261
  <div className="min-w-0 space-y-2">
237
262
  <div>
@@ -383,15 +408,26 @@ function ArticleTableOfContents({
383
408
 
384
409
  if (variant === "mobile") {
385
410
  return (
386
- <nav
387
- aria-label="Table of contents"
388
- className="mb-8 rounded-2xl border border-[var(--blog-accent-border)] bg-[var(--blog-accent-bg)] p-4 lg:hidden"
389
- >
390
- <p className="text-foreground mb-3 text-sm font-semibold">
391
- On this page
392
- </p>
393
- {list}
394
- </nav>
411
+ <details className="group mb-6 rounded-2xl border border-[var(--blog-accent-border)] bg-[var(--blog-accent-bg)] lg:hidden">
412
+ <summary className="text-foreground flex cursor-pointer list-none items-center justify-between gap-3 px-4 py-3 text-sm font-semibold [&::-webkit-details-marker]:hidden">
413
+ <span>On this page</span>
414
+ <span className="text-muted-foreground flex items-center gap-2 text-xs font-medium">
415
+ {formatTableOfContentsSummary(items.length)}
416
+ <span
417
+ className="text-[var(--blog-text-accent)] transition-transform group-open:rotate-180"
418
+ aria-hidden="true"
419
+ >
420
+ ↓
421
+ </span>
422
+ </span>
423
+ </summary>
424
+ <nav
425
+ aria-label="Table of contents"
426
+ className="border-t border-[var(--blog-accent-border)] px-4 py-4"
427
+ >
428
+ {list}
429
+ </nav>
430
+ </details>
395
431
  );
396
432
  }
397
433
 
@@ -410,6 +446,54 @@ function ArticleTableOfContents({
410
446
  );
411
447
  }
412
448
 
449
+ function AuthorAvatar({
450
+ author,
451
+ size,
452
+ }: {
453
+ author: PublishedAuthor;
454
+ size: "md" | "lg";
455
+ }) {
456
+ const sizeClass = size === "lg" ? "h-12 w-12 text-base" : "h-9 w-9 text-sm";
457
+ const initials = getAuthorInitials(author.name);
458
+
459
+ if (author.avatarUrl) {
460
+ return (
461
+ <Image
462
+ src={author.avatarUrl}
463
+ alt={author.name}
464
+ width={size === "lg" ? 48 : 36}
465
+ height={size === "lg" ? 48 : 36}
466
+ className={cn("shrink-0 rounded-full object-cover", sizeClass)}
467
+ loading="lazy"
468
+ />
469
+ );
470
+ }
471
+
472
+ return (
473
+ <span
474
+ className={cn(
475
+ "bg-muted text-muted-foreground inline-flex shrink-0 items-center justify-center rounded-full font-medium",
476
+ sizeClass,
477
+ )}
478
+ aria-hidden="true"
479
+ >
480
+ {initials}
481
+ </span>
482
+ );
483
+ }
484
+
485
+ function getAuthorInitials(name: string): string {
486
+ const initials = name
487
+ .trim()
488
+ .split(/\s+/)
489
+ .filter(Boolean)
490
+ .slice(0, 2)
491
+ .map((part) => part[0]?.toUpperCase())
492
+ .join("");
493
+
494
+ return initials || "?";
495
+ }
496
+
413
497
  function PostArticleCta({
414
498
  cta,
415
499
  }: {
@@ -3,6 +3,7 @@ import Link from "next/link";
3
3
  import Image from "next/image";
4
4
  import {
5
5
  type PublishedArticle,
6
+ type PublishedAuthor,
6
7
  type PublishedSite,
7
8
  } from "../../types/contracts";
8
9
  import { cn } from "../../lib/utils";
@@ -198,7 +199,10 @@ function ArticlePreview({
198
199
  <div className="text-muted-foreground flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">
199
200
  {article.author && (
200
201
  <>
201
- <span className="font-medium">{article.author.name}</span>
202
+ <span className="inline-flex items-center gap-2 font-medium">
203
+ <AuthorAvatar author={article.author} size="sm" />
204
+ {article.author.name}
205
+ </span>
202
206
  <span className="text-border">•</span>
203
207
  </>
204
208
  )}
@@ -218,6 +222,19 @@ function ArticlePreview({
218
222
  {article.excerpt}
219
223
  </p>
220
224
  )}
225
+
226
+ {(article.topics ?? []).length > 0 && (
227
+ <div className="flex flex-wrap gap-2">
228
+ {(article.topics ?? []).map((topic) => (
229
+ <span
230
+ key={topic.id}
231
+ className="rounded-full border border-[var(--blog-accent-border)] px-2.5 py-1 text-xs font-medium text-[var(--blog-text-accent)]"
232
+ >
233
+ {topic.name}
234
+ </span>
235
+ ))}
236
+ </div>
237
+ )}
221
238
  </div>
222
239
  </div>
223
240
 
@@ -249,12 +266,28 @@ function ArticlePreview({
249
266
  {article.excerpt}
250
267
  </p>
251
268
  )}
269
+
270
+ {(article.topics ?? []).length > 0 && (
271
+ <div className="flex flex-wrap gap-2">
272
+ {(article.topics ?? []).map((topic) => (
273
+ <span
274
+ key={topic.id}
275
+ className="rounded-full border border-[var(--blog-accent-border)] px-2.5 py-1 text-xs font-medium text-[var(--blog-text-accent)]"
276
+ >
277
+ {topic.name}
278
+ </span>
279
+ ))}
280
+ </div>
281
+ )}
252
282
  </div>
253
283
 
254
284
  <div className="text-muted-foreground flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">
255
285
  {article.author && (
256
286
  <>
257
- <span className="font-medium">{article.author.name}</span>
287
+ <span className="inline-flex items-center gap-2 font-medium">
288
+ <AuthorAvatar author={article.author} size="sm" />
289
+ {article.author.name}
290
+ </span>
258
291
  <span className="text-border">•</span>
259
292
  </>
260
293
  )}
@@ -275,6 +308,54 @@ function ArticlePreview({
275
308
  );
276
309
  }
277
310
 
311
+ function AuthorAvatar({
312
+ author,
313
+ size,
314
+ }: {
315
+ author: PublishedAuthor;
316
+ size: "sm" | "md";
317
+ }) {
318
+ const sizeClass = size === "md" ? "h-9 w-9 text-sm" : "h-6 w-6 text-xs";
319
+ const initials = getAuthorInitials(author.name);
320
+
321
+ if (author.avatarUrl) {
322
+ return (
323
+ <Image
324
+ src={author.avatarUrl}
325
+ alt={author.name}
326
+ width={size === "md" ? 36 : 24}
327
+ height={size === "md" ? 36 : 24}
328
+ className={cn("shrink-0 rounded-full object-cover", sizeClass)}
329
+ loading="lazy"
330
+ />
331
+ );
332
+ }
333
+
334
+ return (
335
+ <span
336
+ className={cn(
337
+ "bg-muted inline-flex shrink-0 items-center justify-center rounded-full font-medium",
338
+ sizeClass,
339
+ )}
340
+ aria-hidden="true"
341
+ >
342
+ {initials}
343
+ </span>
344
+ );
345
+ }
346
+
347
+ function getAuthorInitials(name: string): string {
348
+ const initials = name
349
+ .trim()
350
+ .split(/\s+/)
351
+ .filter(Boolean)
352
+ .slice(0, 2)
353
+ .map((part) => part[0]?.toUpperCase())
354
+ .join("");
355
+
356
+ return initials || "?";
357
+ }
358
+
278
359
  /**
279
360
  * Generate metadata for the blog home page for SEO optimization.
280
361
  * This function should be used in the Next.js metadata API.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { PublishedArticle, PublishedSite, PublishResult, PublishedAuthor } from './types/index.mjs';
1
+ import { PublishedArticle, PublishedSite, PublishedTopic, PublishResult, PublishedAuthor } from './types/index.mjs';
2
2
  export { PublishPayload } from './types/index.mjs';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import * as React from 'react';
@@ -264,6 +264,32 @@ declare function normalizeBlogBasePath(basePath?: string): string;
264
264
  declare function buildBlogPath(basePath: string | undefined, slug?: string): string;
265
265
  declare function getPathPrefixFromBlogUrl(blogUrl: string): string;
266
266
 
267
+ interface TopicArchive {
268
+ topic: PublishedTopic;
269
+ articles: PublishedArticle[];
270
+ }
271
+ declare function getArticlePrimaryTopic(article: PublishedArticle): PublishedTopic | null;
272
+ declare function getAllTopics(articles: PublishedArticle[]): PublishedTopic[];
273
+ declare function getTopicArchive(articles: PublishedArticle[], topicSlug: string): TopicArchive | null;
274
+
275
+ interface BlogTopicsIndexPageProps {
276
+ articles: PublishedArticle[];
277
+ basePath?: string;
278
+ title?: string;
279
+ description?: string;
280
+ className?: string;
281
+ theme?: BlogTheme;
282
+ }
283
+ interface BlogTopicArchivePageProps {
284
+ articles: PublishedArticle[];
285
+ topicSlug: string;
286
+ basePath?: string;
287
+ className?: string;
288
+ theme?: BlogTheme;
289
+ }
290
+ declare function BlogTopicsIndexPage({ articles, basePath, title, description, className, theme, }: BlogTopicsIndexPageProps): react_jsx_runtime.JSX.Element;
291
+ declare function BlogTopicArchivePage({ articles, topicSlug, basePath, className, theme, }: BlogTopicArchivePageProps): react_jsx_runtime.JSX.Element;
292
+
267
293
  /**
268
294
  * Authentication configuration interface
269
295
  * Customers can implement this to customize authentication behavior
@@ -1579,6 +1605,7 @@ interface PersonSchema extends BaseStructuredData {
1579
1605
  name: string;
1580
1606
  description?: string;
1581
1607
  identifier?: string;
1608
+ image?: string;
1582
1609
  url?: string;
1583
1610
  sameAs?: string[];
1584
1611
  jobTitle?: string;
@@ -1858,4 +1885,4 @@ declare function OPTIONS(request: NextRequest): Promise<NextResponse>;
1858
1885
 
1859
1886
  declare const PACKAGE_VERSION: string;
1860
1887
 
1861
- export { ApiKeyAuth, type AuthConfig, type AuthResult, ArticlePage as BlogArticlePage, BlogHomePage, type BlogPlatformConfig, type BlogPlatformStorage, type BlogPostingSchema, type BlogSitemapConfig, type BlogTheme, type BreadcrumbListSchema, Button, type CanonicalUrlOptions, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, DrizzleStorage, EnvAuth, type GeneratedMetadata, InMemoryStorage, type LinkTag, type MetaTag, type MetadataOptions, type NextjsSitemapEntry, NoAuth, type OrganizationSchema, PACKAGE_VERSION, Pagination$1 as Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, type PersonSchema, PublishResult, PublishedArticle, PublishedAuthor, PublishedSite, type RateLimitConfig, type RateLimitResult, Pagination as ShadcnPagination, type SitemapChangeFreq, type SitemapData, type SitemapEntry, type SitemapOptions, StructuredDataError, type StructuredDataOptions, UninitializedAuth, type WebSiteSchema, autoConfigureRateLimit, bpArticles, bpOperations, buildBlogPath, buttonVariants, checkRateLimit, cn, configureRateLimit, createBlogSitemapRoute, createDynamicBlogSitemap, createRateLimitErrorResponse, createStructuredDataScript, enforceRateLimit, extractKeywordsFromArticle, extractTableOfContents, extractTokenFromHeader, formatArticleDateMeta, generateArticleMetadata, generateArticleStructuredData, generateAuthorStructuredData, generateBlogHomeMetadata, generateBlogHomeStructuredData, generateBlogSitemapEntries, generateBreadcrumbStructuredData, generateCanonicalUrl, generateCanonicalUrlFromSlug, generateCompleteArticleStructuredData, generateOrganizationStructuredData, generatePaginationMetadata, generateSiteMetadata, generateSitemap, generateSitemapIndex, generateWebSiteStructuredData, getAuthConfig, getBaseUrl, getBlogThemeStyle, getDrizzleAdapterSql, getPathPrefixFromBlogUrl, getRateLimitHeaders, getStorage, initBlogPlatform, initBlogPlatformDev, initBlogPlatformOnce, initBlogPlatformProd, initEnvAuth, isValidCanonicalUrl, metadataToHtml, normalizeBlogBasePath, normalizeDomain, normalizeSlug, POST$1 as publishHandler, safeGenerateArticleStructuredData, setAuthConfig, setStorage, shouldSkipAuth, sitemapToXml, GET as slugExistsHandler, OPTIONS as slugExistsOptionsHandler, structuredDataToJsonLd, POST as unpublishHandler, updateArticleCanonicalUrl, usePagination, validateMetadata, validateSitemap, validateStructuredData, GET$1 as versionHandler };
1888
+ export { ApiKeyAuth, type AuthConfig, type AuthResult, ArticlePage as BlogArticlePage, BlogHomePage, type BlogPlatformConfig, type BlogPlatformStorage, type BlogPostingSchema, type BlogSitemapConfig, type BlogTheme, BlogTopicArchivePage, BlogTopicsIndexPage, type BreadcrumbListSchema, Button, type CanonicalUrlOptions, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, DrizzleStorage, EnvAuth, type GeneratedMetadata, InMemoryStorage, type LinkTag, type MetaTag, type MetadataOptions, type NextjsSitemapEntry, NoAuth, type OrganizationSchema, PACKAGE_VERSION, Pagination$1 as Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, type PersonSchema, PublishResult, PublishedArticle, PublishedAuthor, PublishedSite, PublishedTopic, type RateLimitConfig, type RateLimitResult, Pagination as ShadcnPagination, type SitemapChangeFreq, type SitemapData, type SitemapEntry, type SitemapOptions, StructuredDataError, type StructuredDataOptions, type TopicArchive, UninitializedAuth, type WebSiteSchema, autoConfigureRateLimit, bpArticles, bpOperations, buildBlogPath, buttonVariants, checkRateLimit, cn, configureRateLimit, createBlogSitemapRoute, createDynamicBlogSitemap, createRateLimitErrorResponse, createStructuredDataScript, enforceRateLimit, extractKeywordsFromArticle, extractTableOfContents, extractTokenFromHeader, formatArticleDateMeta, generateArticleMetadata, generateArticleStructuredData, generateAuthorStructuredData, generateBlogHomeMetadata, generateBlogHomeStructuredData, generateBlogSitemapEntries, generateBreadcrumbStructuredData, generateCanonicalUrl, generateCanonicalUrlFromSlug, generateCompleteArticleStructuredData, generateOrganizationStructuredData, generatePaginationMetadata, generateSiteMetadata, generateSitemap, generateSitemapIndex, generateWebSiteStructuredData, getAllTopics, getArticlePrimaryTopic, getAuthConfig, getBaseUrl, getBlogThemeStyle, getDrizzleAdapterSql, getPathPrefixFromBlogUrl, getRateLimitHeaders, getStorage, getTopicArchive, initBlogPlatform, initBlogPlatformDev, initBlogPlatformOnce, initBlogPlatformProd, initEnvAuth, isValidCanonicalUrl, metadataToHtml, normalizeBlogBasePath, normalizeDomain, normalizeSlug, POST$1 as publishHandler, safeGenerateArticleStructuredData, setAuthConfig, setStorage, shouldSkipAuth, sitemapToXml, GET as slugExistsHandler, OPTIONS as slugExistsOptionsHandler, structuredDataToJsonLd, POST as unpublishHandler, updateArticleCanonicalUrl, usePagination, validateMetadata, validateSitemap, validateStructuredData, GET$1 as versionHandler };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PublishedArticle, PublishedSite, PublishResult, PublishedAuthor } from './types/index.js';
1
+ import { PublishedArticle, PublishedSite, PublishedTopic, PublishResult, PublishedAuthor } from './types/index.js';
2
2
  export { PublishPayload } from './types/index.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import * as React from 'react';
@@ -264,6 +264,32 @@ declare function normalizeBlogBasePath(basePath?: string): string;
264
264
  declare function buildBlogPath(basePath: string | undefined, slug?: string): string;
265
265
  declare function getPathPrefixFromBlogUrl(blogUrl: string): string;
266
266
 
267
+ interface TopicArchive {
268
+ topic: PublishedTopic;
269
+ articles: PublishedArticle[];
270
+ }
271
+ declare function getArticlePrimaryTopic(article: PublishedArticle): PublishedTopic | null;
272
+ declare function getAllTopics(articles: PublishedArticle[]): PublishedTopic[];
273
+ declare function getTopicArchive(articles: PublishedArticle[], topicSlug: string): TopicArchive | null;
274
+
275
+ interface BlogTopicsIndexPageProps {
276
+ articles: PublishedArticle[];
277
+ basePath?: string;
278
+ title?: string;
279
+ description?: string;
280
+ className?: string;
281
+ theme?: BlogTheme;
282
+ }
283
+ interface BlogTopicArchivePageProps {
284
+ articles: PublishedArticle[];
285
+ topicSlug: string;
286
+ basePath?: string;
287
+ className?: string;
288
+ theme?: BlogTheme;
289
+ }
290
+ declare function BlogTopicsIndexPage({ articles, basePath, title, description, className, theme, }: BlogTopicsIndexPageProps): react_jsx_runtime.JSX.Element;
291
+ declare function BlogTopicArchivePage({ articles, topicSlug, basePath, className, theme, }: BlogTopicArchivePageProps): react_jsx_runtime.JSX.Element;
292
+
267
293
  /**
268
294
  * Authentication configuration interface
269
295
  * Customers can implement this to customize authentication behavior
@@ -1579,6 +1605,7 @@ interface PersonSchema extends BaseStructuredData {
1579
1605
  name: string;
1580
1606
  description?: string;
1581
1607
  identifier?: string;
1608
+ image?: string;
1582
1609
  url?: string;
1583
1610
  sameAs?: string[];
1584
1611
  jobTitle?: string;
@@ -1858,4 +1885,4 @@ declare function OPTIONS(request: NextRequest): Promise<NextResponse>;
1858
1885
 
1859
1886
  declare const PACKAGE_VERSION: string;
1860
1887
 
1861
- export { ApiKeyAuth, type AuthConfig, type AuthResult, ArticlePage as BlogArticlePage, BlogHomePage, type BlogPlatformConfig, type BlogPlatformStorage, type BlogPostingSchema, type BlogSitemapConfig, type BlogTheme, type BreadcrumbListSchema, Button, type CanonicalUrlOptions, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, DrizzleStorage, EnvAuth, type GeneratedMetadata, InMemoryStorage, type LinkTag, type MetaTag, type MetadataOptions, type NextjsSitemapEntry, NoAuth, type OrganizationSchema, PACKAGE_VERSION, Pagination$1 as Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, type PersonSchema, PublishResult, PublishedArticle, PublishedAuthor, PublishedSite, type RateLimitConfig, type RateLimitResult, Pagination as ShadcnPagination, type SitemapChangeFreq, type SitemapData, type SitemapEntry, type SitemapOptions, StructuredDataError, type StructuredDataOptions, UninitializedAuth, type WebSiteSchema, autoConfigureRateLimit, bpArticles, bpOperations, buildBlogPath, buttonVariants, checkRateLimit, cn, configureRateLimit, createBlogSitemapRoute, createDynamicBlogSitemap, createRateLimitErrorResponse, createStructuredDataScript, enforceRateLimit, extractKeywordsFromArticle, extractTableOfContents, extractTokenFromHeader, formatArticleDateMeta, generateArticleMetadata, generateArticleStructuredData, generateAuthorStructuredData, generateBlogHomeMetadata, generateBlogHomeStructuredData, generateBlogSitemapEntries, generateBreadcrumbStructuredData, generateCanonicalUrl, generateCanonicalUrlFromSlug, generateCompleteArticleStructuredData, generateOrganizationStructuredData, generatePaginationMetadata, generateSiteMetadata, generateSitemap, generateSitemapIndex, generateWebSiteStructuredData, getAuthConfig, getBaseUrl, getBlogThemeStyle, getDrizzleAdapterSql, getPathPrefixFromBlogUrl, getRateLimitHeaders, getStorage, initBlogPlatform, initBlogPlatformDev, initBlogPlatformOnce, initBlogPlatformProd, initEnvAuth, isValidCanonicalUrl, metadataToHtml, normalizeBlogBasePath, normalizeDomain, normalizeSlug, POST$1 as publishHandler, safeGenerateArticleStructuredData, setAuthConfig, setStorage, shouldSkipAuth, sitemapToXml, GET as slugExistsHandler, OPTIONS as slugExistsOptionsHandler, structuredDataToJsonLd, POST as unpublishHandler, updateArticleCanonicalUrl, usePagination, validateMetadata, validateSitemap, validateStructuredData, GET$1 as versionHandler };
1888
+ export { ApiKeyAuth, type AuthConfig, type AuthResult, ArticlePage as BlogArticlePage, BlogHomePage, type BlogPlatformConfig, type BlogPlatformStorage, type BlogPostingSchema, type BlogSitemapConfig, type BlogTheme, BlogTopicArchivePage, BlogTopicsIndexPage, type BreadcrumbListSchema, Button, type CanonicalUrlOptions, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, DrizzleStorage, EnvAuth, type GeneratedMetadata, InMemoryStorage, type LinkTag, type MetaTag, type MetadataOptions, type NextjsSitemapEntry, NoAuth, type OrganizationSchema, PACKAGE_VERSION, Pagination$1 as Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, type PersonSchema, PublishResult, PublishedArticle, PublishedAuthor, PublishedSite, PublishedTopic, type RateLimitConfig, type RateLimitResult, Pagination as ShadcnPagination, type SitemapChangeFreq, type SitemapData, type SitemapEntry, type SitemapOptions, StructuredDataError, type StructuredDataOptions, type TopicArchive, UninitializedAuth, type WebSiteSchema, autoConfigureRateLimit, bpArticles, bpOperations, buildBlogPath, buttonVariants, checkRateLimit, cn, configureRateLimit, createBlogSitemapRoute, createDynamicBlogSitemap, createRateLimitErrorResponse, createStructuredDataScript, enforceRateLimit, extractKeywordsFromArticle, extractTableOfContents, extractTokenFromHeader, formatArticleDateMeta, generateArticleMetadata, generateArticleStructuredData, generateAuthorStructuredData, generateBlogHomeMetadata, generateBlogHomeStructuredData, generateBlogSitemapEntries, generateBreadcrumbStructuredData, generateCanonicalUrl, generateCanonicalUrlFromSlug, generateCompleteArticleStructuredData, generateOrganizationStructuredData, generatePaginationMetadata, generateSiteMetadata, generateSitemap, generateSitemapIndex, generateWebSiteStructuredData, getAllTopics, getArticlePrimaryTopic, getAuthConfig, getBaseUrl, getBlogThemeStyle, getDrizzleAdapterSql, getPathPrefixFromBlogUrl, getRateLimitHeaders, getStorage, getTopicArchive, initBlogPlatform, initBlogPlatformDev, initBlogPlatformOnce, initBlogPlatformProd, initEnvAuth, isValidCanonicalUrl, metadataToHtml, normalizeBlogBasePath, normalizeDomain, normalizeSlug, POST$1 as publishHandler, safeGenerateArticleStructuredData, setAuthConfig, setStorage, shouldSkipAuth, sitemapToXml, GET as slugExistsHandler, OPTIONS as slugExistsOptionsHandler, structuredDataToJsonLd, POST as unpublishHandler, updateArticleCanonicalUrl, usePagination, validateMetadata, validateSitemap, validateStructuredData, GET$1 as versionHandler };