@fullstackdatasolutions/articles 1.2.3 → 1.3.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +313 -1
  3. package/dist/index.cjs +308 -79
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +267 -16
  6. package/dist/index.d.ts +267 -16
  7. package/dist/index.js +300 -79
  8. package/dist/index.js.map +1 -1
  9. package/dist/nextjs.cjs +325 -31
  10. package/dist/nextjs.cjs.map +1 -1
  11. package/dist/nextjs.d.cts +179 -2
  12. package/dist/nextjs.d.ts +179 -2
  13. package/dist/nextjs.js +325 -31
  14. package/dist/nextjs.js.map +1 -1
  15. package/dist/server.cjs +660 -50
  16. package/dist/server.cjs.map +1 -1
  17. package/dist/server.d.cts +333 -12
  18. package/dist/server.d.ts +333 -12
  19. package/dist/server.js +645 -50
  20. package/dist/server.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/ArticleAnswer.tsx +35 -0
  23. package/src/ArticleSchemas.tsx +263 -23
  24. package/src/AuthorArticlesPage.tsx +38 -8
  25. package/src/__tests__/ArticleAnswer.test.tsx +25 -0
  26. package/src/__tests__/ArticleSchemas.test.tsx +516 -0
  27. package/src/__tests__/AuthorArticlesPage.test.tsx +76 -0
  28. package/src/__tests__/authorUtils.test.ts +50 -0
  29. package/src/__tests__/markdown.test.ts +77 -1
  30. package/src/__tests__/nextjs.test.ts +31 -15
  31. package/src/__tests__/seoUtils.test.ts +279 -0
  32. package/src/__tests__/server-articles.test.ts +434 -1
  33. package/src/__tests__/validateArticles.test.ts +167 -6
  34. package/src/articleTypes.ts +57 -0
  35. package/src/articlesConfig.ts +176 -1
  36. package/src/authorUtils.ts +19 -1
  37. package/src/errorReporting.ts +1 -0
  38. package/src/index.ts +17 -1
  39. package/src/markdown.ts +100 -1
  40. package/src/nextjs.ts +7 -4
  41. package/src/seoUtils.ts +247 -26
  42. package/src/server-articles.ts +385 -25
  43. package/src/server.ts +35 -4
  44. package/src/validateArticles.ts +157 -12
package/dist/index.d.cts CHANGED
@@ -14,6 +14,21 @@ interface HowToStep {
14
14
  name: string;
15
15
  text: string;
16
16
  }
17
+ /**
18
+ * A real-world thing an article is about, emitted as schema.org `about`.
19
+ * `sameAs` should point at an authoritative identifier for the entity
20
+ * (Wikipedia, Wikidata, an official site) - that URL is what lets a consumer
21
+ * resolve "Pathfinder" the game system rather than guessing from the string.
22
+ */
23
+ interface EntityReference {
24
+ name: string;
25
+ sameAs?: string;
26
+ }
27
+ /** An outbound source an article cites, emitted as schema.org `citation`. */
28
+ interface CitationReference {
29
+ name: string;
30
+ url?: string;
31
+ }
17
32
  interface Article {
18
33
  slug: string;
19
34
  title: string;
@@ -38,6 +53,18 @@ interface Article {
38
53
  toc?: TocItem[];
39
54
  faq?: FaqItem[];
40
55
  howTo?: HowToStep[];
56
+ /**
57
+ * A direct, self-contained answer to the article's core question, 40-60
58
+ * words. Rendered by `ArticleAnswer`, emitted as the Article schema's
59
+ * `abstract`, used as the `acceptedAnswer` when `articleType` is
60
+ * `'QAPage'`, and placed at the top of the article's markdown twin - the
61
+ * one passage most likely to be lifted verbatim by an answer engine.
62
+ */
63
+ answer?: string;
64
+ /** Entities this article is about. Emitted as schema.org `about`. */
65
+ about?: EntityReference[];
66
+ /** Outbound sources. Emitted as schema.org `citation`. */
67
+ citation?: CitationReference[];
41
68
  canonicalUrl?: string;
42
69
  articleType?: string;
43
70
  series?: string;
@@ -152,6 +179,13 @@ interface AuthorProfile {
152
179
  promise?: string;
153
180
  /** Structured long-form origin story - see `RichText`/`RichTextSection`. */
154
181
  originStory?: RichText;
182
+ /**
183
+ * Topics this author writes about, emitted as Person `knowsAbout`. Omit to
184
+ * derive it from the categories of their own published articles - unlike
185
+ * `credentials`/`proof`, subject matter is verifiable from the corpus
186
+ * itself, so it does belong in structured data.
187
+ */
188
+ knowsAbout?: string[];
155
189
  /** Who this author's content/work is for, e.g. "New game masters", "Streaming DMs". */
156
190
  servesWho?: string[];
157
191
  /** Core beliefs/approach statements. */
@@ -164,6 +198,27 @@ interface AuthorProfile {
164
198
  credentials?: string[];
165
199
  /** Concrete, sourceable proof points. */
166
200
  proof?: ProofItem[];
201
+ /**
202
+ * The one canonical URL identifying this person across every site they
203
+ * publish on. Used *only* to derive the Person `@id`, so the same author
204
+ * resolves to a single entity everywhere instead of one entity per site.
205
+ *
206
+ * Deliberately separate from `url`: that field also drives byline link
207
+ * targets, the author page's Open Graph URL, and its `CollectionPage` URL,
208
+ * so pointing it at another domain would send readers off-site and hand
209
+ * this site's author page a canonical belonging to a different one.
210
+ * `identityUrl` changes nothing a reader sees.
211
+ *
212
+ * Set the same value on every site. Falls back to `url`, then to this
213
+ * site's own author page.
214
+ */
215
+ identityUrl?: string;
216
+ /**
217
+ * Additional profile URLs identifying this same person elsewhere, merged
218
+ * into the Person schema's `sameAs` alongside the derived social links.
219
+ * List the author's pages on the other sites here.
220
+ */
221
+ sameAs?: string[];
167
222
  /** Primary call-to-action rendered on the author's page. */
168
223
  primaryCta?: {
169
224
  label: string;
@@ -338,6 +393,54 @@ interface BreadcrumbsConfig {
338
393
  /** Optional label overrides for built-in breadcrumb items. */
339
394
  labels?: BreadcrumbLabels;
340
395
  }
396
+ /** Payload passed to `ArticlesConfig.onAiCrawl`. */
397
+ interface AiCrawlEvent {
398
+ /** Article slug whose markdown twin was fetched. */
399
+ slug: string;
400
+ /** Matched crawler name (e.g. `'GPTBot'`), or `'unknown'` when the agent is not recognized. */
401
+ crawler: string;
402
+ /** Raw `User-Agent` header, or an empty string when absent. */
403
+ userAgent: string;
404
+ }
405
+ /**
406
+ * The publishing entity behind the site. Drives `OrganizationSchema`,
407
+ * `WebSiteSchema`, and the `publisher` reference on every article - so all
408
+ * three point at one `@id` instead of repeating an inline, unlinked
409
+ * `Organization` stub per page.
410
+ */
411
+ interface OrganizationConfig {
412
+ /** schema.org type. Use `'Person'` for a personal brand. Default: `'Organization'`. */
413
+ type?: 'Organization' | 'Person';
414
+ /** Entity name. Falls back to `siteName`. */
415
+ name?: string;
416
+ /** Entity homepage. Falls back to `siteUrl`. */
417
+ url?: string;
418
+ /** Logo URL. Site-relative paths are resolved against `siteUrl`. */
419
+ logo?: string;
420
+ /** Entity description. Falls back to `ArticlesConfig.description`. */
421
+ description?: string;
422
+ /** Profile URLs that identify the same entity elsewhere (social, Crunchbase, Wikidata). */
423
+ sameAs?: string[];
424
+ /**
425
+ * The umbrella entity this site belongs to, for a network of sites run by
426
+ * one publisher. Emitted as `parentOrganization` - the link that lets
427
+ * authority earned by the network attach to each site in it, instead of
428
+ * each site standing alone.
429
+ */
430
+ parentOrganization?: {
431
+ name: string;
432
+ url: string;
433
+ };
434
+ /**
435
+ * Search URL template for the `WebSite` `SearchAction`, e.g.
436
+ * `'/search?q={search_term_string}'`. Omitted by default - the library's
437
+ * own search is client-side with no crawlable results URL, so declaring one
438
+ * that does not exist would be a false claim. Only set this if the app
439
+ * actually serves search results at that URL. Must contain the literal
440
+ * `{search_term_string}` placeholder.
441
+ */
442
+ searchUrlTemplate?: string;
443
+ }
341
444
  /** Top-level configuration object. Pass one instance to every library component. */
342
445
  interface ArticlesConfig {
343
446
  /** Canonical base URL of the site, used in metadata and JSON-LD. Example: `'https://yoursite.com'` */
@@ -400,6 +503,94 @@ interface ArticlesConfig {
400
503
  * step rather than a build-time failure otherwise.
401
504
  */
402
505
  paths?: Record<string, PathDefinition>;
506
+ /**
507
+ * Template for the `<title>` tag on article, category, series, and author
508
+ * pages. Supports `{title}` and `{siteName}` placeholders.
509
+ * Default: `'{title} | {siteName}'`.
510
+ *
511
+ * Google truncates a result title around 60 characters, and a site name
512
+ * suffix spends that budget on every page. Set `'{title}'` to drop it when
513
+ * your titles are already long and your brand draws little search volume -
514
+ * the suffix is only earning its characters if people search for the brand.
515
+ */
516
+ titleTemplate?: string;
517
+ /**
518
+ * BCP 47 language tag for the site's content. Emitted as the Article
519
+ * schema's `inLanguage` and the RSS channel `<language>`. Default: `'en'`.
520
+ */
521
+ language?: string;
522
+ /**
523
+ * Set to `false` when articles sit behind a paywall or registration wall.
524
+ * Default: `true`, emitted as the Article schema's `isAccessibleForFree` -
525
+ * an explicit "this is readable" signal, since consumers that cannot tell
526
+ * tend to skip suspected-paywalled sources.
527
+ */
528
+ isAccessibleForFree?: boolean;
529
+ /**
530
+ * CSS selectors marking the parts of an article suitable for text-to-speech,
531
+ * emitted as the Article schema's `speakable`. Omitted by default - the
532
+ * correct selectors depend on the consuming app's own markup, and guessing
533
+ * them would point at elements that may not exist.
534
+ */
535
+ speakableSelectors?: string[];
536
+ /**
537
+ * Set to `true` to derive `FAQPage` entries from question-shaped `##`
538
+ * headings and the paragraph that follows each one. Default: `false` -
539
+ * turning prose into structured data without the author's intent can
540
+ * promote a rhetorical heading into a published Q&A pair, so this is
541
+ * opt-in. Explicit `faq` frontmatter always wins over derived entries.
542
+ */
543
+ deriveFaqFromHeadings?: boolean;
544
+ /**
545
+ * Shared entity vocabulary, keyed by an app-chosen slug. Article `about`
546
+ * entries may reference a key here instead of repeating a name/`sameAs`
547
+ * pair - the point of `about` is that a consumer can resolve one entity
548
+ * across a corpus, which free-text names spelled three different ways
549
+ * defeat. `validateArticles` warns on `about` keys with no registry entry.
550
+ */
551
+ entities?: Record<string, EntityReference>;
552
+ /**
553
+ * Where `lastmod` comes from when frontmatter omits it.
554
+ * - `'published'` (default): reuse the publish date, as before 1.3.0.
555
+ * - `'none'`: leave `lastmod` unset, so `dateModified` is omitted rather
556
+ * than repeating a stale publish date.
557
+ * - `'fileMtime'`: read the article file's modification time. Accurate
558
+ * locally; on a CI runner that clones fresh, every file's mtime is the
559
+ * checkout time, which would report the whole corpus as updated today.
560
+ * Only use it where the build preserves mtimes.
561
+ */
562
+ lastmodFallback?: 'published' | 'none' | 'fileMtime';
563
+ /**
564
+ * Called when an AI crawler fetches an article's markdown twin. The one
565
+ * choke point where those requests land, so it is the only place a site
566
+ * can measure whether any of its AI-readable content is being read, and
567
+ * by which bot. No PII: the payload carries the slug, the matched crawler
568
+ * name, and the raw user agent string only.
569
+ */
570
+ onAiCrawl?: (event: AiCrawlEvent) => void;
571
+ /**
572
+ * The publishing entity behind the site. Omit to keep the pre-1.3.0 inline
573
+ * `{'@type':'Organization', name: siteName}` publisher stub on articles.
574
+ * Set it to emit `OrganizationSchema`/`WebSiteSchema` in the root layout and
575
+ * have every article, author, and collection page reference the same `@id`.
576
+ */
577
+ organization?: OrganizationConfig;
578
+ /**
579
+ * Default `aiCrawl` value for articles whose frontmatter omits the key.
580
+ * Default: `false` (every article stays opted out unless it sets
581
+ * `aiCrawl: true`). Set to `true` on a site whose goal is being cited by
582
+ * answer engines to opt the whole corpus in at once; per-article
583
+ * `aiCrawl: false` still wins and keeps that article blocked.
584
+ */
585
+ aiCrawlDefault?: boolean;
586
+ /**
587
+ * Set to `false` to serve article markdown twins as the bare body, with no
588
+ * attribution header. Default: `true` - the twin is prefixed with the
589
+ * title, excerpt, canonical source URL, dates, author, and site name so a
590
+ * model reading `/articles/[slug].md` can attribute it. Only applies when
591
+ * a config is available (i.e. via `getArticleMarkdownResponse`).
592
+ */
593
+ markdownTwinHeader?: boolean;
403
594
  /**
404
595
  * Vendor-neutral event callback (Phase 27F). Fired by components/hooks at
405
596
  * meaningful reader-journey moments (see `ArticleEvent` in `events.ts`).
@@ -413,6 +604,19 @@ declare const DEFAULT_CATEGORIES_PAGE_SIZE = 8;
413
604
  declare const DEFAULT_LAYOUT: ArticlesSection[];
414
605
  declare function breadcrumbsAreEnabled(config: ArticlesConfig): boolean;
415
606
  declare function getBreadcrumbsConfig(config: ArticlesConfig): BreadcrumbsConfig;
607
+ /** Stable `@id` for the site's publishing entity. */
608
+ declare function getOrganizationId(config: Pick<ArticlesConfig, 'siteUrl'>): string;
609
+ /** Stable `@id` for the site itself. */
610
+ declare function getWebSiteId(config: Pick<ArticlesConfig, 'siteUrl'>): string;
611
+ /** Stable `@id` for an author, so every article by them resolves to one Person. */
612
+ declare function getPersonId(authorUrl: string): string;
613
+ declare const DEFAULT_TITLE_TEMPLATE = "{title} | {siteName}";
614
+ /**
615
+ * Applies `ArticlesConfig.titleTemplate` to a page title. Kept here rather
616
+ * than inlined at each call site so article, category, series, and author
617
+ * pages can never drift apart on how the site name is appended.
618
+ */
619
+ declare function formatPageTitle(title: string, config: Pick<ArticlesConfig, 'siteName' | 'titleTemplate'>): string;
416
620
 
417
621
  declare function ArticlesPage({ config, initialArticles, initialCategories, page, totalPages, totalCount, }: Readonly<{
418
622
  config: ArticlesConfig;
@@ -612,6 +816,20 @@ declare function BreadcrumbSchema({ items }: Readonly<{
612
816
  items: BreadcrumbItem[];
613
817
  }>): react_jsx_runtime.JSX.Element;
614
818
 
819
+ interface ArticleComment {
820
+ id: string;
821
+ articleSlug: string;
822
+ body: string;
823
+ isDeleted: boolean;
824
+ createdAt: string;
825
+ authorId: string;
826
+ authorName: string;
827
+ parentId: string | null;
828
+ }
829
+ interface ArticleCommentWithReplies extends ArticleComment {
830
+ replies: ArticleComment[];
831
+ }
832
+
615
833
  type ArticleSEOProps = Readonly<{
616
834
  article: Article;
617
835
  articleUrl: string;
@@ -620,8 +838,15 @@ type ArticleSEOProps = Readonly<{
620
838
  showAuthor?: boolean;
621
839
  authors?: AuthorProfile[];
622
840
  config?: ArticlesConfig;
841
+ /**
842
+ * Top-level comments to emit as `commentCount`/`comment`. Real discussion
843
+ * is a quality signal that is otherwise invisible in structured data.
844
+ * Deleted comments are excluded, and only the author name, body, and
845
+ * timestamp are emitted - never the commenter's id.
846
+ */
847
+ comments?: readonly ArticleComment[];
623
848
  }>;
624
- declare function ArticleSEO({ article, articleUrl, siteName, siteLogo, showAuthor, authors, config, }: ArticleSEOProps): react_jsx_runtime.JSX.Element;
849
+ declare function ArticleSEO({ article, articleUrl, siteName, siteLogo, showAuthor, authors, config, comments, }: ArticleSEOProps): react_jsx_runtime.JSX.Element;
625
850
  type FAQPageSchemaProps = Readonly<{
626
851
  items: ReadonlyArray<{
627
852
  question: string;
@@ -642,6 +867,30 @@ type CollectionPageSchemaProps = Readonly<{
642
867
  items?: CollectionPageItem[];
643
868
  }>;
644
869
  declare function CollectionPageSchema({ title, description, url, articleCount, items, }: CollectionPageSchemaProps): react_jsx_runtime.JSX.Element;
870
+ type OrganizationSchemaProps = Readonly<{
871
+ config: ArticlesConfig;
872
+ }>;
873
+ /**
874
+ * Site-level publisher entity, rendered once in the root layout.
875
+ *
876
+ * Articles reference this by `@id` rather than repeating an inline
877
+ * `Organization` stub, so every page on the site resolves to one entity - the
878
+ * thing that lets a search or answer engine attribute a whole corpus to a
879
+ * single publisher instead of treating each page as an orphan.
880
+ * Returns `null` when `config.organization` is unset.
881
+ */
882
+ declare function OrganizationSchema({ config }: OrganizationSchemaProps): react_jsx_runtime.JSX.Element | null;
883
+ type WebSiteSchemaProps = Readonly<{
884
+ config: ArticlesConfig;
885
+ }>;
886
+ /**
887
+ * Site entity, rendered once in the root layout alongside `OrganizationSchema`.
888
+ * Emits a `SearchAction` only when `organization.searchUrlTemplate` is set -
889
+ * the library's own search is client-side with no crawlable results URL, so
890
+ * declaring one unconditionally would advertise an endpoint that does not exist.
891
+ * Returns `null` when `config.organization` is unset.
892
+ */
893
+ declare function WebSiteSchema({ config }: WebSiteSchemaProps): react_jsx_runtime.JSX.Element | null;
645
894
 
646
895
  interface ArticleSocialShareProps {
647
896
  readonly title: string;
@@ -707,6 +956,22 @@ type ArticleTOCProps = Readonly<{
707
956
  }>;
708
957
  declare function ArticleTOC({ toc, className }: ArticleTOCProps): react_jsx_runtime.JSX.Element | null;
709
958
 
959
+ type ArticleAnswerProps = Readonly<{
960
+ article: Pick<Article, 'answer'>;
961
+ /** Heading shown above the answer. Default: `'The short answer'`. */
962
+ label?: string;
963
+ className?: string;
964
+ }>;
965
+ /**
966
+ * Renders `article.answer` as a callout above the article body.
967
+ *
968
+ * The same text is emitted as the Article schema's `abstract` and placed at
969
+ * the top of the article's markdown twin, so the passage an answer engine is
970
+ * most likely to lift is also the one a reader sees first. Returns `null`
971
+ * when the article has no `answer`, so it is safe to render unconditionally.
972
+ */
973
+ declare function ArticleAnswer({ article, label, className, }: ArticleAnswerProps): react_jsx_runtime.JSX.Element | null;
974
+
710
975
  declare function ScrollToTop(): react_jsx_runtime.JSX.Element | null;
711
976
 
712
977
  interface PaginationNavProps {
@@ -766,20 +1031,6 @@ interface CommentsSectionProps {
766
1031
  }
767
1032
  declare function CommentsSection({ articleSlug, config }: CommentsSectionProps): react_jsx_runtime.JSX.Element | null;
768
1033
 
769
- interface ArticleComment {
770
- id: string;
771
- articleSlug: string;
772
- body: string;
773
- isDeleted: boolean;
774
- createdAt: string;
775
- authorId: string;
776
- authorName: string;
777
- parentId: string | null;
778
- }
779
- interface ArticleCommentWithReplies extends ArticleComment {
780
- replies: ArticleComment[];
781
- }
782
-
783
1034
  interface CommentThreadProps {
784
1035
  readonly comments: ArticleCommentWithReplies[];
785
1036
  readonly articleSlug: string;
@@ -815,4 +1066,4 @@ interface UseArticlesReturn {
815
1066
  }
816
1067
  declare function useArticles(initialArticles?: Article[], initialCategories?: CategoryInfo[]): UseArticlesReturn;
817
1068
 
818
- export { type Article, ArticleBackLink, type ArticleBreadcrumbEntry, type ArticleBreadcrumbToken, ArticleCard, ArticleCategoryGrid, type ArticleComment, type ArticleCommentWithReplies, ArticleDetailHero, type ArticleEvent, type ArticleEventHandler, type ArticleEventName, ArticleNavigation, ArticleSEO, ArticleSearchBar, ArticleSocialShare, ArticleTOC, ArticleViewTracker, type ArticleViewedEvent, type ArticlesConfig, ArticlesHero, ArticlesPage, type ArticlesSection, type ArticlesTheme, AuthorArticlesPage, type AuthorBreadcrumbEntry, type AuthorBreadcrumbToken, AuthorCard, type AuthorClickedEvent, AuthorDetailHero, type AuthorPageSection, type AuthorProfile, type AuthorSocial, AuthorSocialLinks, Breadcrumb, type BreadcrumbItem, type BreadcrumbLabels, BreadcrumbSchema, type BreadcrumbsConfig, CategoryArticlesPage, type CategoryBreadcrumbEntry, type CategoryBreadcrumbToken, type CategoryDescription, type CategoryInfo, type CollectionPageItem, CollectionPageSchema, CommentForm, CommentItem, CommentThread, type CommentsConfig, CommentsSection, type CtaClickedEvent, CtaViewTracker, type CtaViewedEvent, type CustomBreadcrumbItem, DEFAULT_CATEGORIES_PAGE_SIZE, DEFAULT_LAYOUT, DEFAULT_PAGE_SIZE, FAQPageSchema, type FaqItem, FeaturedArticle, type HowToStep, LatestArticles, LatestArticlesSection, type LinkTargetStrategy, type ListingPagination, type ListingPaginationContext, type MdxComponents, type MeaningfulReadEvent, PaginationNav, type PathDefinition, type PathStepAdvancedEvent, type ProofItem, type RelatedArticleClickedEvent, RelatedArticlesSection, type RichText, type RichTextSection, ScrollToTop, SeriesArticlesPage, type SharedEvent, type TocItem, type UseArticlesReturn, breadcrumbsAreEnabled, getBreadcrumbsConfig, useArticles };
1069
+ export { type AiCrawlEvent, type Article, ArticleAnswer, ArticleBackLink, type ArticleBreadcrumbEntry, type ArticleBreadcrumbToken, ArticleCard, ArticleCategoryGrid, type ArticleComment, type ArticleCommentWithReplies, ArticleDetailHero, type ArticleEvent, type ArticleEventHandler, type ArticleEventName, ArticleNavigation, ArticleSEO, ArticleSearchBar, ArticleSocialShare, ArticleTOC, ArticleViewTracker, type ArticleViewedEvent, type ArticlesConfig, ArticlesHero, ArticlesPage, type ArticlesSection, type ArticlesTheme, AuthorArticlesPage, type AuthorBreadcrumbEntry, type AuthorBreadcrumbToken, AuthorCard, type AuthorClickedEvent, AuthorDetailHero, type AuthorPageSection, type AuthorProfile, type AuthorSocial, AuthorSocialLinks, Breadcrumb, type BreadcrumbItem, type BreadcrumbLabels, BreadcrumbSchema, type BreadcrumbsConfig, CategoryArticlesPage, type CategoryBreadcrumbEntry, type CategoryBreadcrumbToken, type CategoryDescription, type CategoryInfo, type CitationReference, type CollectionPageItem, CollectionPageSchema, CommentForm, CommentItem, CommentThread, type CommentsConfig, CommentsSection, type CtaClickedEvent, CtaViewTracker, type CtaViewedEvent, type CustomBreadcrumbItem, DEFAULT_CATEGORIES_PAGE_SIZE, DEFAULT_LAYOUT, DEFAULT_PAGE_SIZE, DEFAULT_TITLE_TEMPLATE, type EntityReference, FAQPageSchema, type FaqItem, FeaturedArticle, type HowToStep, LatestArticles, LatestArticlesSection, type LinkTargetStrategy, type ListingPagination, type ListingPaginationContext, type MdxComponents, type MeaningfulReadEvent, type OrganizationConfig, OrganizationSchema, PaginationNav, type PathDefinition, type PathStepAdvancedEvent, type ProofItem, type RelatedArticleClickedEvent, RelatedArticlesSection, type RichText, type RichTextSection, ScrollToTop, SeriesArticlesPage, type SharedEvent, type TocItem, type UseArticlesReturn, WebSiteSchema, breadcrumbsAreEnabled, formatPageTitle, getBreadcrumbsConfig, getOrganizationId, getPersonId, getWebSiteId, useArticles };