@xexr/blog-platform 1.1.4 → 1.1.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/app/blog/[slug]/page.tsx +10 -3
  3. package/dist/app/blog/page.tsx +12 -11
  4. package/dist/app/blog/series/[slug]/page.d.ts +28 -0
  5. package/dist/app/blog/series/[slug]/page.tsx +39 -0
  6. package/dist/app/blog/series/page.d.ts +24 -0
  7. package/dist/app/blog/series/page.tsx +28 -0
  8. package/dist/components/ArchiveStructuredData.tsx +61 -0
  9. package/dist/components/SeriesArchivePages.tsx +222 -0
  10. package/dist/components/SeriesNavigation.tsx +117 -0
  11. package/dist/components/TopicArchivePages.test.ts +52 -4
  12. package/dist/components/TopicArchivePages.tsx +14 -4
  13. package/dist/{index-Dr8HaKGm.d.mts → index-DsXjuPn4.d.mts} +45 -1
  14. package/dist/{index-Dr8HaKGm.d.ts → index-DsXjuPn4.d.ts} +45 -1
  15. package/dist/index.d.mts +86 -5
  16. package/dist/index.d.ts +86 -5
  17. package/dist/index.js +14 -14
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +14 -14
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/lib/related-articles.d.mts +3 -2
  22. package/dist/lib/related-articles.d.ts +3 -2
  23. package/dist/lib/series.ts +55 -0
  24. package/dist/lib/sitemap.ts +78 -46
  25. package/dist/lib/storage/drizzle.ts +9 -0
  26. package/dist/lib/structured-data.ts +10 -11
  27. package/dist/lib/urls.ts +7 -0
  28. package/dist/{sitemap-BmCh8BpN.d.ts → sitemap-B64QGT4l.d.ts} +11 -4
  29. package/dist/{sitemap-Dbl4CUGI.d.mts → sitemap-Dy7Q4ATM.d.mts} +11 -4
  30. package/dist/sitemap.d.mts +2 -2
  31. package/dist/sitemap.d.ts +2 -2
  32. package/dist/sitemap.js +5 -5
  33. package/dist/sitemap.js.map +1 -1
  34. package/dist/sitemap.mjs +5 -5
  35. package/dist/sitemap.mjs.map +1 -1
  36. package/dist/types/contracts.ts +61 -0
  37. package/dist/types/index.d.mts +1 -1
  38. package/dist/types/index.d.ts +1 -1
  39. package/package.json +12 -13
@@ -1,4 +1,4 @@
1
- import { P as PublishedTopic, a as PublishedArticle } from '../index-Dr8HaKGm.mjs';
1
+ import { PublishedTopic, PublishedArticle } from '../index.mjs';
2
2
 
3
3
  interface RelatedArticleCandidate {
4
4
  readonly id: string;
@@ -14,4 +14,5 @@ interface RelatedFeaturedArticlesOptions {
14
14
  declare function getRelatedFeaturedArticles<TArticle extends RelatedArticleCandidate>(currentArticle: RelatedArticleCandidate, articles: readonly TArticle[], options?: RelatedFeaturedArticlesOptions): TArticle[];
15
15
  type RelatedPublishedArticle = PublishedArticle;
16
16
 
17
- export { type RelatedArticleCandidate, type RelatedFeaturedArticlesOptions, type RelatedPublishedArticle, getRelatedFeaturedArticles };
17
+ export { getRelatedFeaturedArticles };
18
+ export type { RelatedArticleCandidate, RelatedFeaturedArticlesOptions, RelatedPublishedArticle };
@@ -1,4 +1,4 @@
1
- import { P as PublishedTopic, a as PublishedArticle } from '../index-Dr8HaKGm.js';
1
+ import { PublishedTopic, PublishedArticle } from '../index.js';
2
2
 
3
3
  interface RelatedArticleCandidate {
4
4
  readonly id: string;
@@ -14,4 +14,5 @@ interface RelatedFeaturedArticlesOptions {
14
14
  declare function getRelatedFeaturedArticles<TArticle extends RelatedArticleCandidate>(currentArticle: RelatedArticleCandidate, articles: readonly TArticle[], options?: RelatedFeaturedArticlesOptions): TArticle[];
15
15
  type RelatedPublishedArticle = PublishedArticle;
16
16
 
17
- export { type RelatedArticleCandidate, type RelatedFeaturedArticlesOptions, type RelatedPublishedArticle, getRelatedFeaturedArticles };
17
+ export { getRelatedFeaturedArticles };
18
+ export type { RelatedArticleCandidate, RelatedFeaturedArticlesOptions, RelatedPublishedArticle };
@@ -0,0 +1,55 @@
1
+ import type {
2
+ PublishedArticle,
3
+ PublishedSeriesContext,
4
+ } from "../types/contracts";
5
+
6
+ export interface SeriesArchive {
7
+ series: PublishedSeriesContext;
8
+ articles: PublishedArticle[];
9
+ }
10
+
11
+ export function getAllSeries(
12
+ articles: PublishedArticle[],
13
+ ): PublishedSeriesContext[] {
14
+ const seriesBySlug = new Map<string, PublishedSeriesContext>();
15
+
16
+ for (const article of articles) {
17
+ if (
18
+ article.series &&
19
+ (!seriesBySlug.has(article.series.slug) ||
20
+ article.series.articles.length >
21
+ (seriesBySlug.get(article.series.slug)?.articles.length ?? 0))
22
+ ) {
23
+ seriesBySlug.set(article.series.slug, article.series);
24
+ }
25
+ }
26
+
27
+ return Array.from(seriesBySlug.values()).sort((a, b) =>
28
+ a.title.localeCompare(b.title),
29
+ );
30
+ }
31
+
32
+ export function getSeriesArchive(
33
+ articles: PublishedArticle[],
34
+ seriesSlug: string,
35
+ ): SeriesArchive | null {
36
+ const matchingArticles = articles
37
+ .filter((article) => article.series?.slug === seriesSlug)
38
+ .sort((a, b) => (a.series?.position ?? 0) - (b.series?.position ?? 0));
39
+
40
+ if (matchingArticles.length === 0) return null;
41
+
42
+ const series = matchingArticles[0]?.series;
43
+ if (!series) return null;
44
+
45
+ return {
46
+ series,
47
+ articles: matchingArticles,
48
+ };
49
+ }
50
+
51
+ export function getArticleSeriesNavigation(
52
+ article: PublishedArticle,
53
+ ): PublishedSeriesContext | null {
54
+ return article.series ?? null;
55
+ }
@@ -36,8 +36,9 @@ import {
36
36
  normalizeDomain,
37
37
  type CanonicalUrlOptions,
38
38
  } from "./seo";
39
+ import { getAllSeries } from "./series";
39
40
  import { getAllTopics } from "./topics";
40
- import { buildAuthorPath, buildBlogPath } from "./urls";
41
+ import { buildAuthorPath, buildBlogPath, buildSeriesPath } from "./urls";
41
42
 
42
43
  /**
43
44
  * Configuration options for sitemap generation.
@@ -52,10 +53,13 @@ export interface SitemapOptions {
52
53
  /** Whether to include topic pages in sitemap */
53
54
  includeTopicPages?: boolean;
54
55
 
55
- /** Whether to include pagination pages in sitemap */
56
+ /** Whether to include series pages in sitemap */
57
+ includeSeriesPages?: boolean;
58
+
59
+ /** @deprecated Pagination pages are never included. */
56
60
  includePaginationPages?: boolean;
57
61
 
58
- /** Number of articles per page for pagination calculation */
62
+ /** @deprecated Pagination pages are never included. */
59
63
  articlesPerPage?: number;
60
64
 
61
65
  /** Maximum number of sitemap entries (defaults to 50,000 per Google guidelines) */
@@ -71,6 +75,8 @@ export interface SitemapOptions {
71
75
  authorPages?: SitemapChangeFreq;
72
76
  /** Change frequency for topic index and archive pages */
73
77
  topicPages?: SitemapChangeFreq;
78
+ /** Change frequency for series index and archive pages */
79
+ seriesPages?: SitemapChangeFreq;
74
80
  /** Change frequency for pagination pages */
75
81
  paginationPages?: SitemapChangeFreq;
76
82
  };
@@ -85,6 +91,8 @@ export interface SitemapOptions {
85
91
  authorPages?: number;
86
92
  /** Priority for topic index and archive pages (0.0-1.0) */
87
93
  topicPages?: number;
94
+ /** Priority for series index and archive pages (0.0-1.0) */
95
+ seriesPages?: number;
88
96
  /** Priority for pagination pages (0.0-1.0) */
89
97
  paginationPages?: number;
90
98
  };
@@ -204,8 +212,7 @@ export async function generateBlogSitemapEntries(
204
212
  const {
205
213
  includeAuthorPages = true,
206
214
  includeTopicPages = true,
207
- includePaginationPages = true,
208
- articlesPerPage = 10,
215
+ includeSeriesPages = true,
209
216
  maxEntries = 50000,
210
217
  changeFrequency = {},
211
218
  priority = {},
@@ -221,6 +228,7 @@ export async function generateBlogSitemapEntries(
221
228
  const sitemapAuthors =
222
229
  authors.length > 0 ? authors : getAuthorsFromArticles(articles);
223
230
  const sitemapTopics = getAllTopics([...articles]);
231
+ const sitemapSeries = getAllSeries([...articles]);
224
232
 
225
233
  // Add blog home page
226
234
  entries.push({
@@ -257,7 +265,9 @@ export async function generateBlogSitemapEntries(
257
265
  if (entries.length >= maxEntries) return;
258
266
 
259
267
  const topicArticles = articles.filter((article) =>
260
- (article.topics ?? []).some((candidate) => candidate.slug === topic.slug),
268
+ (article.topics ?? []).some(
269
+ (candidate) => candidate.slug === topic.slug,
270
+ ),
261
271
  );
262
272
 
263
273
  entries.push({
@@ -269,6 +279,32 @@ export async function generateBlogSitemapEntries(
269
279
  });
270
280
  }
271
281
 
282
+ if (includeSeriesPages && sitemapSeries.length > 0) {
283
+ if (entries.length < maxEntries) {
284
+ entries.push({
285
+ url: `${baseUrl}${buildBlogPath(pathPrefix, "series")}`,
286
+ lastModified: getLatestModificationDate(articles),
287
+ changeFrequency: changeFrequency.seriesPages ?? "weekly",
288
+ priority: priority.seriesPages ?? 0.6,
289
+ });
290
+ }
291
+
292
+ sitemapSeries.forEach((series) => {
293
+ if (entries.length >= maxEntries) return;
294
+
295
+ const seriesArticles = articles.filter(
296
+ (article) => article.series?.slug === series.slug,
297
+ );
298
+
299
+ entries.push({
300
+ url: `${baseUrl}${buildSeriesPath(pathPrefix, series.slug)}`,
301
+ lastModified: getLatestModificationDate(seriesArticles),
302
+ changeFrequency: changeFrequency.seriesPages ?? "weekly",
303
+ priority: priority.seriesPages ?? 0.6,
304
+ });
305
+ });
306
+ }
307
+
272
308
  // Add author pages if enabled
273
309
  if (includeAuthorPages && sitemapAuthors.length > 0) {
274
310
  if (entries.length < maxEntries) {
@@ -300,22 +336,6 @@ export async function generateBlogSitemapEntries(
300
336
  });
301
337
  }
302
338
 
303
- // Add pagination pages if enabled
304
- if (includePaginationPages && articles.length > articlesPerPage) {
305
- const totalPages = Math.ceil(articles.length / articlesPerPage);
306
-
307
- for (let page = 2; page <= totalPages; page++) {
308
- if (entries.length >= maxEntries) break;
309
-
310
- entries.push({
311
- url: `${baseUrl}${pathPrefix}?page=${page}`,
312
- lastModified: getLatestModificationDate(articles),
313
- changeFrequency: changeFrequency.paginationPages ?? "daily",
314
- priority: priority.paginationPages ?? 0.5,
315
- });
316
- }
317
- }
318
-
319
339
  return entries;
320
340
  }
321
341
 
@@ -338,8 +358,7 @@ export function generateSitemap(
338
358
  const {
339
359
  includeAuthorPages = true,
340
360
  includeTopicPages = true,
341
- includePaginationPages = true,
342
- articlesPerPage = 10,
361
+ includeSeriesPages = true,
343
362
  maxEntries = 50000,
344
363
  changeFrequency = {},
345
364
  priority = {},
@@ -356,6 +375,7 @@ export function generateSitemap(
356
375
  const sitemapAuthors =
357
376
  authors.length > 0 ? authors : getAuthorsFromArticles(articles);
358
377
  const sitemapTopics = getAllTopics([...articles]);
378
+ const sitemapSeries = getAllSeries([...articles]);
359
379
 
360
380
  // Calculate total potential entries to determine if truncation will occur
361
381
  let potentialEntries = 1; // Home page
@@ -363,12 +383,12 @@ export function generateSitemap(
363
383
  if (includeTopicPages && sitemapTopics.length > 0) {
364
384
  potentialEntries += sitemapTopics.length + 1; // Topic index + topic pages
365
385
  }
366
- if (includeAuthorPages) {
367
- potentialEntries += sitemapAuthors.length > 0 ? sitemapAuthors.length + 1 : 0; // Authors index + author pages
386
+ if (includeSeriesPages && sitemapSeries.length > 0) {
387
+ potentialEntries += sitemapSeries.length + 1; // Series index + series pages
368
388
  }
369
- if (includePaginationPages && articles.length > articlesPerPage) {
370
- const totalPages = Math.ceil(articles.length / articlesPerPage);
371
- potentialEntries += totalPages - 1; // Pagination pages (excluding page 1 which is home)
389
+ if (includeAuthorPages) {
390
+ potentialEntries +=
391
+ sitemapAuthors.length > 0 ? sitemapAuthors.length + 1 : 0; // Authors index + author pages
372
392
  }
373
393
 
374
394
  const willTruncate = potentialEntries > maxEntries;
@@ -408,7 +428,9 @@ export function generateSitemap(
408
428
  if (entries.length >= maxEntries) return;
409
429
 
410
430
  const topicArticles = articles.filter((article) =>
411
- (article.topics ?? []).some((candidate) => candidate.slug === topic.slug),
431
+ (article.topics ?? []).some(
432
+ (candidate) => candidate.slug === topic.slug,
433
+ ),
412
434
  );
413
435
 
414
436
  entries.push({
@@ -420,6 +442,32 @@ export function generateSitemap(
420
442
  });
421
443
  }
422
444
 
445
+ if (includeSeriesPages && sitemapSeries.length > 0) {
446
+ if (entries.length < maxEntries) {
447
+ entries.push({
448
+ loc: `${baseUrl}${buildBlogPath(pathPrefix, "series")}`,
449
+ lastmod: getLatestModificationDate(articles),
450
+ changefreq: changeFrequency.seriesPages ?? "weekly",
451
+ priority: priority.seriesPages ?? 0.6,
452
+ });
453
+ }
454
+
455
+ sitemapSeries.forEach((series) => {
456
+ if (entries.length >= maxEntries) return;
457
+
458
+ const seriesArticles = articles.filter(
459
+ (article) => article.series?.slug === series.slug,
460
+ );
461
+
462
+ entries.push({
463
+ loc: `${baseUrl}${buildSeriesPath(pathPrefix, series.slug)}`,
464
+ lastmod: getLatestModificationDate(seriesArticles),
465
+ changefreq: changeFrequency.seriesPages ?? "weekly",
466
+ priority: priority.seriesPages ?? 0.6,
467
+ });
468
+ });
469
+ }
470
+
423
471
  // Add author pages if enabled
424
472
  if (includeAuthorPages && sitemapAuthors.length > 0) {
425
473
  if (entries.length < maxEntries) {
@@ -451,22 +499,6 @@ export function generateSitemap(
451
499
  });
452
500
  }
453
501
 
454
- // Add pagination pages if enabled
455
- if (includePaginationPages && articles.length > articlesPerPage) {
456
- const totalPages = Math.ceil(articles.length / articlesPerPage);
457
-
458
- for (let page = 2; page <= totalPages; page++) {
459
- if (entries.length >= maxEntries) break;
460
-
461
- entries.push({
462
- loc: `${baseUrl}${pathPrefix}?page=${page}`,
463
- lastmod: getLatestModificationDate(articles),
464
- changefreq: changeFrequency.paginationPages ?? "daily",
465
- priority: priority.paginationPages ?? 0.5,
466
- });
467
- }
468
- }
469
-
470
502
  return {
471
503
  entries,
472
504
  totalEntries: entries.length,
@@ -98,6 +98,7 @@ function toRow(article: PublishedArticle): ArticleRow {
98
98
  metaJson: JSON.stringify({
99
99
  ...article.meta,
100
100
  __bloggyTopics: article.topics ?? [],
101
+ __bloggySeries: article.series ?? null,
101
102
  __bloggyCta: article.cta ?? null,
102
103
  }),
103
104
  version: article.version,
@@ -126,6 +127,7 @@ function fromRow(row: ArticleRow): PublishedArticle {
126
127
  site: JSON.parse(row.siteJson) as PublishedSite,
127
128
  cta: extractCta(row.metaJson),
128
129
  topics: extractTopics(row.metaJson),
130
+ series: extractSeries(row.metaJson),
129
131
  meta: extractMeta(row.metaJson),
130
132
  version: row.version,
131
133
  };
@@ -133,6 +135,7 @@ function fromRow(row: ArticleRow): PublishedArticle {
133
135
 
134
136
  type StoredArticleMeta = PublishedArticle["meta"] & {
135
137
  __bloggyTopics?: PublishedArticle["topics"];
138
+ __bloggySeries?: PublishedArticle["series"] | null;
136
139
  __bloggyCta?: PublishedArticle["cta"] | null;
137
140
  };
138
141
 
@@ -150,9 +153,15 @@ function extractCta(metaJson: string): PublishedArticle["cta"] {
150
153
  return parsed.__bloggyCta ?? undefined;
151
154
  }
152
155
 
156
+ function extractSeries(metaJson: string): PublishedArticle["series"] {
157
+ const parsed = parseStoredMeta(metaJson);
158
+ return parsed.__bloggySeries ?? undefined;
159
+ }
160
+
153
161
  function extractMeta(metaJson: string): PublishedArticle["meta"] {
154
162
  const parsed = parseStoredMeta(metaJson);
155
163
  delete parsed.__bloggyTopics;
164
+ delete parsed.__bloggySeries;
156
165
  delete parsed.__bloggyCta;
157
166
  const meta = parsed;
158
167
  return meta;
@@ -222,18 +222,18 @@ export function generateArticleStructuredData(
222
222
  schema.inLanguage = language ?? article.site.locale;
223
223
  }
224
224
 
225
- // Extract topics from tone adjectives or keywords for 'about' property
226
- if (article.site.toneAdjectives.length > 0) {
227
- schema.about = article.site.toneAdjectives.map((topic) => ({
225
+ const subjects = [
226
+ ...(article.topics ?? []).map((topic) => topic.name),
227
+ ...(article.series ? [article.series.title] : []),
228
+ ];
229
+ if (subjects.length) {
230
+ schema.about = [...new Set(subjects)].map((name) => ({
228
231
  "@type": "Thing" as const,
229
- name: topic,
232
+ name,
230
233
  }));
231
234
  }
232
235
 
233
- // Genre based on site description or tone
234
- if (article.site.toneAdjectives.length > 0) {
235
- schema.genre = [...article.site.toneAdjectives];
236
- }
236
+
237
237
  }
238
238
 
239
239
  return schema;
@@ -288,9 +288,8 @@ export function generateAuthorStructuredData(
288
288
  schema.additionalType = "GuestAuthor";
289
289
  }
290
290
 
291
- // Add knowledge areas from tone adjectives
292
- if (author.toneAdjectives && author.toneAdjectives.length > 0) {
293
- schema.knowsAbout = [...author.toneAdjectives];
291
+ if (author.expertise?.length) {
292
+ schema.knowsAbout = [...author.expertise];
294
293
  }
295
294
 
296
295
  return schema;
package/dist/lib/urls.ts CHANGED
@@ -30,6 +30,13 @@ export function buildAuthorPath(
30
30
  return buildBlogPath(basePath, `authors/${authorSlug}`);
31
31
  }
32
32
 
33
+ export function buildSeriesPath(
34
+ basePath: string | undefined,
35
+ seriesSlug: string,
36
+ ): string {
37
+ return buildBlogPath(basePath, `series/${seriesSlug}`);
38
+ }
39
+
33
40
  export function getPathPrefixFromBlogUrl(blogUrl: string): string {
34
41
  const parsed = new URL(blogUrl);
35
42
  return normalizeBlogBasePath(parsed.pathname);
@@ -1,4 +1,4 @@
1
- import { a as PublishedArticle, b as PublishedSite, c as PublishedAuthor } from './index-Dr8HaKGm.js';
1
+ import { a as PublishedArticle, b as PublishedSite, c as PublishedAuthor } from './index-DsXjuPn4.js';
2
2
 
3
3
  /**
4
4
  * SEO utilities for canonical URL generation and validation.
@@ -171,9 +171,11 @@ interface SitemapOptions {
171
171
  includeAuthorPages?: boolean;
172
172
  /** Whether to include topic pages in sitemap */
173
173
  includeTopicPages?: boolean;
174
- /** Whether to include pagination pages in sitemap */
174
+ /** Whether to include series pages in sitemap */
175
+ includeSeriesPages?: boolean;
176
+ /** @deprecated Pagination pages are never included. */
175
177
  includePaginationPages?: boolean;
176
- /** Number of articles per page for pagination calculation */
178
+ /** @deprecated Pagination pages are never included. */
177
179
  articlesPerPage?: number;
178
180
  /** Maximum number of sitemap entries (defaults to 50,000 per Google guidelines) */
179
181
  maxEntries?: number;
@@ -187,6 +189,8 @@ interface SitemapOptions {
187
189
  authorPages?: SitemapChangeFreq;
188
190
  /** Change frequency for topic index and archive pages */
189
191
  topicPages?: SitemapChangeFreq;
192
+ /** Change frequency for series index and archive pages */
193
+ seriesPages?: SitemapChangeFreq;
190
194
  /** Change frequency for pagination pages */
191
195
  paginationPages?: SitemapChangeFreq;
192
196
  };
@@ -200,6 +204,8 @@ interface SitemapOptions {
200
204
  authorPages?: number;
201
205
  /** Priority for topic index and archive pages (0.0-1.0) */
202
206
  topicPages?: number;
207
+ /** Priority for series index and archive pages (0.0-1.0) */
208
+ seriesPages?: number;
203
209
  /** Priority for pagination pages (0.0-1.0) */
204
210
  paginationPages?: number;
205
211
  };
@@ -419,4 +425,5 @@ interface BlogSitemapConfig {
419
425
  */
420
426
  declare function createDynamicBlogSitemap(config: BlogSitemapConfig): () => Promise<NextjsSitemapEntry[]>;
421
427
 
422
- export { type BlogSitemapConfig as B, type CanonicalUrlOptions as C, type NextjsSitemapEntry as N, type SitemapChangeFreq as S, type SitemapData as a, type SitemapEntry as b, type SitemapOptions as c, createBlogSitemapRoute as d, createDynamicBlogSitemap as e, generateCanonicalUrl as f, generateBlogSitemapEntries as g, generateCanonicalUrlFromSlug as h, generateSitemap as i, generateSitemapIndex as j, getBaseUrl as k, isValidCanonicalUrl as l, normalizeSlug as m, normalizeDomain as n, sitemapToXml as s, updateArticleCanonicalUrl as u, validateSitemap as v };
428
+ export { createBlogSitemapRoute as d, createDynamicBlogSitemap as e, generateCanonicalUrl as f, generateBlogSitemapEntries as g, generateCanonicalUrlFromSlug as h, generateSitemap as i, generateSitemapIndex as j, getBaseUrl as k, isValidCanonicalUrl as l, normalizeSlug as m, normalizeDomain as n, sitemapToXml as s, updateArticleCanonicalUrl as u, validateSitemap as v };
429
+ export type { BlogSitemapConfig as B, CanonicalUrlOptions as C, NextjsSitemapEntry as N, SitemapChangeFreq as S, SitemapData as a, SitemapEntry as b, SitemapOptions as c };
@@ -1,4 +1,4 @@
1
- import { a as PublishedArticle, b as PublishedSite, c as PublishedAuthor } from './index-Dr8HaKGm.mjs';
1
+ import { a as PublishedArticle, b as PublishedSite, c as PublishedAuthor } from './index-DsXjuPn4.mjs';
2
2
 
3
3
  /**
4
4
  * SEO utilities for canonical URL generation and validation.
@@ -171,9 +171,11 @@ interface SitemapOptions {
171
171
  includeAuthorPages?: boolean;
172
172
  /** Whether to include topic pages in sitemap */
173
173
  includeTopicPages?: boolean;
174
- /** Whether to include pagination pages in sitemap */
174
+ /** Whether to include series pages in sitemap */
175
+ includeSeriesPages?: boolean;
176
+ /** @deprecated Pagination pages are never included. */
175
177
  includePaginationPages?: boolean;
176
- /** Number of articles per page for pagination calculation */
178
+ /** @deprecated Pagination pages are never included. */
177
179
  articlesPerPage?: number;
178
180
  /** Maximum number of sitemap entries (defaults to 50,000 per Google guidelines) */
179
181
  maxEntries?: number;
@@ -187,6 +189,8 @@ interface SitemapOptions {
187
189
  authorPages?: SitemapChangeFreq;
188
190
  /** Change frequency for topic index and archive pages */
189
191
  topicPages?: SitemapChangeFreq;
192
+ /** Change frequency for series index and archive pages */
193
+ seriesPages?: SitemapChangeFreq;
190
194
  /** Change frequency for pagination pages */
191
195
  paginationPages?: SitemapChangeFreq;
192
196
  };
@@ -200,6 +204,8 @@ interface SitemapOptions {
200
204
  authorPages?: number;
201
205
  /** Priority for topic index and archive pages (0.0-1.0) */
202
206
  topicPages?: number;
207
+ /** Priority for series index and archive pages (0.0-1.0) */
208
+ seriesPages?: number;
203
209
  /** Priority for pagination pages (0.0-1.0) */
204
210
  paginationPages?: number;
205
211
  };
@@ -419,4 +425,5 @@ interface BlogSitemapConfig {
419
425
  */
420
426
  declare function createDynamicBlogSitemap(config: BlogSitemapConfig): () => Promise<NextjsSitemapEntry[]>;
421
427
 
422
- export { type BlogSitemapConfig as B, type CanonicalUrlOptions as C, type NextjsSitemapEntry as N, type SitemapChangeFreq as S, type SitemapData as a, type SitemapEntry as b, type SitemapOptions as c, createBlogSitemapRoute as d, createDynamicBlogSitemap as e, generateCanonicalUrl as f, generateBlogSitemapEntries as g, generateCanonicalUrlFromSlug as h, generateSitemap as i, generateSitemapIndex as j, getBaseUrl as k, isValidCanonicalUrl as l, normalizeSlug as m, normalizeDomain as n, sitemapToXml as s, updateArticleCanonicalUrl as u, validateSitemap as v };
428
+ export { createBlogSitemapRoute as d, createDynamicBlogSitemap as e, generateCanonicalUrl as f, generateBlogSitemapEntries as g, generateCanonicalUrlFromSlug as h, generateSitemap as i, generateSitemapIndex as j, getBaseUrl as k, isValidCanonicalUrl as l, normalizeSlug as m, normalizeDomain as n, sitemapToXml as s, updateArticleCanonicalUrl as u, validateSitemap as v };
429
+ export type { BlogSitemapConfig as B, CanonicalUrlOptions as C, NextjsSitemapEntry as N, SitemapChangeFreq as S, SitemapData as a, SitemapEntry as b, SitemapOptions as c };
@@ -1,2 +1,2 @@
1
- import './index-Dr8HaKGm.mjs';
2
- export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, i as generateSitemap, j as generateSitemapIndex, s as sitemapToXml, v as validateSitemap } from './sitemap-Dbl4CUGI.mjs';
1
+ import './index-DsXjuPn4.mjs';
2
+ export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, i as generateSitemap, j as generateSitemapIndex, s as sitemapToXml, v as validateSitemap } from './sitemap-Dy7Q4ATM.mjs';
package/dist/sitemap.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import './index-Dr8HaKGm.js';
2
- export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, i as generateSitemap, j as generateSitemapIndex, s as sitemapToXml, v as validateSitemap } from './sitemap-BmCh8BpN.js';
1
+ import './index-DsXjuPn4.js';
2
+ export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, i as generateSitemap, j as generateSitemapIndex, s as sitemapToXml, v as validateSitemap } from './sitemap-B64QGT4l.js';
package/dist/sitemap.js CHANGED
@@ -1,6 +1,6 @@
1
- 'use strict';function T(e){let t=new Map;for(let r of e)r.author?.slug&&t.set(r.author.slug,q(t.get(r.author.slug),r.author));return Array.from(t.values()).sort((r,i)=>r.name.localeCompare(i.name))}function q(e,t){return e?{...e,bio:e.bio??t.bio,avatarUrl:e.avatarUrl??t.avatarUrl,pronouns:e.pronouns??t.pronouns,socialLinks:e.socialLinks??t.socialLinks,toneAdjectives:e.toneAdjectives.length>0?e.toneAdjectives:t.toneAdjectives}:t}function w(e,t=true){let r=e.trim();return r=r.replace(/\/+$/,""),/^https?:\/\//.exec(r)||(r=`${t?"https":"http"}://${r}`),t&&r.startsWith("http://")&&(r=r.replace("http://","https://")),r}function F(e){let t=e.trim();if(!t)throw new Error("Slug cannot be empty");if(!/^[a-z0-9-]+$/.test(t))throw new Error("Slug can only contain lowercase letters, numbers, and hyphens");let i=t.replace(/-+/g,"-").replace(/^-+|-+$/g,"");if(!i)throw new Error("Slug cannot consist only of hyphens");return i}function O(e,t={}){let{forceHttps:r=true,removeTrailingSlash:i=true,domain:s=e.site.domain,pathPrefix:n="/blog"}=t;if(!s)throw new Error("Domain is required for canonical URL generation");if(!e.slug)throw new Error("Article slug is required for canonical URL generation");let l=w(s,r),u=F(e.slug),c=n.replace(/^(?!\/)/,"/").replace(/\/+$/,""),a=`${l}${c}/${u}`;return i&&(a=a.replace(/\/+$/,"")),a}function _(e){let t=new Map;for(let r of e)for(let i of r.topics??[])t.has(i.slug)||t.set(i.slug,i);return Array.from(t.values()).sort((r,i)=>r.name.localeCompare(i.name))}function M(e="/blog"){let t=e.trim();return !t||t==="/"?"":t.replace(/^(?!\/)/,"/").replace(/\/+$/,"")}function b(e,t){let r=M(e),i=t?.replace(/^\/+/,"").replace(/\/+$/,"");return i?`${r}/${i}`.replace(/\/+/g,"/"):r||"/"}function v(e,t){return b(e,`authors/${t}`)}async function U(e,t,r=[],i={}){let{includeAuthorPages:s=true,includeTopicPages:n=true,includePaginationPages:l=true,articlesPerPage:u=10,maxEntries:c=5e4,changeFrequency:a={},priority:g={}}=i,o=[],m=w(i.canonical?.domain??e.domain,i.canonical?.forceHttps??true),f=i.canonical?.pathPrefix??"/blog",R=r.length>0?r:T(t),y=_([...t]);if(o.push({url:`${m}${f}`,lastModified:P(t),changeFrequency:a.homePage??"daily",priority:g.homePage??1}),t.forEach(p=>{if(o.length>=c)return;let d=O(p,i.canonical);o.push({url:d,lastModified:p.updatedAt,changeFrequency:a.articles??"monthly",priority:g.articles??.8});}),n&&y.length>0&&(o.length<c&&o.push({url:`${m}${b(f,"topics")}`,lastModified:P(t),changeFrequency:a.topicPages??"weekly",priority:g.topicPages??.6}),y.forEach(p=>{if(o.length>=c)return;let d=t.filter(S=>(S.topics??[]).some(h=>h.slug===p.slug));o.push({url:`${m}${b(f,`topics/${p.slug}`)}`,lastModified:P(d),changeFrequency:a.topicPages??"weekly",priority:g.topicPages??.6});})),s&&R.length>0&&(o.length<c&&o.push({url:`${m}${b(f,"authors")}`,lastModified:P(t),changeFrequency:a.authorPages??"weekly",priority:g.authorPages??.6}),R.forEach(p=>{if(o.length>=c)return;let d=`${m}${v(f,p.slug)}`,S=t.filter(A=>A.author?.id===p.id),h=P(S);o.push({url:d,lastModified:h,changeFrequency:a.authorPages??"weekly",priority:g.authorPages??.6});})),l&&t.length>u){let p=Math.ceil(t.length/u);for(let d=2;d<=p&&!(o.length>=c);d++)o.push({url:`${m}${f}?page=${d}`,lastModified:P(t),changeFrequency:a.paginationPages??"daily",priority:g.paginationPages??.5});}return o}function X(e,t,r=[],i={}){let{includeAuthorPages:s=true,includeTopicPages:n=true,includePaginationPages:l=true,articlesPerPage:u=10,maxEntries:c=5e4,changeFrequency:a={},priority:g={}}=i,o=[],m=w(i.canonical?.domain??e.domain,i.canonical?.forceHttps??true),f=i.canonical?.pathPrefix??"/blog",R=new Date().toISOString(),y=r.length>0?r:T(t),p=_([...t]),d=1;if(d+=t.length,n&&p.length>0&&(d+=p.length+1),s&&(d+=y.length>0?y.length+1:0),l&&t.length>u){let h=Math.ceil(t.length/u);d+=h-1;}let S=d>c;if(o.push({loc:`${m}${f}`,lastmod:P(t),changefreq:a.homePage??"daily",priority:g.homePage??1}),t.forEach(h=>{if(o.length>=c)return;let A=O(h,i.canonical);o.push({loc:A,lastmod:h.updatedAt,changefreq:a.articles??"monthly",priority:g.articles??.8});}),n&&p.length>0&&(o.length<c&&o.push({loc:`${m}${b(f,"topics")}`,lastmod:P(t),changefreq:a.topicPages??"weekly",priority:g.topicPages??.6}),p.forEach(h=>{if(o.length>=c)return;let A=t.filter($=>($.topics??[]).some(E=>E.slug===h.slug));o.push({loc:`${m}${b(f,`topics/${h.slug}`)}`,lastmod:P(A),changefreq:a.topicPages??"weekly",priority:g.topicPages??.6});})),s&&y.length>0&&(o.length<c&&o.push({loc:`${m}${b(f,"authors")}`,lastmod:P(t),changefreq:a.authorPages??"weekly",priority:g.authorPages??.6}),y.forEach(h=>{if(o.length>=c)return;let A=`${m}${v(f,h.slug)}`,$=t.filter(B=>B.author?.id===h.id),E=P($);o.push({loc:A,lastmod:E,changefreq:a.authorPages??"weekly",priority:g.authorPages??.6});})),l&&t.length>u){let h=Math.ceil(t.length/u);for(let A=2;A<=h&&!(o.length>=c);A++)o.push({loc:`${m}${f}?page=${A}`,lastmod:P(t),changefreq:a.paginationPages??"daily",priority:g.paginationPages??.5});}return {entries:o,totalEntries:o.length,truncated:S,generatedAt:R,baseUrl:m}}function L(e){let t='<?xml version="1.0" encoding="UTF-8"?>',r='<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',i="</urlset>",s=e.entries.map(n=>{let l=[];return l.push(" <url>"),l.push(` <loc>${x(n.loc)}</loc>`),n.lastmod&&l.push(` <lastmod>${x(n.lastmod)}</lastmod>`),n.changefreq&&l.push(` <changefreq>${x(n.changefreq)}</changefreq>`),n.priority!==void 0&&l.push(` <priority>${n.priority.toFixed(1)}</priority>`),l.push(" </url>"),l.join(`
2
- `)});return [t,r,...s,i].join(`
3
- `)}function J(e,t){let r='<?xml version="1.0" encoding="UTF-8"?>',i='<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',s="</sitemapindex>",n=e.map(l=>{let u=[];return u.push(" <sitemap>"),u.push(` <loc>${x(l.url)}</loc>`),l.lastmod&&u.push(` <lastmod>${x(l.lastmod)}</lastmod>`),u.push(" </sitemap>"),u.join(`
4
- `)});return [r,i,...n,s].join(`
5
- `)}function Q(e){let t=[],r=[];e.entries.length===0?t.push("Sitemap must contain at least one URL"):e.entries.length>5e4&&t.push("Sitemap contains more than 50,000 URLs (Google limit)"),e.truncated&&r.push("Sitemap was truncated due to size limits"),e.entries.forEach((s,n)=>{try{new URL(s.loc);}catch{t.push(`Invalid URL at entry ${n+1}: ${s.loc}`);}s.priority!==void 0&&(s.priority<0||s.priority>1)&&t.push(`Invalid priority at entry ${n+1}: must be between 0.0 and 1.0`),s.lastmod&&!C(s.lastmod)&&t.push(`Invalid lastmod date at entry ${n+1}: ${s.lastmod}`),s.loc.length>2048&&r.push(`URL at entry ${n+1} exceeds 2048 character limit`);});let i=new Map;return e.entries.forEach(s=>{let n=i.get(s.loc)??0;i.set(s.loc,n+1);}),i.forEach((s,n)=>{s>1&&t.push(`Duplicate URL found: ${n} (appears ${s} times)`);}),{valid:t.length===0,errors:t,warnings:r}}function P(e){return e.length===0?new Date().toISOString():e.reduce((r,i)=>{let s=new Date(i.updatedAt);return s>r?s:r},new Date(e[0].updatedAt)).toISOString()}function Y(e,t,r=[],i={}){return async function(){let l=(await U(e,t,r,i)).map(a=>({loc:a.url,lastmod:typeof a.lastModified=="string"?a.lastModified:a.lastModified?.toISOString(),changefreq:a.changeFrequency,priority:a.priority})),u={entries:l,totalEntries:l.length,generatedAt:new Date().toISOString(),baseUrl:w(i.canonical?.domain??e.domain,i.canonical?.forceHttps??true)},c=L(u);return new Response(c,{headers:{"Content-Type":"application/xml","Cache-Control":"public, max-age=3600, s-maxage=3600"}})}}function K(e){return async function(){let r=[...e.staticRoutes??[],...e.getStaticRoutes?await e.getStaticRoutes():[]],i=await e.getSite(),s=await e.getArticles(),n=e.getAuthors?await e.getAuthors():[];return [...r,...await U(i,s,n,e.options)]}}function x(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"};return e.replace(/[&<>"']/g,r=>t[r]??r)}function C(e){try{let t=new Date(e),r=t.toISOString(),i=e.endsWith("Z")&&!e.includes(".")?e.replace("Z",".000Z"):e;return r===i&&!isNaN(t.getTime())}catch{return false}}exports.createBlogSitemapRoute=Y;exports.createDynamicBlogSitemap=K;exports.generateBlogSitemapEntries=U;exports.generateSitemap=X;exports.generateSitemapIndex=J;exports.sitemapToXml=L;exports.validateSitemap=Q;//# sourceMappingURL=sitemap.js.map
1
+ 'use strict';function v(t){let e=new Map;for(let r of t)r.author?.slug&&e.set(r.author.slug,F(e.get(r.author.slug),r.author));return Array.from(e.values()).sort((r,i)=>r.name.localeCompare(i.name))}function F(t,e){return t?{...t,bio:t.bio??e.bio,avatarUrl:t.avatarUrl??e.avatarUrl,pronouns:t.pronouns??e.pronouns,socialLinks:t.socialLinks??e.socialLinks,toneAdjectives:t.toneAdjectives.length>0?t.toneAdjectives:e.toneAdjectives}:e}function w(t,e=true){let r=t.trim();return r=r.replace(/\/+$/,""),/^https?:\/\//.exec(r)||(r=`${e?"https":"http"}://${r}`),e&&r.startsWith("http://")&&(r=r.replace("http://","https://")),r}function M(t){let e=t.trim();if(!e)throw new Error("Slug cannot be empty");if(!/^[a-z0-9-]+$/.test(e))throw new Error("Slug can only contain lowercase letters, numbers, and hyphens");let i=e.replace(/-+/g,"-").replace(/^-+|-+$/g,"");if(!i)throw new Error("Slug cannot consist only of hyphens");return i}function T(t,e={}){let{forceHttps:r=true,removeTrailingSlash:i=true,domain:n=t.site.domain,pathPrefix:o="/blog"}=e;if(!n)throw new Error("Domain is required for canonical URL generation");if(!t.slug)throw new Error("Article slug is required for canonical URL generation");let u=w(n,r),l=M(t.slug),c=o.replace(/^(?!\/)/,"/").replace(/\/+$/,""),a=`${u}${c}/${l}`;return i&&(a=a.replace(/\/+$/,"")),a}function O(t){let e=new Map;for(let r of t)r.series&&(!e.has(r.series.slug)||r.series.articles.length>(e.get(r.series.slug)?.articles.length??0))&&e.set(r.series.slug,r.series);return Array.from(e.values()).sort((r,i)=>r.title.localeCompare(i.title))}function _(t){let e=new Map;for(let r of t)for(let i of r.topics??[])e.has(i.slug)||e.set(i.slug,i);return Array.from(e.values()).sort((r,i)=>r.name.localeCompare(i.name))}function L(t="/blog"){let e=t.trim();return !e||e==="/"?"":e.replace(/^(?!\/)/,"/").replace(/\/+$/,"")}function P(t,e){let r=L(t),i=e?.replace(/^\/+/,"").replace(/\/+$/,"");return i?`${r}/${i}`.replace(/\/+/g,"/"):r||"/"}function U(t,e){return P(t,`authors/${e}`)}function B(t,e){return P(t,`series/${e}`)}async function q(t,e,r=[],i={}){let{includeAuthorPages:n=true,includeTopicPages:o=true,includeSeriesPages:u=true,maxEntries:l=5e4,changeFrequency:c={},priority:a={}}=i,s=[],h=w(i.canonical?.domain??t.domain,i.canonical?.forceHttps??true),p=i.canonical?.pathPrefix??"/blog",$=r.length>0?r:v(e),b=_([...e]),y=O([...e]);return s.push({url:`${h}${p}`,lastModified:m(e),changeFrequency:c.homePage??"daily",priority:a.homePage??1}),e.forEach(g=>{if(s.length>=l)return;let f=T(g,i.canonical);s.push({url:f,lastModified:g.updatedAt,changeFrequency:c.articles??"monthly",priority:a.articles??.8});}),o&&b.length>0&&(s.length<l&&s.push({url:`${h}${P(p,"topics")}`,lastModified:m(e),changeFrequency:c.topicPages??"weekly",priority:a.topicPages??.6}),b.forEach(g=>{if(s.length>=l)return;let f=e.filter(S=>(S.topics??[]).some(d=>d.slug===g.slug));s.push({url:`${h}${P(p,`topics/${g.slug}`)}`,lastModified:m(f),changeFrequency:c.topicPages??"weekly",priority:a.topicPages??.6});})),u&&y.length>0&&(s.length<l&&s.push({url:`${h}${P(p,"series")}`,lastModified:m(e),changeFrequency:c.seriesPages??"weekly",priority:a.seriesPages??.6}),y.forEach(g=>{if(s.length>=l)return;let f=e.filter(S=>S.series?.slug===g.slug);s.push({url:`${h}${B(p,g.slug)}`,lastModified:m(f),changeFrequency:c.seriesPages??"weekly",priority:a.seriesPages??.6});})),n&&$.length>0&&(s.length<l&&s.push({url:`${h}${P(p,"authors")}`,lastModified:m(e),changeFrequency:c.authorPages??"weekly",priority:a.authorPages??.6}),$.forEach(g=>{if(s.length>=l)return;let f=`${h}${U(p,g.slug)}`,S=e.filter(A=>A.author?.id===g.id),d=m(S);s.push({url:f,lastModified:d,changeFrequency:c.authorPages??"weekly",priority:a.authorPages??.6});})),s}function K(t,e,r=[],i={}){let{includeAuthorPages:n=true,includeTopicPages:o=true,includeSeriesPages:u=true,maxEntries:l=5e4,changeFrequency:c={},priority:a={}}=i,s=[],h=w(i.canonical?.domain??t.domain,i.canonical?.forceHttps??true),p=i.canonical?.pathPrefix??"/blog",$=new Date().toISOString(),b=r.length>0?r:v(e),y=_([...e]),g=O([...e]),f=1;f+=e.length,o&&y.length>0&&(f+=y.length+1),u&&g.length>0&&(f+=g.length+1),n&&(f+=b.length>0?b.length+1:0);let S=f>l;return s.push({loc:`${h}${p}`,lastmod:m(e),changefreq:c.homePage??"daily",priority:a.homePage??1}),e.forEach(d=>{if(s.length>=l)return;let A=T(d,i.canonical);s.push({loc:A,lastmod:d.updatedAt,changefreq:c.articles??"monthly",priority:a.articles??.8});}),o&&y.length>0&&(s.length<l&&s.push({loc:`${h}${P(p,"topics")}`,lastmod:m(e),changefreq:c.topicPages??"weekly",priority:a.topicPages??.6}),y.forEach(d=>{if(s.length>=l)return;let A=e.filter(x=>(x.topics??[]).some(E=>E.slug===d.slug));s.push({loc:`${h}${P(p,`topics/${d.slug}`)}`,lastmod:m(A),changefreq:c.topicPages??"weekly",priority:a.topicPages??.6});})),u&&g.length>0&&(s.length<l&&s.push({loc:`${h}${P(p,"series")}`,lastmod:m(e),changefreq:c.seriesPages??"weekly",priority:a.seriesPages??.6}),g.forEach(d=>{if(s.length>=l)return;let A=e.filter(x=>x.series?.slug===d.slug);s.push({loc:`${h}${B(p,d.slug)}`,lastmod:m(A),changefreq:c.seriesPages??"weekly",priority:a.seriesPages??.6});})),n&&b.length>0&&(s.length<l&&s.push({loc:`${h}${P(p,"authors")}`,lastmod:m(e),changefreq:c.authorPages??"weekly",priority:a.authorPages??.6}),b.forEach(d=>{if(s.length>=l)return;let A=`${h}${U(p,d.slug)}`,x=e.filter(C=>C.author?.id===d.id),E=m(x);s.push({loc:A,lastmod:E,changefreq:c.authorPages??"weekly",priority:a.authorPages??.6});})),{entries:s,totalEntries:s.length,truncated:S,generatedAt:$,baseUrl:h}}function k(t){let e='<?xml version="1.0" encoding="UTF-8"?>',r='<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',i="</urlset>",n=t.entries.map(o=>{let u=[];return u.push(" <url>"),u.push(` <loc>${R(o.loc)}</loc>`),o.lastmod&&u.push(` <lastmod>${R(o.lastmod)}</lastmod>`),o.changefreq&&u.push(` <changefreq>${R(o.changefreq)}</changefreq>`),o.priority!==void 0&&u.push(` <priority>${o.priority.toFixed(1)}</priority>`),u.push(" </url>"),u.join(`
2
+ `)});return [e,r,...n,i].join(`
3
+ `)}function ee(t,e){let r='<?xml version="1.0" encoding="UTF-8"?>',i='<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',n="</sitemapindex>",o=t.map(u=>{let l=[];return l.push(" <sitemap>"),l.push(` <loc>${R(u.url)}</loc>`),u.lastmod&&l.push(` <lastmod>${R(u.lastmod)}</lastmod>`),l.push(" </sitemap>"),l.join(`
4
+ `)});return [r,i,...o,n].join(`
5
+ `)}function te(t){let e=[],r=[];t.entries.length===0?e.push("Sitemap must contain at least one URL"):t.entries.length>5e4&&e.push("Sitemap contains more than 50,000 URLs (Google limit)"),t.truncated&&r.push("Sitemap was truncated due to size limits"),t.entries.forEach((n,o)=>{try{new URL(n.loc);}catch{e.push(`Invalid URL at entry ${o+1}: ${n.loc}`);}n.priority!==void 0&&(n.priority<0||n.priority>1)&&e.push(`Invalid priority at entry ${o+1}: must be between 0.0 and 1.0`),n.lastmod&&!D(n.lastmod)&&e.push(`Invalid lastmod date at entry ${o+1}: ${n.lastmod}`),n.loc.length>2048&&r.push(`URL at entry ${o+1} exceeds 2048 character limit`);});let i=new Map;return t.entries.forEach(n=>{let o=i.get(n.loc)??0;i.set(n.loc,o+1);}),i.forEach((n,o)=>{n>1&&e.push(`Duplicate URL found: ${o} (appears ${n} times)`);}),{valid:e.length===0,errors:e,warnings:r}}function m(t){return t.length===0?new Date().toISOString():t.reduce((r,i)=>{let n=new Date(i.updatedAt);return n>r?n:r},new Date(t[0].updatedAt)).toISOString()}function re(t,e,r=[],i={}){return async function(){let u=(await q(t,e,r,i)).map(a=>({loc:a.url,lastmod:typeof a.lastModified=="string"?a.lastModified:a.lastModified?.toISOString(),changefreq:a.changeFrequency,priority:a.priority})),l={entries:u,totalEntries:u.length,generatedAt:new Date().toISOString(),baseUrl:w(i.canonical?.domain??t.domain,i.canonical?.forceHttps??true)},c=k(l);return new Response(c,{headers:{"Content-Type":"application/xml","Cache-Control":"public, max-age=3600, s-maxage=3600"}})}}function ie(t){return async function(){let r=[...t.staticRoutes??[],...t.getStaticRoutes?await t.getStaticRoutes():[]],i=await t.getSite(),n=await t.getArticles(),o=t.getAuthors?await t.getAuthors():[];return [...r,...await q(i,n,o,t.options)]}}function R(t){let e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"};return t.replace(/[&<>"']/g,r=>e[r]??r)}function D(t){try{let e=new Date(t),r=e.toISOString(),i=t.endsWith("Z")&&!t.includes(".")?t.replace("Z",".000Z"):t;return r===i&&!isNaN(e.getTime())}catch{return false}}exports.createBlogSitemapRoute=re;exports.createDynamicBlogSitemap=ie;exports.generateBlogSitemapEntries=q;exports.generateSitemap=K;exports.generateSitemapIndex=ee;exports.sitemapToXml=k;exports.validateSitemap=te;//# sourceMappingURL=sitemap.js.map
6
6
  //# sourceMappingURL=sitemap.js.map