@xexr/blog-platform 1.1.3 → 1.1.5

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 (38) hide show
  1. package/dist/app/blog/[slug]/page.tsx +11 -4
  2. package/dist/app/blog/authors/[slug]/page.tsx +1 -1
  3. package/dist/app/blog/page.test.ts +20 -0
  4. package/dist/app/blog/page.tsx +14 -13
  5. package/dist/app/blog/series/[slug]/page.d.ts +28 -0
  6. package/dist/app/blog/series/[slug]/page.tsx +39 -0
  7. package/dist/app/blog/series/page.d.ts +24 -0
  8. package/dist/app/blog/series/page.tsx +28 -0
  9. package/dist/components/SeriesArchivePages.tsx +212 -0
  10. package/dist/components/SeriesNavigation.tsx +117 -0
  11. package/dist/components/TopicArchivePages.test.ts +22 -0
  12. package/dist/components/TopicArchivePages.tsx +1 -1
  13. package/dist/{index-Dr8HaKGm.d.mts → index-CKWrb9a4.d.mts} +43 -1
  14. package/dist/{index-Dr8HaKGm.d.ts → index-CKWrb9a4.d.ts} +43 -1
  15. package/dist/index.d.mts +85 -5
  16. package/dist/index.d.ts +85 -5
  17. package/dist/index.js +12 -12
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +12 -12
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/lib/related-articles.d.mts +1 -1
  22. package/dist/lib/related-articles.d.ts +1 -1
  23. package/dist/lib/series.ts +55 -0
  24. package/dist/lib/sitemap.ts +76 -4
  25. package/dist/lib/storage/drizzle.ts +9 -0
  26. package/dist/lib/urls.ts +7 -0
  27. package/dist/{sitemap-BmCh8BpN.d.ts → sitemap-BDT3d496.d.ts} +7 -1
  28. package/dist/{sitemap-Dbl4CUGI.d.mts → sitemap-D3rS0iAF.d.mts} +7 -1
  29. package/dist/sitemap.d.mts +2 -2
  30. package/dist/sitemap.d.ts +2 -2
  31. package/dist/sitemap.js +5 -5
  32. package/dist/sitemap.js.map +1 -1
  33. package/dist/sitemap.mjs +5 -5
  34. package/dist/sitemap.mjs.map +1 -1
  35. package/dist/types/contracts.ts +58 -0
  36. package/dist/types/index.d.mts +1 -1
  37. package/dist/types/index.d.ts +1 -1
  38. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { P as PublishedTopic, a as PublishedArticle } from '../index-Dr8HaKGm.mjs';
1
+ import { P as PublishedTopic, a as PublishedArticle } from '../index-CKWrb9a4.mjs';
2
2
 
3
3
  interface RelatedArticleCandidate {
4
4
  readonly id: string;
@@ -1,4 +1,4 @@
1
- import { P as PublishedTopic, a as PublishedArticle } from '../index-Dr8HaKGm.js';
1
+ import { P as PublishedTopic, a as PublishedArticle } from '../index-CKWrb9a4.js';
2
2
 
3
3
  interface RelatedArticleCandidate {
4
4
  readonly id: string;
@@ -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,6 +53,9 @@ export interface SitemapOptions {
52
53
  /** Whether to include topic pages in sitemap */
53
54
  includeTopicPages?: boolean;
54
55
 
56
+ /** Whether to include series pages in sitemap */
57
+ includeSeriesPages?: boolean;
58
+
55
59
  /** Whether to include pagination pages in sitemap */
56
60
  includePaginationPages?: boolean;
57
61
 
@@ -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,6 +212,7 @@ export async function generateBlogSitemapEntries(
204
212
  const {
205
213
  includeAuthorPages = true,
206
214
  includeTopicPages = true,
215
+ includeSeriesPages = true,
207
216
  includePaginationPages = true,
208
217
  articlesPerPage = 10,
209
218
  maxEntries = 50000,
@@ -221,6 +230,7 @@ export async function generateBlogSitemapEntries(
221
230
  const sitemapAuthors =
222
231
  authors.length > 0 ? authors : getAuthorsFromArticles(articles);
223
232
  const sitemapTopics = getAllTopics([...articles]);
233
+ const sitemapSeries = getAllSeries([...articles]);
224
234
 
225
235
  // Add blog home page
226
236
  entries.push({
@@ -257,7 +267,9 @@ export async function generateBlogSitemapEntries(
257
267
  if (entries.length >= maxEntries) return;
258
268
 
259
269
  const topicArticles = articles.filter((article) =>
260
- (article.topics ?? []).some((candidate) => candidate.slug === topic.slug),
270
+ (article.topics ?? []).some(
271
+ (candidate) => candidate.slug === topic.slug,
272
+ ),
261
273
  );
262
274
 
263
275
  entries.push({
@@ -269,6 +281,32 @@ export async function generateBlogSitemapEntries(
269
281
  });
270
282
  }
271
283
 
284
+ if (includeSeriesPages && sitemapSeries.length > 0) {
285
+ if (entries.length < maxEntries) {
286
+ entries.push({
287
+ url: `${baseUrl}${buildBlogPath(pathPrefix, "series")}`,
288
+ lastModified: getLatestModificationDate(articles),
289
+ changeFrequency: changeFrequency.seriesPages ?? "weekly",
290
+ priority: priority.seriesPages ?? 0.6,
291
+ });
292
+ }
293
+
294
+ sitemapSeries.forEach((series) => {
295
+ if (entries.length >= maxEntries) return;
296
+
297
+ const seriesArticles = articles.filter(
298
+ (article) => article.series?.slug === series.slug,
299
+ );
300
+
301
+ entries.push({
302
+ url: `${baseUrl}${buildSeriesPath(pathPrefix, series.slug)}`,
303
+ lastModified: getLatestModificationDate(seriesArticles),
304
+ changeFrequency: changeFrequency.seriesPages ?? "weekly",
305
+ priority: priority.seriesPages ?? 0.6,
306
+ });
307
+ });
308
+ }
309
+
272
310
  // Add author pages if enabled
273
311
  if (includeAuthorPages && sitemapAuthors.length > 0) {
274
312
  if (entries.length < maxEntries) {
@@ -338,6 +376,7 @@ export function generateSitemap(
338
376
  const {
339
377
  includeAuthorPages = true,
340
378
  includeTopicPages = true,
379
+ includeSeriesPages = true,
341
380
  includePaginationPages = true,
342
381
  articlesPerPage = 10,
343
382
  maxEntries = 50000,
@@ -356,6 +395,7 @@ export function generateSitemap(
356
395
  const sitemapAuthors =
357
396
  authors.length > 0 ? authors : getAuthorsFromArticles(articles);
358
397
  const sitemapTopics = getAllTopics([...articles]);
398
+ const sitemapSeries = getAllSeries([...articles]);
359
399
 
360
400
  // Calculate total potential entries to determine if truncation will occur
361
401
  let potentialEntries = 1; // Home page
@@ -363,8 +403,12 @@ export function generateSitemap(
363
403
  if (includeTopicPages && sitemapTopics.length > 0) {
364
404
  potentialEntries += sitemapTopics.length + 1; // Topic index + topic pages
365
405
  }
406
+ if (includeSeriesPages && sitemapSeries.length > 0) {
407
+ potentialEntries += sitemapSeries.length + 1; // Series index + series pages
408
+ }
366
409
  if (includeAuthorPages) {
367
- potentialEntries += sitemapAuthors.length > 0 ? sitemapAuthors.length + 1 : 0; // Authors index + author pages
410
+ potentialEntries +=
411
+ sitemapAuthors.length > 0 ? sitemapAuthors.length + 1 : 0; // Authors index + author pages
368
412
  }
369
413
  if (includePaginationPages && articles.length > articlesPerPage) {
370
414
  const totalPages = Math.ceil(articles.length / articlesPerPage);
@@ -408,7 +452,9 @@ export function generateSitemap(
408
452
  if (entries.length >= maxEntries) return;
409
453
 
410
454
  const topicArticles = articles.filter((article) =>
411
- (article.topics ?? []).some((candidate) => candidate.slug === topic.slug),
455
+ (article.topics ?? []).some(
456
+ (candidate) => candidate.slug === topic.slug,
457
+ ),
412
458
  );
413
459
 
414
460
  entries.push({
@@ -420,6 +466,32 @@ export function generateSitemap(
420
466
  });
421
467
  }
422
468
 
469
+ if (includeSeriesPages && sitemapSeries.length > 0) {
470
+ if (entries.length < maxEntries) {
471
+ entries.push({
472
+ loc: `${baseUrl}${buildBlogPath(pathPrefix, "series")}`,
473
+ lastmod: getLatestModificationDate(articles),
474
+ changefreq: changeFrequency.seriesPages ?? "weekly",
475
+ priority: priority.seriesPages ?? 0.6,
476
+ });
477
+ }
478
+
479
+ sitemapSeries.forEach((series) => {
480
+ if (entries.length >= maxEntries) return;
481
+
482
+ const seriesArticles = articles.filter(
483
+ (article) => article.series?.slug === series.slug,
484
+ );
485
+
486
+ entries.push({
487
+ loc: `${baseUrl}${buildSeriesPath(pathPrefix, series.slug)}`,
488
+ lastmod: getLatestModificationDate(seriesArticles),
489
+ changefreq: changeFrequency.seriesPages ?? "weekly",
490
+ priority: priority.seriesPages ?? 0.6,
491
+ });
492
+ });
493
+ }
494
+
423
495
  // Add author pages if enabled
424
496
  if (includeAuthorPages && sitemapAuthors.length > 0) {
425
497
  if (entries.length < maxEntries) {
@@ -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;
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-CKWrb9a4.js';
2
2
 
3
3
  /**
4
4
  * SEO utilities for canonical URL generation and validation.
@@ -171,6 +171,8 @@ interface SitemapOptions {
171
171
  includeAuthorPages?: boolean;
172
172
  /** Whether to include topic pages in sitemap */
173
173
  includeTopicPages?: boolean;
174
+ /** Whether to include series pages in sitemap */
175
+ includeSeriesPages?: boolean;
174
176
  /** Whether to include pagination pages in sitemap */
175
177
  includePaginationPages?: boolean;
176
178
  /** Number of articles per page for pagination calculation */
@@ -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
  };
@@ -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-CKWrb9a4.mjs';
2
2
 
3
3
  /**
4
4
  * SEO utilities for canonical URL generation and validation.
@@ -171,6 +171,8 @@ interface SitemapOptions {
171
171
  includeAuthorPages?: boolean;
172
172
  /** Whether to include topic pages in sitemap */
173
173
  includeTopicPages?: boolean;
174
+ /** Whether to include series pages in sitemap */
175
+ includeSeriesPages?: boolean;
174
176
  /** Whether to include pagination pages in sitemap */
175
177
  includePaginationPages?: boolean;
176
178
  /** Number of articles per page for pagination calculation */
@@ -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
  };
@@ -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-CKWrb9a4.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-D3rS0iAF.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-CKWrb9a4.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-BDT3d496.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 O(t){let e=new Map;for(let r of t)r.author?.slug&&e.set(r.author.slug,L(e.get(r.author.slug),r.author));return Array.from(e.values()).sort((r,i)=>r.name.localeCompare(i.name))}function L(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 R(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 k(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,e={}){let{forceHttps:r=true,removeTrailingSlash:i=true,domain:n=t.site.domain,pathPrefix:a="/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 l=R(n,r),P=k(t.slug),b=a.replace(/^(?!\/)/,"/").replace(/\/+$/,""),o=`${l}${b}/${P}`;return i&&(o=o.replace(/\/+$/,"")),o}function U(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 q(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 D(t="/blog"){let e=t.trim();return !e||e==="/"?"":e.replace(/^(?!\/)/,"/").replace(/\/+$/,"")}function y(t,e){let r=D(t),i=e?.replace(/^\/+/,"").replace(/\/+$/,"");return i?`${r}/${i}`.replace(/\/+/g,"/"):r||"/"}function B(t,e){return y(t,`authors/${e}`)}function F(t,e){return y(t,`series/${e}`)}async function C(t,e,r=[],i={}){let{includeAuthorPages:n=true,includeTopicPages:a=true,includeSeriesPages:l=true,includePaginationPages:P=true,articlesPerPage:b=10,maxEntries:o=5e4,changeFrequency:u={},priority:c={}}=i,s=[],h=R(i.canonical?.domain??t.domain,i.canonical?.forceHttps??true),m=i.canonical?.pathPrefix??"/blog",v=r.length>0?r:O(e),S=q([...e]),x=U([...e]);if(s.push({url:`${h}${m}`,lastModified:f(e),changeFrequency:u.homePage??"daily",priority:c.homePage??1}),e.forEach(p=>{if(s.length>=o)return;let d=_(p,i.canonical);s.push({url:d,lastModified:p.updatedAt,changeFrequency:u.articles??"monthly",priority:c.articles??.8});}),a&&S.length>0&&(s.length<o&&s.push({url:`${h}${y(m,"topics")}`,lastModified:f(e),changeFrequency:u.topicPages??"weekly",priority:c.topicPages??.6}),S.forEach(p=>{if(s.length>=o)return;let d=e.filter(w=>(w.topics??[]).some(g=>g.slug===p.slug));s.push({url:`${h}${y(m,`topics/${p.slug}`)}`,lastModified:f(d),changeFrequency:u.topicPages??"weekly",priority:c.topicPages??.6});})),l&&x.length>0&&(s.length<o&&s.push({url:`${h}${y(m,"series")}`,lastModified:f(e),changeFrequency:u.seriesPages??"weekly",priority:c.seriesPages??.6}),x.forEach(p=>{if(s.length>=o)return;let d=e.filter(w=>w.series?.slug===p.slug);s.push({url:`${h}${F(m,p.slug)}`,lastModified:f(d),changeFrequency:u.seriesPages??"weekly",priority:c.seriesPages??.6});})),n&&v.length>0&&(s.length<o&&s.push({url:`${h}${y(m,"authors")}`,lastModified:f(e),changeFrequency:u.authorPages??"weekly",priority:c.authorPages??.6}),v.forEach(p=>{if(s.length>=o)return;let d=`${h}${B(m,p.slug)}`,w=e.filter(A=>A.author?.id===p.id),g=f(w);s.push({url:d,lastModified:g,changeFrequency:u.authorPages??"weekly",priority:c.authorPages??.6});})),P&&e.length>b){let p=Math.ceil(e.length/b);for(let d=2;d<=p&&!(s.length>=o);d++)s.push({url:`${h}${m}?page=${d}`,lastModified:f(e),changeFrequency:u.paginationPages??"daily",priority:c.paginationPages??.5});}return s}function te(t,e,r=[],i={}){let{includeAuthorPages:n=true,includeTopicPages:a=true,includeSeriesPages:l=true,includePaginationPages:P=true,articlesPerPage:b=10,maxEntries:o=5e4,changeFrequency:u={},priority:c={}}=i,s=[],h=R(i.canonical?.domain??t.domain,i.canonical?.forceHttps??true),m=i.canonical?.pathPrefix??"/blog",v=new Date().toISOString(),S=r.length>0?r:O(e),x=q([...e]),p=U([...e]),d=1;if(d+=e.length,a&&x.length>0&&(d+=x.length+1),l&&p.length>0&&(d+=p.length+1),n&&(d+=S.length>0?S.length+1:0),P&&e.length>b){let g=Math.ceil(e.length/b);d+=g-1;}let w=d>o;if(s.push({loc:`${h}${m}`,lastmod:f(e),changefreq:u.homePage??"daily",priority:c.homePage??1}),e.forEach(g=>{if(s.length>=o)return;let A=_(g,i.canonical);s.push({loc:A,lastmod:g.updatedAt,changefreq:u.articles??"monthly",priority:c.articles??.8});}),a&&x.length>0&&(s.length<o&&s.push({loc:`${h}${y(m,"topics")}`,lastmod:f(e),changefreq:u.topicPages??"weekly",priority:c.topicPages??.6}),x.forEach(g=>{if(s.length>=o)return;let A=e.filter($=>($.topics??[]).some(T=>T.slug===g.slug));s.push({loc:`${h}${y(m,`topics/${g.slug}`)}`,lastmod:f(A),changefreq:u.topicPages??"weekly",priority:c.topicPages??.6});})),l&&p.length>0&&(s.length<o&&s.push({loc:`${h}${y(m,"series")}`,lastmod:f(e),changefreq:u.seriesPages??"weekly",priority:c.seriesPages??.6}),p.forEach(g=>{if(s.length>=o)return;let A=e.filter($=>$.series?.slug===g.slug);s.push({loc:`${h}${F(m,g.slug)}`,lastmod:f(A),changefreq:u.seriesPages??"weekly",priority:c.seriesPages??.6});})),n&&S.length>0&&(s.length<o&&s.push({loc:`${h}${y(m,"authors")}`,lastmod:f(e),changefreq:u.authorPages??"weekly",priority:c.authorPages??.6}),S.forEach(g=>{if(s.length>=o)return;let A=`${h}${B(m,g.slug)}`,$=e.filter(M=>M.author?.id===g.id),T=f($);s.push({loc:A,lastmod:T,changefreq:u.authorPages??"weekly",priority:c.authorPages??.6});})),P&&e.length>b){let g=Math.ceil(e.length/b);for(let A=2;A<=g&&!(s.length>=o);A++)s.push({loc:`${h}${m}?page=${A}`,lastmod:f(e),changefreq:u.paginationPages??"daily",priority:c.paginationPages??.5});}return {entries:s,totalEntries:s.length,truncated:w,generatedAt:v,baseUrl:h}}function G(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(a=>{let l=[];return l.push(" <url>"),l.push(` <loc>${E(a.loc)}</loc>`),a.lastmod&&l.push(` <lastmod>${E(a.lastmod)}</lastmod>`),a.changefreq&&l.push(` <changefreq>${E(a.changefreq)}</changefreq>`),a.priority!==void 0&&l.push(` <priority>${a.priority.toFixed(1)}</priority>`),l.push(" </url>"),l.join(`
2
+ `)});return [e,r,...n,i].join(`
3
+ `)}function re(t,e){let r='<?xml version="1.0" encoding="UTF-8"?>',i='<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',n="</sitemapindex>",a=t.map(l=>{let P=[];return P.push(" <sitemap>"),P.push(` <loc>${E(l.url)}</loc>`),l.lastmod&&P.push(` <lastmod>${E(l.lastmod)}</lastmod>`),P.push(" </sitemap>"),P.join(`
4
+ `)});return [r,i,...a,n].join(`
5
+ `)}function ie(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,a)=>{try{new URL(n.loc);}catch{e.push(`Invalid URL at entry ${a+1}: ${n.loc}`);}n.priority!==void 0&&(n.priority<0||n.priority>1)&&e.push(`Invalid priority at entry ${a+1}: must be between 0.0 and 1.0`),n.lastmod&&!I(n.lastmod)&&e.push(`Invalid lastmod date at entry ${a+1}: ${n.lastmod}`),n.loc.length>2048&&r.push(`URL at entry ${a+1} exceeds 2048 character limit`);});let i=new Map;return t.entries.forEach(n=>{let a=i.get(n.loc)??0;i.set(n.loc,a+1);}),i.forEach((n,a)=>{n>1&&e.push(`Duplicate URL found: ${a} (appears ${n} times)`);}),{valid:e.length===0,errors:e,warnings:r}}function f(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 se(t,e,r=[],i={}){return async function(){let l=(await C(t,e,r,i)).map(o=>({loc:o.url,lastmod:typeof o.lastModified=="string"?o.lastModified:o.lastModified?.toISOString(),changefreq:o.changeFrequency,priority:o.priority})),P={entries:l,totalEntries:l.length,generatedAt:new Date().toISOString(),baseUrl:R(i.canonical?.domain??t.domain,i.canonical?.forceHttps??true)},b=G(P);return new Response(b,{headers:{"Content-Type":"application/xml","Cache-Control":"public, max-age=3600, s-maxage=3600"}})}}function ne(t){return async function(){let r=[...t.staticRoutes??[],...t.getStaticRoutes?await t.getStaticRoutes():[]],i=await t.getSite(),n=await t.getArticles(),a=t.getAuthors?await t.getAuthors():[];return [...r,...await C(i,n,a,t.options)]}}function E(t){let e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"};return t.replace(/[&<>"']/g,r=>e[r]??r)}function I(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=se;exports.createDynamicBlogSitemap=ne;exports.generateBlogSitemapEntries=C;exports.generateSitemap=te;exports.generateSitemapIndex=re;exports.sitemapToXml=G;exports.validateSitemap=ie;//# sourceMappingURL=sitemap.js.map
6
6
  //# sourceMappingURL=sitemap.js.map