@founderhq/next-blog 0.9.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.
package/dist/server.js ADDED
@@ -0,0 +1,681 @@
1
+ import { absoluteUrl, articlePath, articleUrl, authorPath, blogIndexPath, categoryPath, dateToIso, escapeHtml, imageUrl, normalizeRoutePrefix, stripHtml, tagPath, } from "./utils.js";
2
+ function isRecord(value) {
3
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4
+ }
5
+ function readString(value) {
6
+ return typeof value === "string" && value.trim() ? value.trim() : null;
7
+ }
8
+ function readNumber(value) {
9
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
10
+ }
11
+ function hasNoIndex(article) {
12
+ var _a, _b, _c;
13
+ return (_c = (_b = (_a = article.seo) === null || _a === void 0 ? void 0 : _a.robots) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes("noindex")) !== null && _c !== void 0 ? _c : false;
14
+ }
15
+ function articleCanonicalUrl(article, site) {
16
+ var _a, _b;
17
+ return absoluteUrl(site.siteUrl, ((_b = (_a = article.seo) === null || _a === void 0 ? void 0 : _a.canonicalUrl) === null || _b === void 0 ? void 0 : _b.trim()) || articlePath(article, site));
18
+ }
19
+ function hasSameSiteCanonical(article, site) {
20
+ var _a, _b;
21
+ if (!((_b = (_a = article.seo) === null || _a === void 0 ? void 0 : _a.canonicalUrl) === null || _b === void 0 ? void 0 : _b.trim()))
22
+ return true;
23
+ try {
24
+ return (new URL(articleCanonicalUrl(article, site)).origin ===
25
+ new URL(site.siteUrl).origin);
26
+ }
27
+ catch (_c) {
28
+ return false;
29
+ }
30
+ }
31
+ export function isIndexableBlogArticle(article, site) {
32
+ return !hasNoIndex(article) && hasSameSiteCanonical(article, site);
33
+ }
34
+ function stripTags(value) {
35
+ return value
36
+ .replace(/<script[\s\S]*?<\/script>/gi, "")
37
+ .replace(/<style[\s\S]*?<\/style>/gi, "")
38
+ .replace(/<[^>]*>/g, " ")
39
+ .replace(/\s+/g, " ")
40
+ .trim();
41
+ }
42
+ function headingSlug(text, fallback) {
43
+ const slug = text
44
+ .toLowerCase()
45
+ .trim()
46
+ .replace(/[^\w\s-]/g, "")
47
+ .replace(/[\s_]+/g, "-")
48
+ .replace(/^-+|-+$/g, "");
49
+ return slug || `heading-${fallback}`;
50
+ }
51
+ function uniqueHeadingId(text, index, used) {
52
+ var _a;
53
+ const base = headingSlug(text, index);
54
+ const seen = (_a = used.get(base)) !== null && _a !== void 0 ? _a : 0;
55
+ used.set(base, seen + 1);
56
+ return seen === 0 ? base : `${base}-${seen + 1}`;
57
+ }
58
+ export function addHeadingIdsAndExtractToc(html) {
59
+ const toc = [];
60
+ const used = new Map();
61
+ const nextHtml = html.replace(/<h([1-6])([^>]*)>([\s\S]*?)<\/h\1>/gi, (match, rawLevel, rawAttrs, inner) => {
62
+ var _a, _b, _c, _d;
63
+ const level = Number(rawLevel);
64
+ const text = stripTags(inner);
65
+ if (!text || level < 2)
66
+ return match;
67
+ const existingId = (_c = (_b = (_a = /\sid=(["'])(.*?)\1/i.exec(rawAttrs)) === null || _a === void 0 ? void 0 : _a[2]) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : null;
68
+ const id = existingId || uniqueHeadingId(text, toc.length + 1, used);
69
+ toc.push({ id, text, level });
70
+ if (existingId) {
71
+ used.set(existingId, ((_d = used.get(existingId)) !== null && _d !== void 0 ? _d : 0) + 1);
72
+ return match;
73
+ }
74
+ return `<h${level}${rawAttrs} id="${id}">${inner}</h${level}>`;
75
+ });
76
+ return { html: nextHtml, toc };
77
+ }
78
+ function readImage(value) {
79
+ if (!isRecord(value))
80
+ return null;
81
+ const url = readString(value.url);
82
+ const alt = readString(value.alt);
83
+ if (!url || !alt)
84
+ return null;
85
+ return {
86
+ url,
87
+ alt,
88
+ width: readNumber(value.width),
89
+ height: readNumber(value.height),
90
+ aspectRatio: readString(value.aspectRatio),
91
+ caption: readString(value.caption),
92
+ };
93
+ }
94
+ function readAuthor(value) {
95
+ if (!isRecord(value))
96
+ return null;
97
+ const name = readString(value.name);
98
+ if (!name)
99
+ return null;
100
+ return {
101
+ id: typeof value.id === "string" || typeof value.id === "number"
102
+ ? value.id
103
+ : undefined,
104
+ name,
105
+ slug: readString(value.slug),
106
+ title: readString(value.title),
107
+ bio: readString(value.bio),
108
+ avatar: readImage(value.avatar),
109
+ profileUrl: readString(value.profileUrl),
110
+ sameAs: Array.isArray(value.sameAs)
111
+ ? value.sameAs
112
+ .map((item) => (isRecord(item) ? readString(item.url) : readString(item)))
113
+ .filter((item) => Boolean(item))
114
+ : undefined,
115
+ };
116
+ }
117
+ export function normalizePayloadBlogAuthor(doc) {
118
+ var _a;
119
+ return {
120
+ id: typeof doc.id === "string" || typeof doc.id === "number"
121
+ ? doc.id
122
+ : undefined,
123
+ name: (_a = readString(doc.name)) !== null && _a !== void 0 ? _a : "Unknown author",
124
+ slug: readString(doc.slug),
125
+ title: readString(doc.title),
126
+ bio: readString(doc.bio),
127
+ avatar: readImage(doc.avatar),
128
+ profileUrl: readString(doc.profileUrl),
129
+ sameAs: Array.isArray(doc.sameAs)
130
+ ? doc.sameAs
131
+ .map((item) => (isRecord(item) ? readString(item.url) : readString(item)))
132
+ .filter((item) => Boolean(item))
133
+ : undefined,
134
+ };
135
+ }
136
+ function readTaxonomies(value) {
137
+ const items = Array.isArray(value) ? value : value ? [value] : [];
138
+ return items.flatMap((item) => {
139
+ if (!isRecord(item))
140
+ return [];
141
+ const title = readString(item.title);
142
+ const slug = readString(item.slug);
143
+ if (!title || !slug)
144
+ return [];
145
+ return [
146
+ {
147
+ id: typeof item.id === "string" || typeof item.id === "number"
148
+ ? item.id
149
+ : undefined,
150
+ title,
151
+ slug,
152
+ description: readString(item.description),
153
+ },
154
+ ];
155
+ });
156
+ }
157
+ export function normalizePayloadBlogTaxonomy(doc) {
158
+ var _a, _b, _c;
159
+ return {
160
+ id: typeof doc.id === "string" || typeof doc.id === "number"
161
+ ? doc.id
162
+ : undefined,
163
+ title: (_a = readString(doc.title)) !== null && _a !== void 0 ? _a : "Untitled",
164
+ slug: (_b = readString(doc.slug)) !== null && _b !== void 0 ? _b : String((_c = doc.id) !== null && _c !== void 0 ? _c : ""),
165
+ description: readString(doc.description),
166
+ };
167
+ }
168
+ export function normalizePayloadBlogArticle(doc) {
169
+ var _a, _b, _c, _d;
170
+ const content = addHeadingIdsAndExtractToc((_a = readString(doc.contentHtml)) !== null && _a !== void 0 ? _a : "");
171
+ const seo = isRecord(doc.seo) ? doc.seo : {};
172
+ return {
173
+ id: typeof doc.id === "string" || typeof doc.id === "number"
174
+ ? doc.id
175
+ : undefined,
176
+ title: (_b = readString(doc.title)) !== null && _b !== void 0 ? _b : "Untitled",
177
+ slug: (_c = readString(doc.slug)) !== null && _c !== void 0 ? _c : String((_d = doc.id) !== null && _d !== void 0 ? _d : ""),
178
+ excerpt: readString(doc.excerpt),
179
+ contentHtml: content.html,
180
+ searchText: readString(doc.searchText),
181
+ author: readAuthor(doc.author),
182
+ categories: readTaxonomies(doc.categories),
183
+ tags: readTaxonomies(doc.tags),
184
+ featuredImage: readImage(doc.featuredImage),
185
+ publishedAt: readString(doc.publishedAt),
186
+ updatedAt: readString(doc.updatedAt),
187
+ language: readString(doc.language),
188
+ seo: {
189
+ metaTitle: readString(seo.metaTitle),
190
+ metaDescription: readString(seo.metaDescription),
191
+ canonicalUrl: readString(seo.canonicalUrl),
192
+ robots: readString(seo.robots),
193
+ ogImage: readImage(seo.ogImage),
194
+ schemaOverride: isRecord(seo.schemaOverride) ? seo.schemaOverride : null,
195
+ },
196
+ toc: content.toc,
197
+ };
198
+ }
199
+ export function normalizePayloadBlogListResult(result) {
200
+ return Object.assign(Object.assign({}, result), { docs: result.docs.map(normalizePayloadBlogArticle) });
201
+ }
202
+ export function paginateBlogArticles(articles, page = 1, limit = 12) {
203
+ const safeLimit = Math.max(1, Math.floor(limit));
204
+ const totalDocs = articles.length;
205
+ const totalPages = Math.max(1, Math.ceil(totalDocs / safeLimit));
206
+ const safePage = Math.min(Math.max(1, Math.floor(page)), totalPages);
207
+ const start = (safePage - 1) * safeLimit;
208
+ return {
209
+ docs: articles.slice(start, start + safeLimit),
210
+ totalDocs,
211
+ page: safePage,
212
+ totalPages,
213
+ };
214
+ }
215
+ export function buildBlogPagination(params) {
216
+ var _a;
217
+ const basePath = (_a = params.basePath) !== null && _a !== void 0 ? _a : normalizeRoutePrefix(params.site.routePrefix);
218
+ const pagePath = (page) => page <= 1 ? basePath || "/" : `${basePath.replace(/\/$/, "")}/page/${page}`;
219
+ return {
220
+ page: params.page,
221
+ totalPages: params.totalPages,
222
+ totalDocs: params.totalDocs,
223
+ prevHref: params.page > 1 ? pagePath(params.page - 1) : null,
224
+ nextHref: params.page < params.totalPages ? pagePath(params.page + 1) : null,
225
+ };
226
+ }
227
+ export function buildArticleMetadata(article, site) {
228
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
229
+ const canonical = articleCanonicalUrl(article, site);
230
+ const description = ((_b = (_a = article.seo) === null || _a === void 0 ? void 0 : _a.metaDescription) === null || _b === void 0 ? void 0 : _b.trim()) ||
231
+ ((_c = article.excerpt) === null || _c === void 0 ? void 0 : _c.trim()) ||
232
+ stripHtml((_d = article.contentHtml) !== null && _d !== void 0 ? _d : "").slice(0, 220);
233
+ const title = ((_f = (_e = article.seo) === null || _e === void 0 ? void 0 : _e.metaTitle) === null || _f === void 0 ? void 0 : _f.trim()) || article.title;
234
+ const image = (_j = (_h = (_g = article.seo) === null || _g === void 0 ? void 0 : _g.ogImage) !== null && _h !== void 0 ? _h : article.featuredImage) !== null && _j !== void 0 ? _j : site.defaultOgImage;
235
+ const imageAbsolute = imageUrl(image, site);
236
+ const index = !hasNoIndex(article);
237
+ return {
238
+ title,
239
+ description,
240
+ canonical,
241
+ robots: {
242
+ index,
243
+ follow: true,
244
+ googleBot: {
245
+ index,
246
+ follow: true,
247
+ "max-image-preview": "large",
248
+ "max-snippet": -1,
249
+ "max-video-preview": -1,
250
+ },
251
+ },
252
+ openGraph: Object.assign(Object.assign(Object.assign(Object.assign({ type: "article", url: canonical, siteName: site.siteName, title,
253
+ description }, (dateToIso(article.publishedAt)
254
+ ? { publishedTime: (_k = dateToIso(article.publishedAt)) !== null && _k !== void 0 ? _k : undefined }
255
+ : {})), (dateToIso(article.updatedAt)
256
+ ? { modifiedTime: (_l = dateToIso(article.updatedAt)) !== null && _l !== void 0 ? _l : undefined }
257
+ : {})), (((_m = article.author) === null || _m === void 0 ? void 0 : _m.name) ? { authors: [article.author.name] } : {})), (imageAbsolute
258
+ ? {
259
+ images: [
260
+ Object.assign(Object.assign(Object.assign({ url: imageAbsolute }, ((image === null || image === void 0 ? void 0 : image.width) ? { width: image.width } : {})), ((image === null || image === void 0 ? void 0 : image.height) ? { height: image.height } : {})), { alt: (_o = image === null || image === void 0 ? void 0 : image.alt) !== null && _o !== void 0 ? _o : title }),
261
+ ],
262
+ }
263
+ : {})),
264
+ twitter: Object.assign({ card: "summary_large_image", title,
265
+ description }, (imageAbsolute ? { images: [imageAbsolute] } : {})),
266
+ };
267
+ }
268
+ export function buildArticleJsonLd(article, site) {
269
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
270
+ const url = articleCanonicalUrl(article, site);
271
+ const image = (_a = article.featuredImage) !== null && _a !== void 0 ? _a : site.defaultOgImage;
272
+ const imageAbsolute = imageUrl(image, site);
273
+ const siteRoot = site.siteUrl.replace(/\/$/, "");
274
+ const organizationId = `${siteRoot}/#organization`;
275
+ const websiteId = `${siteRoot}/#website`;
276
+ const webpageId = `${url}#webpage`;
277
+ const articleId = `${url}#article`;
278
+ const imageId = imageAbsolute ? `${url}#primaryimage` : null;
279
+ const authorId = article.author
280
+ ? (_b = article.author.profileUrl) !== null && _b !== void 0 ? _b : `${url}#author`
281
+ : organizationId;
282
+ const graph = [
283
+ {
284
+ "@type": "WebSite",
285
+ "@id": websiteId,
286
+ name: site.siteName,
287
+ url: site.siteUrl,
288
+ publisher: {
289
+ "@id": organizationId,
290
+ },
291
+ },
292
+ Object.assign({ "@type": "Organization", "@id": organizationId, name: (_c = site.organizationName) !== null && _c !== void 0 ? _c : site.siteName, url: site.siteUrl }, (site.organizationLogoUrl
293
+ ? { logo: { "@type": "ImageObject", url: site.organizationLogoUrl } }
294
+ : {})),
295
+ {
296
+ "@type": "WebPage",
297
+ "@id": webpageId,
298
+ url,
299
+ name: (_e = (_d = article.seo) === null || _d === void 0 ? void 0 : _d.metaTitle) !== null && _e !== void 0 ? _e : article.title,
300
+ isPartOf: { "@id": websiteId },
301
+ primaryImageOfPage: imageId ? { "@id": imageId } : undefined,
302
+ breadcrumb: { "@id": `${url}#breadcrumb` },
303
+ inLanguage: (_g = (_f = article.language) !== null && _f !== void 0 ? _f : site.defaultLanguage) !== null && _g !== void 0 ? _g : "en",
304
+ },
305
+ {
306
+ "@type": "BreadcrumbList",
307
+ "@id": `${url}#breadcrumb`,
308
+ itemListElement: [
309
+ {
310
+ "@type": "ListItem",
311
+ position: 1,
312
+ name: "Blog",
313
+ item: absoluteUrl(site.siteUrl, normalizeRoutePrefix(site.routePrefix)),
314
+ },
315
+ {
316
+ "@type": "ListItem",
317
+ position: 2,
318
+ name: article.title,
319
+ item: url,
320
+ },
321
+ ],
322
+ },
323
+ ...(article.author
324
+ ? [
325
+ {
326
+ "@type": "Person",
327
+ "@id": authorId,
328
+ name: article.author.name,
329
+ url: (_h = article.author.profileUrl) !== null && _h !== void 0 ? _h : undefined,
330
+ sameAs: ((_j = article.author.sameAs) === null || _j === void 0 ? void 0 : _j.length)
331
+ ? article.author.sameAs
332
+ : undefined,
333
+ },
334
+ ]
335
+ : []),
336
+ ...(imageAbsolute
337
+ ? [
338
+ {
339
+ "@type": "ImageObject",
340
+ "@id": imageId,
341
+ url: imageAbsolute,
342
+ width: (_k = image === null || image === void 0 ? void 0 : image.width) !== null && _k !== void 0 ? _k : undefined,
343
+ height: (_l = image === null || image === void 0 ? void 0 : image.height) !== null && _l !== void 0 ? _l : undefined,
344
+ caption: (_m = image === null || image === void 0 ? void 0 : image.caption) !== null && _m !== void 0 ? _m : undefined,
345
+ },
346
+ ]
347
+ : []),
348
+ Object.assign(Object.assign({ "@type": "BlogPosting", "@id": articleId, headline: article.title, description: (_q = (_o = article.excerpt) !== null && _o !== void 0 ? _o : (_p = article.seo) === null || _p === void 0 ? void 0 : _p.metaDescription) !== null && _q !== void 0 ? _q : undefined, url, mainEntityOfPage: {
349
+ "@id": webpageId,
350
+ }, inLanguage: (_s = (_r = article.language) !== null && _r !== void 0 ? _r : site.defaultLanguage) !== null && _s !== void 0 ? _s : "en", datePublished: (_t = dateToIso(article.publishedAt)) !== null && _t !== void 0 ? _t : undefined, dateModified: (_v = (_u = dateToIso(article.updatedAt)) !== null && _u !== void 0 ? _u : dateToIso(article.publishedAt)) !== null && _v !== void 0 ? _v : undefined, author: article.author
351
+ ? { "@id": authorId }
352
+ : {
353
+ "@id": organizationId,
354
+ }, publisher: {
355
+ "@id": organizationId,
356
+ } }, (imageId ? { image: { "@id": imageId } } : {})), ((_x = (_w = article.seo) === null || _w === void 0 ? void 0 : _w.schemaOverride) !== null && _x !== void 0 ? _x : {})),
357
+ ];
358
+ return {
359
+ "@context": "https://schema.org",
360
+ "@graph": graph,
361
+ };
362
+ }
363
+ export function buildRssXml(params) {
364
+ var _a, _b;
365
+ const prefix = normalizeRoutePrefix(params.site.routePrefix);
366
+ const channelUrl = absoluteUrl(params.site.siteUrl, prefix || "/");
367
+ const items = params.articles
368
+ .filter((article) => !hasNoIndex(article))
369
+ .map((article) => {
370
+ var _a;
371
+ const url = articleCanonicalUrl(article, params.site);
372
+ return [
373
+ "<item>",
374
+ `<title>${escapeHtml(article.title)}</title>`,
375
+ `<link>${escapeHtml(url)}</link>`,
376
+ `<guid>${escapeHtml(url)}</guid>`,
377
+ article.excerpt ? `<description>${escapeHtml(article.excerpt)}</description>` : "",
378
+ dateToIso(article.publishedAt)
379
+ ? `<pubDate>${new Date((_a = dateToIso(article.publishedAt)) !== null && _a !== void 0 ? _a : "").toUTCString()}</pubDate>`
380
+ : "",
381
+ "</item>",
382
+ ].join("");
383
+ })
384
+ .join("");
385
+ return [
386
+ '<?xml version="1.0" encoding="UTF-8"?>',
387
+ '<rss version="2.0">',
388
+ "<channel>",
389
+ `<title>${escapeHtml((_a = params.title) !== null && _a !== void 0 ? _a : `${params.site.siteName} Blog`)}</title>`,
390
+ `<link>${escapeHtml(channelUrl)}</link>`,
391
+ `<description>${escapeHtml((_b = params.description) !== null && _b !== void 0 ? _b : `${params.site.siteName} articles`)}</description>`,
392
+ items,
393
+ "</channel>",
394
+ "</rss>",
395
+ ].join("");
396
+ }
397
+ export function buildBlogSitemapEntries(site, articles) {
398
+ return articles
399
+ .filter((article) => isIndexableBlogArticle(article, site))
400
+ .map((article) => {
401
+ var _a, _b;
402
+ return ({
403
+ url: articleCanonicalUrl(article, site),
404
+ lastModified: (_b = (_a = dateToIso(article.updatedAt)) !== null && _a !== void 0 ? _a : dateToIso(article.publishedAt)) !== null && _b !== void 0 ? _b : undefined,
405
+ });
406
+ });
407
+ }
408
+ export function buildBlogPaginatedSitemapEntries(site, basePath, totalDocs = 0, pageSize = 12) {
409
+ const safePageSize = Math.max(1, Math.floor(pageSize));
410
+ const totalPages = Math.max(1, Math.ceil(totalDocs / safePageSize));
411
+ const normalizedBase = basePath.replace(/\/$/, "") || "/";
412
+ return Array.from({ length: totalPages }, (_, index) => ({
413
+ url: absoluteUrl(site.siteUrl, index === 0 ? normalizedBase : `${normalizedBase}/page/${index + 1}`),
414
+ }));
415
+ }
416
+ export function buildBlogIndexSitemapEntries(site, totalPages = 1) {
417
+ return Array.from({ length: Math.max(1, totalPages) }, (_, index) => ({
418
+ url: absoluteUrl(site.siteUrl, blogIndexPath(site, index + 1)),
419
+ }));
420
+ }
421
+ export function buildBlogDirectorySitemapEntries(site) {
422
+ const prefix = normalizeRoutePrefix(site.routePrefix);
423
+ return ["authors", "categories", "tags"].map((segment) => ({
424
+ url: absoluteUrl(site.siteUrl, `${prefix}/${segment}`),
425
+ }));
426
+ }
427
+ export function buildBlogAuthorSitemapEntries(site, authors) {
428
+ return authors.flatMap((author) => author.slug
429
+ ? [
430
+ {
431
+ url: absoluteUrl(site.siteUrl, authorPath(author, site)),
432
+ },
433
+ ]
434
+ : []);
435
+ }
436
+ export function buildBlogCategorySitemapEntries(site, categories) {
437
+ return categories.map((category) => ({
438
+ url: absoluteUrl(site.siteUrl, categoryPath(category, site)),
439
+ }));
440
+ }
441
+ export function buildBlogTagSitemapEntries(site, tags) {
442
+ return tags.map((tag) => ({
443
+ url: absoluteUrl(site.siteUrl, tagPath(tag, site)),
444
+ }));
445
+ }
446
+ export function buildSitemapUrlsetXml(entries) {
447
+ const urls = entries
448
+ .map((entry) => [
449
+ "<url>",
450
+ `<loc>${escapeHtml(entry.url)}</loc>`,
451
+ entry.lastModified
452
+ ? `<lastmod>${escapeHtml(entry.lastModified)}</lastmod>`
453
+ : "",
454
+ "</url>",
455
+ ].join(""))
456
+ .join("");
457
+ return [
458
+ '<?xml version="1.0" encoding="UTF-8"?>',
459
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
460
+ urls,
461
+ "</urlset>",
462
+ ].join("");
463
+ }
464
+ export function buildSitemapIndexXml(entries) {
465
+ const sitemaps = entries
466
+ .map((entry) => [
467
+ "<sitemap>",
468
+ `<loc>${escapeHtml(entry.url)}</loc>`,
469
+ entry.lastModified
470
+ ? `<lastmod>${escapeHtml(entry.lastModified)}</lastmod>`
471
+ : "",
472
+ "</sitemap>",
473
+ ].join(""))
474
+ .join("");
475
+ return [
476
+ '<?xml version="1.0" encoding="UTF-8"?>',
477
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
478
+ sitemaps,
479
+ "</sitemapindex>",
480
+ ].join("");
481
+ }
482
+ export function buildBlogRobots(site) {
483
+ return {
484
+ rules: {
485
+ userAgent: "*",
486
+ allow: normalizeRoutePrefix(site.routePrefix) || "/",
487
+ },
488
+ sitemap: absoluteUrl(site.siteUrl, "/sitemap.xml"),
489
+ };
490
+ }
491
+ export function searchBlogArticles(articles, query, limit = 20) {
492
+ const terms = query
493
+ .trim()
494
+ .toLowerCase()
495
+ .split(/\s+/)
496
+ .filter(Boolean);
497
+ if (terms.length === 0)
498
+ return [];
499
+ return articles
500
+ .map((article) => {
501
+ var _a, _b, _c;
502
+ const haystack = [
503
+ article.title,
504
+ article.excerpt,
505
+ article.searchText,
506
+ (_a = article.author) === null || _a === void 0 ? void 0 : _a.name,
507
+ ...((_b = article.categories) !== null && _b !== void 0 ? _b : []).map((category) => category.title),
508
+ ...((_c = article.tags) !== null && _c !== void 0 ? _c : []).map((tag) => tag.title),
509
+ ]
510
+ .filter(Boolean)
511
+ .join(" ")
512
+ .toLowerCase();
513
+ const score = terms.reduce((total, term) => total + (haystack.includes(term) ? 1 : 0), 0);
514
+ return { article, score };
515
+ })
516
+ .filter((entry) => entry.score > 0)
517
+ .sort((a, b) => b.score - a.score)
518
+ .slice(0, limit)
519
+ .map((entry) => entry.article);
520
+ }
521
+ async function payloadFetch(options, path) {
522
+ var _a;
523
+ const fetchImpl = (_a = options.fetchImpl) !== null && _a !== void 0 ? _a : fetch;
524
+ const response = await fetchImpl(absoluteUrl(options.baseUrl, path), { headers: options.headers });
525
+ if (!response.ok) {
526
+ throw new Error(`Payload request failed: ${response.status} ${response.statusText}`);
527
+ }
528
+ return (await response.json());
529
+ }
530
+ export async function fetchPayloadBlogPosts(options) {
531
+ var _a, _b, _c;
532
+ const collection = (_a = options.postsCollection) !== null && _a !== void 0 ? _a : "blog-posts";
533
+ const params = new URLSearchParams({
534
+ depth: "2",
535
+ sort: "-publishedAt",
536
+ limit: String((_b = options.limit) !== null && _b !== void 0 ? _b : 20),
537
+ page: String((_c = options.page) !== null && _c !== void 0 ? _c : 1),
538
+ "where[_status][equals]": "published",
539
+ });
540
+ const result = await payloadFetch(options, `/api/${collection}?${params.toString()}`);
541
+ return normalizePayloadBlogListResult(result);
542
+ }
543
+ export async function fetchAllPayloadBlogPosts(options) {
544
+ var _a, _b, _c;
545
+ const limit = (_a = options.limit) !== null && _a !== void 0 ? _a : 100;
546
+ let page = 1;
547
+ let totalPages = 1;
548
+ const docs = [];
549
+ let latest = null;
550
+ do {
551
+ latest = await fetchPayloadBlogPosts(Object.assign(Object.assign({}, options), { limit, page }));
552
+ docs.push(...latest.docs);
553
+ totalPages = (_b = latest.totalPages) !== null && _b !== void 0 ? _b : page;
554
+ page += 1;
555
+ } while (page <= totalPages);
556
+ return Object.assign(Object.assign({}, (latest !== null && latest !== void 0 ? latest : {})), { docs, page: 1, totalDocs: (_c = latest === null || latest === void 0 ? void 0 : latest.totalDocs) !== null && _c !== void 0 ? _c : docs.length, totalPages });
557
+ }
558
+ async function fetchPayloadCollectionDocs(options) {
559
+ var _a, _b, _c, _d;
560
+ const limit = (_a = options.limit) !== null && _a !== void 0 ? _a : 100;
561
+ let page = 1;
562
+ let totalPages = 1;
563
+ const docs = [];
564
+ let latest = null;
565
+ do {
566
+ const params = new URLSearchParams({
567
+ depth: "2",
568
+ limit: String(limit),
569
+ page: String(page),
570
+ sort: (_b = options.sort) !== null && _b !== void 0 ? _b : "title",
571
+ });
572
+ latest = await payloadFetch(options, `/api/${options.collection}?${params.toString()}`);
573
+ docs.push(...latest.docs);
574
+ totalPages = (_c = latest.totalPages) !== null && _c !== void 0 ? _c : page;
575
+ page += 1;
576
+ } while (page <= totalPages);
577
+ return Object.assign(Object.assign({}, (latest !== null && latest !== void 0 ? latest : {})), { docs: docs.map(options.normalize), page: 1, totalDocs: (_d = latest === null || latest === void 0 ? void 0 : latest.totalDocs) !== null && _d !== void 0 ? _d : docs.length, totalPages });
578
+ }
579
+ async function fetchPayloadCollectionDocBySlug(options) {
580
+ const params = new URLSearchParams({
581
+ depth: "2",
582
+ limit: "1",
583
+ "where[slug][equals]": options.slug,
584
+ });
585
+ const result = await payloadFetch(options, `/api/${options.collection}?${params.toString()}`);
586
+ return result.docs[0] ? options.normalize(result.docs[0]) : null;
587
+ }
588
+ export function fetchPayloadBlogAuthors(options) {
589
+ var _a;
590
+ return fetchPayloadCollectionDocs(Object.assign(Object.assign({}, options), { collection: (_a = options.authorsCollection) !== null && _a !== void 0 ? _a : "blog-authors", normalize: normalizePayloadBlogAuthor, limit: options.limit, sort: "name" }));
591
+ }
592
+ export function fetchPayloadBlogAuthorBySlug(options) {
593
+ var _a;
594
+ return fetchPayloadCollectionDocBySlug(Object.assign(Object.assign({}, options), { collection: (_a = options.authorsCollection) !== null && _a !== void 0 ? _a : "blog-authors", normalize: normalizePayloadBlogAuthor }));
595
+ }
596
+ export function fetchPayloadBlogCategories(options) {
597
+ var _a;
598
+ return fetchPayloadCollectionDocs(Object.assign(Object.assign({}, options), { collection: (_a = options.categoriesCollection) !== null && _a !== void 0 ? _a : "blog-categories", normalize: normalizePayloadBlogTaxonomy, limit: options.limit, sort: "title" }));
599
+ }
600
+ export function fetchPayloadBlogCategoryBySlug(options) {
601
+ var _a;
602
+ return fetchPayloadCollectionDocBySlug(Object.assign(Object.assign({}, options), { collection: (_a = options.categoriesCollection) !== null && _a !== void 0 ? _a : "blog-categories", normalize: normalizePayloadBlogTaxonomy }));
603
+ }
604
+ export function fetchPayloadBlogTags(options) {
605
+ var _a;
606
+ return fetchPayloadCollectionDocs(Object.assign(Object.assign({}, options), { collection: (_a = options.tagsCollection) !== null && _a !== void 0 ? _a : "blog-tags", normalize: normalizePayloadBlogTaxonomy, limit: options.limit, sort: "title" }));
607
+ }
608
+ export function fetchPayloadBlogTagBySlug(options) {
609
+ var _a;
610
+ return fetchPayloadCollectionDocBySlug(Object.assign(Object.assign({}, options), { collection: (_a = options.tagsCollection) !== null && _a !== void 0 ? _a : "blog-tags", normalize: normalizePayloadBlogTaxonomy }));
611
+ }
612
+ function idEquals(left, right) {
613
+ return String(left) === String(right);
614
+ }
615
+ export function filterBlogArticlesByAuthor(articles, author) {
616
+ return articles.filter((article) => {
617
+ if (!article.author)
618
+ return false;
619
+ if (author.id != null && article.author.id != null) {
620
+ return idEquals(article.author.id, author.id);
621
+ }
622
+ return Boolean(author.slug && article.author.slug === author.slug);
623
+ });
624
+ }
625
+ export function filterBlogArticlesByCategory(articles, category) {
626
+ return articles.filter((article) => {
627
+ var _a;
628
+ return ((_a = article.categories) !== null && _a !== void 0 ? _a : []).some((item) => {
629
+ if (category.id != null && item.id != null)
630
+ return idEquals(item.id, category.id);
631
+ return item.slug === category.slug;
632
+ });
633
+ });
634
+ }
635
+ export function filterBlogArticlesByTag(articles, tag) {
636
+ return articles.filter((article) => {
637
+ var _a;
638
+ return ((_a = article.tags) !== null && _a !== void 0 ? _a : []).some((item) => {
639
+ if (tag.id != null && item.id != null)
640
+ return idEquals(item.id, tag.id);
641
+ return item.slug === tag.slug;
642
+ });
643
+ });
644
+ }
645
+ export async function fetchPayloadBlogPostBySlug(options) {
646
+ var _a;
647
+ const collection = (_a = options.postsCollection) !== null && _a !== void 0 ? _a : "blog-posts";
648
+ const params = new URLSearchParams({
649
+ depth: "2",
650
+ limit: "1",
651
+ "where[slug][equals]": options.slug,
652
+ "where[_status][equals]": "published",
653
+ });
654
+ const result = await payloadFetch(options, `/api/${collection}?${params.toString()}`);
655
+ return result.docs[0] ? normalizePayloadBlogArticle(result.docs[0]) : null;
656
+ }
657
+ export async function fetchPayloadBlogPostByPreviousSlug(options) {
658
+ var _a;
659
+ const collection = (_a = options.postsCollection) !== null && _a !== void 0 ? _a : "blog-posts";
660
+ const params = new URLSearchParams({
661
+ depth: "2",
662
+ limit: "1",
663
+ "where[slugHistory.slug][equals]": options.slug,
664
+ "where[_status][equals]": "published",
665
+ });
666
+ const result = await payloadFetch(options, `/api/${collection}?${params.toString()}`);
667
+ return result.docs[0] ? normalizePayloadBlogArticle(result.docs[0]) : null;
668
+ }
669
+ export async function fetchPayloadBlogRedirect(options) {
670
+ var _a, _b;
671
+ const collection = (_a = options.redirectsCollection) !== null && _a !== void 0 ? _a : "blog-redirects";
672
+ const params = new URLSearchParams({
673
+ depth: "1",
674
+ limit: "1",
675
+ "where[from][equals]": options.path,
676
+ });
677
+ const result = await payloadFetch(options, `/api/${collection}?${params.toString()}`);
678
+ return (_b = result.docs[0]) !== null && _b !== void 0 ? _b : null;
679
+ }
680
+ export { absoluteUrl, articlePath, articleUrl, authorPath, blogIndexPath, categoryPath, normalizeRoutePrefix, tagPath, };
681
+ //# sourceMappingURL=server.js.map