@fullstackdatasolutions/articles 0.9.0 → 0.11.0

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 (48) hide show
  1. package/CHANGELOG.md +243 -0
  2. package/README.md +226 -29
  3. package/dist/index.cjs +635 -274
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +165 -56
  6. package/dist/index.d.ts +165 -56
  7. package/dist/index.js +614 -250
  8. package/dist/index.js.map +1 -1
  9. package/dist/nextjs.cjs +40 -5
  10. package/dist/nextjs.cjs.map +1 -1
  11. package/dist/nextjs.d.cts +72 -0
  12. package/dist/nextjs.d.ts +72 -0
  13. package/dist/nextjs.js +40 -5
  14. package/dist/nextjs.js.map +1 -1
  15. package/dist/server.cjs +280 -16
  16. package/dist/server.cjs.map +1 -1
  17. package/dist/server.d.cts +92 -3
  18. package/dist/server.d.ts +92 -3
  19. package/dist/server.js +269 -16
  20. package/dist/server.js.map +1 -1
  21. package/package.json +8 -5
  22. package/src/ArticleDetailHero.tsx +27 -2
  23. package/src/ArticleSchemas.tsx +27 -27
  24. package/src/AuthorArticlesPage.tsx +60 -0
  25. package/src/AuthorCard.tsx +112 -0
  26. package/src/AuthorDetailHero.tsx +56 -0
  27. package/src/Breadcrumb.tsx +78 -0
  28. package/src/CategoryArticlesPage.tsx +62 -11
  29. package/src/__tests__/ArticleDetailHero.test.tsx +21 -1
  30. package/src/__tests__/ArticleSchemas.test.tsx +47 -2
  31. package/src/__tests__/AuthorArticlesPage.test.tsx +74 -0
  32. package/src/__tests__/AuthorCard.test.tsx +98 -0
  33. package/src/__tests__/AuthorDetailHero.test.tsx +51 -0
  34. package/src/__tests__/CategoryArticlesPage.test.tsx +31 -5
  35. package/src/__tests__/articlesConfig.test.ts +20 -1
  36. package/src/__tests__/authorUtils.test.ts +89 -0
  37. package/src/__tests__/renderMdx.test.tsx +113 -0
  38. package/src/__tests__/seoUtils-authors.test.ts +160 -0
  39. package/src/__tests__/seoUtils.test.ts +4 -0
  40. package/src/__tests__/server-articles.test.ts +159 -2
  41. package/src/articleTypes.ts +33 -0
  42. package/src/articlesConfig.ts +68 -0
  43. package/src/authorUtils.ts +95 -0
  44. package/src/index.ts +32 -9
  45. package/src/renderMdx.tsx +8 -2
  46. package/src/seoUtils.ts +226 -7
  47. package/src/server-articles.ts +98 -10
  48. package/src/server.ts +19 -1
package/dist/server.cjs CHANGED
@@ -81,27 +81,38 @@ var server_exports = {};
81
81
  __export(server_exports, {
82
82
  ArticleContent: () => ArticleContent,
83
83
  ArticleTOC: () => ArticleTOC,
84
+ buildArticleBreadcrumbs: () => buildArticleBreadcrumbs,
85
+ buildAuthorBreadcrumbs: () => buildAuthorBreadcrumbs,
86
+ buildCategoryBreadcrumbs: () => buildCategoryBreadcrumbs,
84
87
  categoryToSlug: () => categoryToSlug,
85
88
  extractToc: () => extractToc,
86
89
  generateArticleMetadata: () => generateArticleMetadata,
87
90
  generateArticleStaticParams: () => generateArticleStaticParams,
88
91
  generateArticlesIndexMetadata: () => generateArticlesIndexMetadata,
92
+ generateAuthorMetadata: () => generateAuthorMetadata,
93
+ generateAuthorStaticParams: () => generateAuthorStaticParams,
89
94
  generateCategoryMetadata: () => generateCategoryMetadata,
90
95
  generateCategoryStaticParams: () => generateCategoryStaticParams,
91
96
  generateRssFeed: () => generateRssFeed,
92
97
  getAdjacentArticles: () => getAdjacentArticles,
93
98
  getAiRobotsTxtRules: () => getAiRobotsTxtRules,
94
99
  getAllArticles: () => getAllArticles,
100
+ getAllAuthors: () => getAllAuthors,
95
101
  getAllCategories: () => getAllCategories,
96
102
  getArticleAiHeaders: () => getArticleAiHeaders,
103
+ getArticleAuthors: () => getArticleAuthors,
97
104
  getArticleMarkdown: () => getArticleMarkdown,
98
105
  getArticleMarkdownResponse: () => getArticleMarkdownResponse,
99
106
  getArticleMarkdownUrl: () => getArticleMarkdownUrl,
100
107
  getArticleMetadata: () => getArticleMetadata,
101
108
  getArticleSitemapEntries: () => getArticleSitemapEntries,
109
+ getArticlesByAuthor: () => getArticlesByAuthor,
102
110
  getArticlesByCategory: () => getArticlesByCategory,
111
+ getAuthorBySlug: () => getAuthorBySlug,
103
112
  getAvailableArticleSlugs: () => getAvailableArticleSlugs,
113
+ getBreadcrumbsConfig: () => getBreadcrumbsConfig,
104
114
  markdownToHtml: () => markdownToHtml,
115
+ resolveAuthorAvatar: () => resolveAuthorAvatar,
105
116
  sanitizeImagePath: () => sanitizeImagePath2,
106
117
  searchArticles: () => searchArticles,
107
118
  setArticlesErrorHandler: () => setArticlesErrorHandler
@@ -578,7 +589,67 @@ function parseHowToSteps(raw) {
578
589
  );
579
590
  return steps.length ? steps : void 0;
580
591
  }
581
- function getArticleSummary(slug) {
592
+ function parseAuthors(raw) {
593
+ if (!Array.isArray(raw)) return void 0;
594
+ const authors = raw.filter(
595
+ (author) => typeof author === "string" && author.trim().length > 0
596
+ );
597
+ return authors;
598
+ }
599
+ function getAuthorBySlug(slug, config) {
600
+ var _a, _b;
601
+ const profile = (_a = config.authors) == null ? void 0 : _a[slug];
602
+ if (!profile) return null;
603
+ return __spreadProps(__spreadValues({}, profile), {
604
+ url: (_b = profile.url) != null ? _b : `${config.siteUrl.replace(/\/$/, "")}/articles/authors/${profile.slug}`
605
+ });
606
+ }
607
+ function getConfiguredAuthorByName(name, config) {
608
+ var _a;
609
+ const normalizedName = name.trim().toLowerCase();
610
+ const profile = Object.values((_a = config.authors) != null ? _a : {}).find(
611
+ (author) => author.name.toLowerCase() === normalizedName
612
+ );
613
+ return profile ? getAuthorBySlug(profile.slug, config) : null;
614
+ }
615
+ function resolveArticleAuthorName(rawAuthor, rawAuthors, config) {
616
+ var _a, _b, _c, _d;
617
+ const authorArray = parseAuthors(rawAuthors);
618
+ const firstAuthor = authorArray == null ? void 0 : authorArray[0];
619
+ const rawAuthorValue = typeof rawAuthor === "string" && rawAuthor.trim() ? rawAuthor : void 0;
620
+ const author = firstAuthor != null ? firstAuthor : rawAuthorValue;
621
+ const resolved = author != null ? author : config == null ? void 0 : config.defaultAuthor;
622
+ if (!resolved) return "";
623
+ if (!config) return resolved;
624
+ return (_d = (_c = (_a = getAuthorBySlug(resolved, config)) == null ? void 0 : _a.name) != null ? _c : (_b = getConfiguredAuthorByName(resolved, config)) == null ? void 0 : _b.name) != null ? _d : resolved;
625
+ }
626
+ function getArticleAuthors(article, config) {
627
+ var _a;
628
+ const fallbackAuthors = Array.from(
629
+ new Set(
630
+ [article.author, config.defaultAuthor].filter(
631
+ (author) => typeof author === "string" && author.trim().length > 0
632
+ )
633
+ )
634
+ );
635
+ const authorValues = (_a = article.authors) != null ? _a : fallbackAuthors;
636
+ if (authorValues.length === 0) return [];
637
+ const resolvedAuthors = authorValues.map((author) => {
638
+ var _a2;
639
+ return (_a2 = getAuthorBySlug(author, config)) != null ? _a2 : getConfiguredAuthorByName(author, config);
640
+ }).filter((author) => author !== null).filter((author, index, all) => all.findIndex((a) => a.slug === author.slug) === index);
641
+ if (resolvedAuthors.length > 0) return resolvedAuthors;
642
+ return authorValues.map((fallbackName) => ({
643
+ name: fallbackName,
644
+ slug: categoryToSlug(fallbackName),
645
+ bio: ""
646
+ }));
647
+ }
648
+ function getAllAuthors(config) {
649
+ var _a;
650
+ return Object.keys((_a = config.authors) != null ? _a : {}).map((slug) => getAuthorBySlug(slug, config)).filter((author) => author !== null);
651
+ }
652
+ function getArticleSummary(slug, config) {
582
653
  return __async(this, null, function* () {
583
654
  try {
584
655
  const found = findArticleFile(slug);
@@ -594,7 +665,8 @@ function getArticleSummary(slug) {
594
665
  excerpt: data.excerpt || "",
595
666
  date: parseDateField(data.date),
596
667
  lastmod: parseDateField(data.lastmod),
597
- author: data.author || "Andrew Blase",
668
+ author: resolveArticleAuthorName(data.author, data.authors, config),
669
+ authors: parseAuthors(data.authors),
598
670
  category: categories[0],
599
671
  categories,
600
672
  readTime,
@@ -623,7 +695,7 @@ function getArticleSummary(slug) {
623
695
  var getArticleMetadata = (0, import_react.cache)(
624
696
  (slug, config) => __async(void 0, null, function* () {
625
697
  try {
626
- const summary = yield getArticleSummary(slug);
698
+ const summary = yield getArticleSummary(slug, config);
627
699
  if (!summary) return null;
628
700
  const found = findArticleFile(slug);
629
701
  if (!found) return null;
@@ -649,9 +721,9 @@ var getArticleMetadata = (0, import_react.cache)(
649
721
  }
650
722
  })
651
723
  );
652
- var getAllArticles = (0, import_react.cache)(() => __async(void 0, null, function* () {
724
+ var getAllArticles = (0, import_react.cache)((config) => __async(void 0, null, function* () {
653
725
  const slugs = getAvailableArticleSlugs();
654
- const articles = yield Promise.all(slugs.map((slug) => getArticleSummary(slug)));
726
+ const articles = yield Promise.all(slugs.map((slug) => getArticleSummary(slug, config)));
655
727
  const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
656
728
  return articles.filter((article) => article !== null).filter((article) => !article.date || article.date <= currentDate).filter((article) => !(article.draft && process.env.NODE_ENV === "production")).sort((a, b) => {
657
729
  if (!a.date && !b.date) return 0;
@@ -741,8 +813,8 @@ function getAiRobotsTxtRules() {
741
813
  }
742
814
  function searchArticles(query, config) {
743
815
  return __async(this, null, function* () {
744
- if (!(query == null ? void 0 : query.trim())) return getAllArticles();
745
- const articles = yield getAllArticles();
816
+ if (!(query == null ? void 0 : query.trim())) return getAllArticles(config);
817
+ const articles = yield getAllArticles(config);
746
818
  const searchTerm = query.toLowerCase().trim();
747
819
  const includeAuthor = (config == null ? void 0 : config.showAuthor) !== false;
748
820
  return articles.filter((article) => {
@@ -779,14 +851,33 @@ function getAllCategories() {
779
851
  })).sort((a, b) => b.count - a.count);
780
852
  });
781
853
  }
782
- function getArticlesByCategory(categorySlug) {
854
+ function getArticlesByCategory(categorySlug, config) {
783
855
  return __async(this, null, function* () {
784
- const articles = yield getAllArticles();
856
+ const articles = yield getAllArticles(config);
785
857
  return articles.filter(
786
858
  (article) => article.categories.some((cat) => categoryToSlug(cat) === categorySlug)
787
859
  );
788
860
  });
789
861
  }
862
+ function getArticlesByAuthor(authorSlug, config) {
863
+ return __async(this, null, function* () {
864
+ const articles = yield getAllArticles(config);
865
+ return articles.filter(
866
+ (article) => getArticleAuthors(article, config).some((author) => author.slug === authorSlug)
867
+ );
868
+ });
869
+ }
870
+
871
+ // src/articlesConfig.ts
872
+ function breadcrumbsAreEnabled(config) {
873
+ var _a;
874
+ return config.breadcrumbs !== false && ((_a = config.breadcrumbs) == null ? void 0 : _a.show) !== false;
875
+ }
876
+ function getBreadcrumbsConfig(config) {
877
+ var _a;
878
+ if (config.breadcrumbs === false) return {};
879
+ return (_a = config.breadcrumbs) != null ? _a : {};
880
+ }
790
881
 
791
882
  // src/seoUtils.ts
792
883
  function escapeXml(str) {
@@ -835,6 +926,10 @@ function generateCategoryStaticParams() {
835
926
  return categories.map((cat) => ({ category: cat.slug }));
836
927
  });
837
928
  }
929
+ function generateAuthorStaticParams(config) {
930
+ if (config.showAuthorPage === false) return [];
931
+ return getAllAuthors(config).map((author) => ({ author: author.slug }));
932
+ }
838
933
  function resolveImageUrl(featuredImage, siteUrl) {
839
934
  const base = siteUrl.replace(/\/$/, "");
840
935
  if (featuredImage.startsWith("http://") || featuredImage.startsWith("https://")) {
@@ -845,7 +940,7 @@ function resolveImageUrl(featuredImage, siteUrl) {
845
940
  function generateArticleMetadata(slug, config) {
846
941
  return __async(this, null, function* () {
847
942
  var _a, _b, _c, _d, _e, _f, _g;
848
- const article = yield getArticleMetadata(slug);
943
+ const article = yield getArticleMetadata(slug, config);
849
944
  if (!article) {
850
945
  return {
851
946
  title: "Article Not Found",
@@ -859,6 +954,7 @@ function generateArticleMetadata(slug, config) {
859
954
  const description = (_b = article.excerpt) != null ? _b : `Read ${article.title} on ${config.siteName}.`;
860
955
  const showAuthor = config.showAuthor !== false;
861
956
  const markdownUrl = getArticleMarkdownUrl(article, config);
957
+ const authorNames = getArticleAuthors(article, config).map((author) => author.name);
862
958
  return {
863
959
  title: `${article.title} | ${config.siteName}`,
864
960
  description,
@@ -871,7 +967,7 @@ function generateArticleMetadata(slug, config) {
871
967
  images: [{ url: imageUrl, width: 1200, height: 630, alt: article.title }],
872
968
  locale: "en_US",
873
969
  type: "article"
874
- }, article.date && { publishedTime: article.date }), article.lastmod && { modifiedTime: new Date(article.lastmod).toISOString() }), showAuthor && { authors: [article.author] }), {
970
+ }, article.date && { publishedTime: article.date }), article.lastmod && { modifiedTime: new Date(article.lastmod).toISOString() }), showAuthor && authorNames.length > 0 && { authors: authorNames }), {
875
971
  tags: (_d = article.tags) != null ? _d : []
876
972
  }),
877
973
  twitter: {
@@ -898,7 +994,7 @@ function generateArticleMetadata(slug, config) {
898
994
  "max-snippet": -1
899
995
  }
900
996
  },
901
- other: __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, showAuthor && { "article:author": article.author }), article.date && {
997
+ other: __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, showAuthor && authorNames.length > 0 && { "article:author": authorNames.join(", ") }), article.date && {
902
998
  "article:published_time": new Date(article.date).toISOString()
903
999
  }), article.lastmod && {
904
1000
  "article:modified_time": new Date(article.lastmod).toISOString()
@@ -997,11 +1093,162 @@ function generateCategoryMetadata(categorySlug, config) {
997
1093
  };
998
1094
  });
999
1095
  }
1096
+ function generateAuthorMetadata(authorSlug, config) {
1097
+ return __async(this, null, function* () {
1098
+ var _a;
1099
+ const author = getAuthorBySlug(authorSlug, config);
1100
+ if (!author || config.showAuthorPage === false) return { title: "Author Not Found" };
1101
+ const siteUrl = config.siteUrl.replace(/\/$/, "");
1102
+ const authorUrl = (_a = author.url) != null ? _a : `${siteUrl}/articles/authors/${author.slug}`;
1103
+ const title = `${author.name} Articles | ${config.siteName}`;
1104
+ return {
1105
+ title,
1106
+ description: author.bio,
1107
+ openGraph: __spreadValues({
1108
+ title,
1109
+ description: author.bio,
1110
+ url: authorUrl,
1111
+ siteName: config.siteName,
1112
+ type: "profile",
1113
+ locale: "en_US"
1114
+ }, author.avatar && { images: [{ url: resolveAuthorAvatar(author, config) }] }),
1115
+ twitter: __spreadValues({
1116
+ card: "summary_large_image",
1117
+ title,
1118
+ description: author.bio
1119
+ }, author.avatar && { images: [resolveAuthorAvatar(author, config)] }),
1120
+ alternates: {
1121
+ canonical: authorUrl
1122
+ },
1123
+ robots: {
1124
+ index: true,
1125
+ follow: true
1126
+ }
1127
+ };
1128
+ });
1129
+ }
1130
+ function formatCategoryName(category) {
1131
+ return category.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1132
+ }
1133
+ function buildArticleBreadcrumbs(article, config) {
1134
+ var _a, _b;
1135
+ if (!breadcrumbsAreEnabled(config)) return [];
1136
+ const siteUrl = config.siteUrl.replace(/\/$/, "");
1137
+ const breadcrumbConfig = getBreadcrumbsConfig(config);
1138
+ const labels = (_a = breadcrumbConfig.labels) != null ? _a : {};
1139
+ const categorySlug = categoryToSlug(article.category);
1140
+ const trail = (_b = breadcrumbConfig.article) != null ? _b : ["home", "articles", "primaryCategory", "articleTitle"];
1141
+ const folderSegments = article.slug.split("/").filter(Boolean).slice(0, -1);
1142
+ return trail.flatMap(
1143
+ (token) => buildArticleBreadcrumbToken(token, {
1144
+ article,
1145
+ siteUrl,
1146
+ categorySlug,
1147
+ folderSegments,
1148
+ labels
1149
+ })
1150
+ );
1151
+ }
1152
+ function buildCategoryBreadcrumbs(category, config, categoryName = formatCategoryName(category)) {
1153
+ var _a, _b;
1154
+ if (!breadcrumbsAreEnabled(config)) return [];
1155
+ const siteUrl = config.siteUrl.replace(/\/$/, "");
1156
+ const breadcrumbConfig = getBreadcrumbsConfig(config);
1157
+ const labels = (_a = breadcrumbConfig.labels) != null ? _a : {};
1158
+ const trail = (_b = breadcrumbConfig.category) != null ? _b : ["home", "articles", "category"];
1159
+ return trail.flatMap(
1160
+ (entry) => buildCategoryBreadcrumbEntry(entry, { categoryName, siteUrl, labels })
1161
+ );
1162
+ }
1163
+ function buildAuthorBreadcrumbs(author, config) {
1164
+ var _a, _b;
1165
+ if (!breadcrumbsAreEnabled(config)) return [];
1166
+ const siteUrl = config.siteUrl.replace(/\/$/, "");
1167
+ const breadcrumbConfig = getBreadcrumbsConfig(config);
1168
+ const labels = (_a = breadcrumbConfig.labels) != null ? _a : {};
1169
+ const trail = (_b = breadcrumbConfig.author) != null ? _b : ["home", "articles", "authors", "authorName"];
1170
+ return trail.flatMap(
1171
+ (entry) => buildAuthorBreadcrumbEntry(entry, { author, siteUrl, labels })
1172
+ );
1173
+ }
1174
+ function isCustomBreadcrumbItem(entry) {
1175
+ return typeof entry === "object" && entry !== null && "name" in entry && "url" in entry;
1176
+ }
1177
+ function resolveCustomBreadcrumbItem(item, siteUrl) {
1178
+ if (item.url.startsWith("/")) return { name: item.name, url: `${siteUrl}${item.url}` };
1179
+ return { name: item.name, url: item.url };
1180
+ }
1181
+ function buildArticleBreadcrumbToken(entry, context) {
1182
+ var _a, _b;
1183
+ if (isCustomBreadcrumbItem(entry)) {
1184
+ return [resolveCustomBreadcrumbItem(entry, context.siteUrl)];
1185
+ }
1186
+ if (entry === "home") return [{ name: (_a = context.labels.home) != null ? _a : "Home", url: context.siteUrl }];
1187
+ if (entry === "articles") {
1188
+ return [{ name: (_b = context.labels.articles) != null ? _b : "Articles", url: `${context.siteUrl}/articles` }];
1189
+ }
1190
+ if (entry === "primaryCategory") {
1191
+ return [
1192
+ {
1193
+ name: context.article.category,
1194
+ url: `${context.siteUrl}/articles/category/${context.categorySlug}`
1195
+ }
1196
+ ];
1197
+ }
1198
+ if (entry === "folderPath") {
1199
+ return context.folderSegments.map((segment, index) => ({
1200
+ name: formatCategoryName(segment),
1201
+ url: `${context.siteUrl}/articles/${context.folderSegments.slice(0, index + 1).join("/")}`
1202
+ }));
1203
+ }
1204
+ return [{ name: context.article.title }];
1205
+ }
1206
+ function buildCategoryBreadcrumbEntry(entry, context) {
1207
+ var _a, _b;
1208
+ if (isCustomBreadcrumbItem(entry)) {
1209
+ return [resolveCustomBreadcrumbItem(entry, context.siteUrl)];
1210
+ }
1211
+ if (entry === "home") return [{ name: (_a = context.labels.home) != null ? _a : "Home", url: context.siteUrl }];
1212
+ if (entry === "articles") {
1213
+ return [{ name: (_b = context.labels.articles) != null ? _b : "Articles", url: `${context.siteUrl}/articles` }];
1214
+ }
1215
+ return [{ name: context.categoryName }];
1216
+ }
1217
+ function buildAuthorBreadcrumbEntry(entry, context) {
1218
+ var _a, _b, _c;
1219
+ if (isCustomBreadcrumbItem(entry)) {
1220
+ return [resolveCustomBreadcrumbItem(entry, context.siteUrl)];
1221
+ }
1222
+ if (entry === "home") return [{ name: (_a = context.labels.home) != null ? _a : "Home", url: context.siteUrl }];
1223
+ if (entry === "articles") {
1224
+ return [{ name: (_b = context.labels.articles) != null ? _b : "Articles", url: `${context.siteUrl}/articles` }];
1225
+ }
1226
+ if (entry === "authors") {
1227
+ return [
1228
+ {
1229
+ name: (_c = context.labels.authors) != null ? _c : "Authors",
1230
+ url: `${context.siteUrl}/articles/authors`
1231
+ }
1232
+ ];
1233
+ }
1234
+ return [{ name: context.author.name }];
1235
+ }
1236
+ function resolveAuthorAvatar(author, config) {
1237
+ if (!author.avatar) return "";
1238
+ if (author.avatar.startsWith("http://") || author.avatar.startsWith("https://")) {
1239
+ return author.avatar;
1240
+ }
1241
+ const siteUrl = config.siteUrl.replace(/\/$/, "");
1242
+ return `${siteUrl}/articles/authors/${author.slug}/${author.avatar.replace(/^\/+/, "")}`;
1243
+ }
1000
1244
  function getArticleSitemapEntries(baseUrlOrConfig) {
1001
1245
  return __async(this, null, function* () {
1002
1246
  const baseUrl = (typeof baseUrlOrConfig === "string" ? baseUrlOrConfig : baseUrlOrConfig.siteUrl).replace(/\/$/, "");
1003
1247
  try {
1004
- const [articles, categories] = yield Promise.all([getAllArticles(), getAllCategories()]);
1248
+ const [articles, categories] = yield Promise.all([
1249
+ getAllArticles(typeof baseUrlOrConfig === "string" ? void 0 : baseUrlOrConfig),
1250
+ getAllCategories()
1251
+ ]);
1005
1252
  const articleEntries = articles.map((article) => {
1006
1253
  var _a;
1007
1254
  const dateStr = (_a = article.lastmod) != null ? _a : article.date;
@@ -1019,7 +1266,12 @@ function getArticleSitemapEntries(baseUrlOrConfig) {
1019
1266
  changeFrequency: "weekly",
1020
1267
  priority: 0.7
1021
1268
  }));
1022
- return [...articleEntries, ...categoryEntries];
1269
+ const authorEntries = typeof baseUrlOrConfig === "string" || baseUrlOrConfig.showAuthorPage === false ? [] : getAllAuthors(baseUrlOrConfig).map((author) => ({
1270
+ url: `${baseUrl}/articles/authors/${author.slug}`,
1271
+ changeFrequency: "monthly",
1272
+ priority: 0.6
1273
+ }));
1274
+ return [...articleEntries, ...categoryEntries, ...authorEntries];
1023
1275
  } catch (e) {
1024
1276
  return [];
1025
1277
  }
@@ -1039,7 +1291,7 @@ var import_jsx_runtime = require("react/jsx-runtime");
1039
1291
  function makeImgComponent(basePath) {
1040
1292
  return function MdxImage(_a) {
1041
1293
  var _b = _a, { src, alt } = _b, props = __objRest(_b, ["src", "alt"]);
1042
- const resolvedSrc = src && !src.startsWith("http") && !src.startsWith("/") ? `${basePath}/${src}` : src;
1294
+ const resolvedSrc = typeof src === "string" && !src.startsWith("http") && !src.startsWith("/") ? `${basePath}/${src}` : src;
1043
1295
  return import_react2.default.createElement("img", __spreadValues({ src: resolvedSrc, alt }, props));
1044
1296
  };
1045
1297
  }
@@ -1057,7 +1309,8 @@ function renderMdxSource(source, basePath, config) {
1057
1309
  ]
1058
1310
  }));
1059
1311
  const Content = mdxModule.default;
1060
- const components = basePath ? { img: makeImgComponent(basePath) } : void 0;
1312
+ const internalComponents = basePath ? { img: makeImgComponent(basePath) } : void 0;
1313
+ const components = internalComponents || (config == null ? void 0 : config.mdxComponents) ? __spreadValues(__spreadValues({}, internalComponents), config == null ? void 0 : config.mdxComponents) : void 0;
1061
1314
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Content, { components });
1062
1315
  });
1063
1316
  }
@@ -1101,27 +1354,38 @@ function ArticleTOC({ toc, className }) {
1101
1354
  0 && (module.exports = {
1102
1355
  ArticleContent,
1103
1356
  ArticleTOC,
1357
+ buildArticleBreadcrumbs,
1358
+ buildAuthorBreadcrumbs,
1359
+ buildCategoryBreadcrumbs,
1104
1360
  categoryToSlug,
1105
1361
  extractToc,
1106
1362
  generateArticleMetadata,
1107
1363
  generateArticleStaticParams,
1108
1364
  generateArticlesIndexMetadata,
1365
+ generateAuthorMetadata,
1366
+ generateAuthorStaticParams,
1109
1367
  generateCategoryMetadata,
1110
1368
  generateCategoryStaticParams,
1111
1369
  generateRssFeed,
1112
1370
  getAdjacentArticles,
1113
1371
  getAiRobotsTxtRules,
1114
1372
  getAllArticles,
1373
+ getAllAuthors,
1115
1374
  getAllCategories,
1116
1375
  getArticleAiHeaders,
1376
+ getArticleAuthors,
1117
1377
  getArticleMarkdown,
1118
1378
  getArticleMarkdownResponse,
1119
1379
  getArticleMarkdownUrl,
1120
1380
  getArticleMetadata,
1121
1381
  getArticleSitemapEntries,
1382
+ getArticlesByAuthor,
1122
1383
  getArticlesByCategory,
1384
+ getAuthorBySlug,
1123
1385
  getAvailableArticleSlugs,
1386
+ getBreadcrumbsConfig,
1124
1387
  markdownToHtml,
1388
+ resolveAuthorAvatar,
1125
1389
  sanitizeImagePath,
1126
1390
  searchArticles,
1127
1391
  setArticlesErrorHandler