@growth-labs/seo 0.1.3
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/README.md +80 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +162 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/seo.d.ts +5 -0
- package/dist/middleware/seo.d.ts.map +1 -0
- package/dist/middleware/seo.js +70 -0
- package/dist/middleware/seo.js.map +1 -0
- package/dist/options.d.ts +489 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +118 -0
- package/dist/options.js.map +1 -0
- package/dist/routes/llms.d.ts +4 -0
- package/dist/routes/llms.d.ts.map +1 -0
- package/dist/routes/llms.js +11 -0
- package/dist/routes/llms.js.map +1 -0
- package/dist/routes/podcast-narration.d.ts +4 -0
- package/dist/routes/podcast-narration.d.ts.map +1 -0
- package/dist/routes/podcast-narration.js +36 -0
- package/dist/routes/podcast-narration.js.map +1 -0
- package/dist/routes/podcast.d.ts +4 -0
- package/dist/routes/podcast.d.ts.map +1 -0
- package/dist/routes/podcast.js +20 -0
- package/dist/routes/podcast.js.map +1 -0
- package/dist/routes/robots.d.ts +4 -0
- package/dist/routes/robots.d.ts.map +1 -0
- package/dist/routes/robots.js +11 -0
- package/dist/routes/robots.js.map +1 -0
- package/dist/routes/rss.d.ts +4 -0
- package/dist/routes/rss.d.ts.map +1 -0
- package/dist/routes/rss.js +19 -0
- package/dist/routes/rss.js.map +1 -0
- package/dist/routes/sitemap-articles.d.ts +4 -0
- package/dist/routes/sitemap-articles.d.ts.map +1 -0
- package/dist/routes/sitemap-articles.js +19 -0
- package/dist/routes/sitemap-articles.js.map +1 -0
- package/dist/routes/sitemap-index.d.ts +4 -0
- package/dist/routes/sitemap-index.d.ts.map +1 -0
- package/dist/routes/sitemap-index.js +77 -0
- package/dist/routes/sitemap-index.js.map +1 -0
- package/dist/routes/sitemap-pages.d.ts +4 -0
- package/dist/routes/sitemap-pages.d.ts.map +1 -0
- package/dist/routes/sitemap-pages.js +18 -0
- package/dist/routes/sitemap-pages.js.map +1 -0
- package/dist/routes/sitemap-products.d.ts +4 -0
- package/dist/routes/sitemap-products.d.ts.map +1 -0
- package/dist/routes/sitemap-products.js +18 -0
- package/dist/routes/sitemap-products.js.map +1 -0
- package/dist/routes/sitemap-videos.d.ts +4 -0
- package/dist/routes/sitemap-videos.d.ts.map +1 -0
- package/dist/routes/sitemap-videos.js +18 -0
- package/dist/routes/sitemap-videos.js.map +1 -0
- package/dist/state.d.ts +7 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +18 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +103 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/aeo.d.ts +16 -0
- package/dist/utils/aeo.d.ts.map +1 -0
- package/dist/utils/aeo.js +38 -0
- package/dist/utils/aeo.js.map +1 -0
- package/dist/utils/discover.d.ts +18 -0
- package/dist/utils/discover.d.ts.map +1 -0
- package/dist/utils/discover.js +41 -0
- package/dist/utils/discover.js.map +1 -0
- package/dist/utils/hreflang.d.ts +3 -0
- package/dist/utils/hreflang.d.ts.map +1 -0
- package/dist/utils/hreflang.js +20 -0
- package/dist/utils/hreflang.js.map +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +12 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-ld/article.d.ts +4 -0
- package/dist/utils/json-ld/article.d.ts.map +1 -0
- package/dist/utils/json-ld/article.js +66 -0
- package/dist/utils/json-ld/article.js.map +1 -0
- package/dist/utils/json-ld/audio.d.ts +7 -0
- package/dist/utils/json-ld/audio.d.ts.map +1 -0
- package/dist/utils/json-ld/audio.js +25 -0
- package/dist/utils/json-ld/audio.js.map +1 -0
- package/dist/utils/json-ld/breadcrumb.d.ts +7 -0
- package/dist/utils/json-ld/breadcrumb.d.ts.map +1 -0
- package/dist/utils/json-ld/breadcrumb.js +20 -0
- package/dist/utils/json-ld/breadcrumb.js.map +1 -0
- package/dist/utils/json-ld/faq.d.ts +6 -0
- package/dist/utils/json-ld/faq.d.ts.map +1 -0
- package/dist/utils/json-ld/faq.js +15 -0
- package/dist/utils/json-ld/faq.js.map +1 -0
- package/dist/utils/json-ld/howto.d.ts +7 -0
- package/dist/utils/json-ld/howto.d.ts.map +1 -0
- package/dist/utils/json-ld/howto.js +19 -0
- package/dist/utils/json-ld/howto.js.map +1 -0
- package/dist/utils/json-ld/index.d.ts +13 -0
- package/dist/utils/json-ld/index.d.ts.map +1 -0
- package/dist/utils/json-ld/index.js +12 -0
- package/dist/utils/json-ld/index.js.map +1 -0
- package/dist/utils/json-ld/item-list.d.ts +5 -0
- package/dist/utils/json-ld/item-list.d.ts.map +1 -0
- package/dist/utils/json-ld/item-list.js +20 -0
- package/dist/utils/json-ld/item-list.js.map +1 -0
- package/dist/utils/json-ld/organization.d.ts +4 -0
- package/dist/utils/json-ld/organization.d.ts.map +1 -0
- package/dist/utils/json-ld/organization.js +36 -0
- package/dist/utils/json-ld/organization.js.map +1 -0
- package/dist/utils/json-ld/person.d.ts +6 -0
- package/dist/utils/json-ld/person.d.ts.map +1 -0
- package/dist/utils/json-ld/person.js +23 -0
- package/dist/utils/json-ld/person.js.map +1 -0
- package/dist/utils/json-ld/product.d.ts +5 -0
- package/dist/utils/json-ld/product.d.ts.map +1 -0
- package/dist/utils/json-ld/product.js +112 -0
- package/dist/utils/json-ld/product.js.map +1 -0
- package/dist/utils/json-ld/video.d.ts +3 -0
- package/dist/utils/json-ld/video.d.ts.map +1 -0
- package/dist/utils/json-ld/video.js +20 -0
- package/dist/utils/json-ld/video.js.map +1 -0
- package/dist/utils/json-ld/website.d.ts +4 -0
- package/dist/utils/json-ld/website.d.ts.map +1 -0
- package/dist/utils/json-ld/website.js +22 -0
- package/dist/utils/json-ld/website.js.map +1 -0
- package/dist/utils/llms.d.ts +7 -0
- package/dist/utils/llms.d.ts.map +1 -0
- package/dist/utils/llms.js +38 -0
- package/dist/utils/llms.js.map +1 -0
- package/dist/utils/meta.d.ts +7 -0
- package/dist/utils/meta.d.ts.map +1 -0
- package/dist/utils/meta.js +122 -0
- package/dist/utils/meta.js.map +1 -0
- package/dist/utils/podcast.d.ts +8 -0
- package/dist/utils/podcast.d.ts.map +1 -0
- package/dist/utils/podcast.js +94 -0
- package/dist/utils/podcast.js.map +1 -0
- package/dist/utils/robots.d.ts +3 -0
- package/dist/utils/robots.d.ts.map +1 -0
- package/dist/utils/robots.js +28 -0
- package/dist/utils/robots.js.map +1 -0
- package/dist/utils/rss.d.ts +4 -0
- package/dist/utils/rss.d.ts.map +1 -0
- package/dist/utils/rss.js +53 -0
- package/dist/utils/rss.js.map +1 -0
- package/dist/utils/sitemap.d.ts +13 -0
- package/dist/utils/sitemap.d.ts.map +1 -0
- package/dist/utils/sitemap.js +133 -0
- package/dist/utils/sitemap.js.map +1 -0
- package/dist/utils/validation.d.ts +18 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +141 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/vite-plugin.d.ts +4 -0
- package/dist/vite-plugin.d.ts.map +1 -0
- package/dist/vite-plugin.js +22 -0
- package/dist/vite-plugin.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const AVAILABILITY_MAP = {
|
|
2
|
+
InStock: 'https://schema.org/InStock',
|
|
3
|
+
OutOfStock: 'https://schema.org/OutOfStock',
|
|
4
|
+
PreOrder: 'https://schema.org/PreOrder',
|
|
5
|
+
Discontinued: 'https://schema.org/Discontinued',
|
|
6
|
+
};
|
|
7
|
+
function buildOffer(price, currency, availability, url, condition, hasReturnPolicy) {
|
|
8
|
+
const offer = {
|
|
9
|
+
'@type': 'Offer',
|
|
10
|
+
price,
|
|
11
|
+
priceCurrency: currency,
|
|
12
|
+
availability: AVAILABILITY_MAP[availability] ?? `https://schema.org/${availability}`,
|
|
13
|
+
url,
|
|
14
|
+
};
|
|
15
|
+
if (condition) {
|
|
16
|
+
offer.itemCondition = `https://schema.org/${condition}`;
|
|
17
|
+
}
|
|
18
|
+
if (hasReturnPolicy) {
|
|
19
|
+
offer.hasMerchantReturnPolicy = { '@id': '#return-policy' };
|
|
20
|
+
}
|
|
21
|
+
return offer;
|
|
22
|
+
}
|
|
23
|
+
function buildVariantProduct(variant, url, productCurrency, hasReturnPolicy) {
|
|
24
|
+
const currency = variant.currency ?? productCurrency;
|
|
25
|
+
const v = {
|
|
26
|
+
'@type': 'Product',
|
|
27
|
+
name: variant.name,
|
|
28
|
+
offers: buildOffer(variant.price, currency, variant.availability, url, undefined, hasReturnPolicy),
|
|
29
|
+
};
|
|
30
|
+
if (variant.sku)
|
|
31
|
+
v.sku = variant.sku;
|
|
32
|
+
if (variant.image)
|
|
33
|
+
v.image = variant.image;
|
|
34
|
+
return v;
|
|
35
|
+
}
|
|
36
|
+
export function generateProductJsonLd(product, url, options) {
|
|
37
|
+
const hasReturnPolicy = !!(options.commerce?.enabled && options.commerce.returnPolicy);
|
|
38
|
+
const result = {
|
|
39
|
+
'@context': 'https://schema.org',
|
|
40
|
+
'@type': 'Product',
|
|
41
|
+
name: product.name,
|
|
42
|
+
description: product.description,
|
|
43
|
+
image: product.images,
|
|
44
|
+
offers: buildOffer(product.price, product.currency, product.availability, url, product.condition, hasReturnPolicy),
|
|
45
|
+
};
|
|
46
|
+
if (product.sku)
|
|
47
|
+
result.sku = product.sku;
|
|
48
|
+
if (product.gtin)
|
|
49
|
+
result.gtin = product.gtin;
|
|
50
|
+
if (product.mpn)
|
|
51
|
+
result.mpn = product.mpn;
|
|
52
|
+
if (product.brand) {
|
|
53
|
+
result.brand = {
|
|
54
|
+
'@type': 'Brand',
|
|
55
|
+
name: product.brand,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (product.rating) {
|
|
59
|
+
result.aggregateRating = {
|
|
60
|
+
'@type': 'AggregateRating',
|
|
61
|
+
ratingValue: product.rating.value,
|
|
62
|
+
reviewCount: product.rating.count,
|
|
63
|
+
...(product.rating.bestRating !== undefined ? { bestRating: product.rating.bestRating } : {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (product.reviews?.length) {
|
|
67
|
+
result.review = product.reviews.map((review) => {
|
|
68
|
+
const r = {
|
|
69
|
+
'@type': 'Review',
|
|
70
|
+
author: { '@type': 'Person', name: review.author },
|
|
71
|
+
reviewRating: {
|
|
72
|
+
'@type': 'Rating',
|
|
73
|
+
ratingValue: review.rating,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
if (review.body)
|
|
77
|
+
r.reviewBody = review.body;
|
|
78
|
+
if (review.datePublished)
|
|
79
|
+
r.datePublished = review.datePublished;
|
|
80
|
+
return r;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
export function generateProductGroupJsonLd(product, url, options) {
|
|
86
|
+
const hasReturnPolicy = !!(options.commerce?.enabled && options.commerce.returnPolicy);
|
|
87
|
+
const variants = product.variants ?? [];
|
|
88
|
+
const result = {
|
|
89
|
+
'@context': 'https://schema.org',
|
|
90
|
+
'@type': 'ProductGroup',
|
|
91
|
+
name: product.name,
|
|
92
|
+
description: product.description,
|
|
93
|
+
image: product.images,
|
|
94
|
+
hasVariant: variants.map((v) => buildVariantProduct(v, url, product.currency, hasReturnPolicy)),
|
|
95
|
+
};
|
|
96
|
+
if (product.brand) {
|
|
97
|
+
result.brand = {
|
|
98
|
+
'@type': 'Brand',
|
|
99
|
+
name: product.brand,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (product.rating) {
|
|
103
|
+
result.aggregateRating = {
|
|
104
|
+
'@type': 'AggregateRating',
|
|
105
|
+
ratingValue: product.rating.value,
|
|
106
|
+
reviewCount: product.rating.count,
|
|
107
|
+
...(product.rating.bestRating !== undefined ? { bestRating: product.rating.bestRating } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=product.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product.js","sourceRoot":"","sources":["../../../src/utils/json-ld/product.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/utils/json-ld/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE/D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,CAiBnE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function generateVideoJsonLd(item) {
|
|
2
|
+
const video = item.video;
|
|
3
|
+
const result = {
|
|
4
|
+
'@context': 'https://schema.org',
|
|
5
|
+
'@type': 'VideoObject',
|
|
6
|
+
name: item.title,
|
|
7
|
+
thumbnailUrl: video.thumbnailUrl,
|
|
8
|
+
duration: video.duration,
|
|
9
|
+
};
|
|
10
|
+
if (item.description)
|
|
11
|
+
result.description = item.description;
|
|
12
|
+
if (video.contentUrl)
|
|
13
|
+
result.contentUrl = video.contentUrl;
|
|
14
|
+
if (video.embedUrl)
|
|
15
|
+
result.embedUrl = video.embedUrl;
|
|
16
|
+
if (item.datePublished)
|
|
17
|
+
result.uploadDate = item.datePublished;
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=video.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.js","sourceRoot":"","sources":["../../../src/utils/json-ld/video.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,mBAAmB,CAAC,IAAiB;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAM,CAAA;IAEzB,MAAM,MAAM,GAAiB;QAC5B,UAAU,EAAE,oBAAoB;QAChC,OAAO,EAAE,aAAa;QACtB,IAAI,EAAE,IAAI,CAAC,KAAK;QAChB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACxB,CAAA;IAED,IAAI,IAAI,CAAC,WAAW;QAAE,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;IAC3D,IAAI,KAAK,CAAC,UAAU;QAAE,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAA;IAC1D,IAAI,KAAK,CAAC,QAAQ;QAAE,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;IACpD,IAAI,IAAI,CAAC,aAAa;QAAE,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAA;IAE9D,OAAO,MAAM,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website.d.ts","sourceRoot":"","sources":["../../../src/utils/json-ld/website.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,YAAY,CAuB/E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function generateWebSiteJsonLd(options) {
|
|
2
|
+
const { site, organization, locales } = options;
|
|
3
|
+
const result = {
|
|
4
|
+
'@context': 'https://schema.org',
|
|
5
|
+
'@type': 'WebSite',
|
|
6
|
+
name: organization.name,
|
|
7
|
+
url: site,
|
|
8
|
+
potentialAction: {
|
|
9
|
+
'@type': 'SearchAction',
|
|
10
|
+
target: {
|
|
11
|
+
'@type': 'EntryPoint',
|
|
12
|
+
urlTemplate: `${site}/?q={search_term_string}`,
|
|
13
|
+
},
|
|
14
|
+
'query-input': 'required name=search_term_string',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
if (locales?.length) {
|
|
18
|
+
result.inLanguage = locales.map((l) => l.lang);
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=website.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website.js","sourceRoot":"","sources":["../../../src/utils/json-ld/website.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,qBAAqB,CAAC,OAA2B;IAChE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAE/C,MAAM,MAAM,GAAiB;QAC5B,UAAU,EAAE,oBAAoB;QAChC,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,YAAY,CAAC,IAAI;QACvB,GAAG,EAAE,IAAI;QACT,eAAe,EAAE;YAChB,OAAO,EAAE,cAAc;YACvB,MAAM,EAAE;gBACP,OAAO,EAAE,YAAY;gBACrB,WAAW,EAAE,GAAG,IAAI,0BAA0B;aAC9C;YACD,aAAa,EAAE,kCAAkC;SACjD;KACD,CAAA;IAED,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QACrB,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC;IAED,OAAO,MAAM,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedSeoOptions } from '../options.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate llms.txt per the llmstxt.org spec
|
|
4
|
+
* Format: # Title, > description, ## sections with links, ## Optional links
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateLlmsTxt(options: ResolvedSeoOptions): string;
|
|
7
|
+
//# sourceMappingURL=llms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms.d.ts","sourceRoot":"","sources":["../../src/utils/llms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAsCnE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate llms.txt per the llmstxt.org spec
|
|
3
|
+
* Format: # Title, > description, ## sections with links, ## Optional links
|
|
4
|
+
*/
|
|
5
|
+
export function generateLlmsTxt(options) {
|
|
6
|
+
const { organization, llmsContent } = options;
|
|
7
|
+
const lines = [];
|
|
8
|
+
// Title
|
|
9
|
+
lines.push(`# ${organization.name}`);
|
|
10
|
+
lines.push('');
|
|
11
|
+
if (llmsContent) {
|
|
12
|
+
// Description block
|
|
13
|
+
if (llmsContent.description) {
|
|
14
|
+
lines.push(`> ${llmsContent.description}`);
|
|
15
|
+
lines.push('');
|
|
16
|
+
}
|
|
17
|
+
// Sections with links
|
|
18
|
+
for (const section of llmsContent.sections) {
|
|
19
|
+
lines.push(`## ${section.heading}`);
|
|
20
|
+
lines.push('');
|
|
21
|
+
for (const link of section.links) {
|
|
22
|
+
lines.push(`- [${link.title}](${link.url}): ${link.description}`);
|
|
23
|
+
}
|
|
24
|
+
lines.push('');
|
|
25
|
+
}
|
|
26
|
+
// Optional links
|
|
27
|
+
if (llmsContent.optionalLinks?.length) {
|
|
28
|
+
lines.push('## Optional');
|
|
29
|
+
lines.push('');
|
|
30
|
+
for (const link of llmsContent.optionalLinks) {
|
|
31
|
+
lines.push(`- [${link.title}](${link.url})`);
|
|
32
|
+
}
|
|
33
|
+
lines.push('');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return `${lines.join('\n').trimEnd()}\n`;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=llms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms.js","sourceRoot":"","sources":["../../src/utils/llms.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAA2B;IAC1D,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,OAAO,CAAA;IAE7C,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,QAAQ;IACR,KAAK,CAAC,IAAI,CAAC,KAAK,YAAY,CAAC,IAAI,EAAE,CAAC,CAAA;IACpC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAEd,IAAI,WAAW,EAAE,CAAC;QACjB,oBAAoB;QACpB,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,WAAW,EAAE,CAAC,CAAA;YAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACf,CAAC;QAED,sBAAsB;QACtB,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;YACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACd,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;YAClE,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACf,CAAC;QAED,iBAAiB;QACjB,IAAI,WAAW,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACd,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,aAAa,EAAE,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,CAAA;YAC7C,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACf,CAAC;IACF,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,IAAI,CAAA;AACzC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedSeoOptions } from '../options.js';
|
|
2
|
+
import type { CanonicalLink, ContentItem, MetaTag } from '../types.js';
|
|
3
|
+
export type OgVariant = 'article' | 'product' | 'website';
|
|
4
|
+
export declare function applyTrailingSlash(url: string, policy: string): string;
|
|
5
|
+
export declare function generateCanonical(url: string, options: ResolvedSeoOptions): CanonicalLink;
|
|
6
|
+
export declare function generateMeta(item: ContentItem, variant: OgVariant, options: ResolvedSeoOptions): MetaTag[];
|
|
7
|
+
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/utils/meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAEtE,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;AAEzD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAmCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa,CAKzF;AAED,wBAAgB,YAAY,CAC3B,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,kBAAkB,GACzB,OAAO,EAAE,CA+FX"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export function applyTrailingSlash(url, policy) {
|
|
2
|
+
if (policy === 'never') {
|
|
3
|
+
// Strip trailing slash but preserve root slash
|
|
4
|
+
if (url.endsWith('/') && url !== '/') {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = new URL(url);
|
|
7
|
+
if (parsed.pathname !== '/') {
|
|
8
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, '');
|
|
9
|
+
return parsed.toString();
|
|
10
|
+
}
|
|
11
|
+
return url;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return url.endsWith('/') && url.length > 1 ? url.slice(0, -1) : url;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return url;
|
|
18
|
+
}
|
|
19
|
+
if (policy === 'always') {
|
|
20
|
+
if (!url.endsWith('/')) {
|
|
21
|
+
try {
|
|
22
|
+
const parsed = new URL(url);
|
|
23
|
+
// Don't add slash if there's a query string or hash
|
|
24
|
+
if (!parsed.search && !parsed.hash) {
|
|
25
|
+
parsed.pathname = parsed.pathname.replace(/\/*$/, '/');
|
|
26
|
+
return parsed.toString();
|
|
27
|
+
}
|
|
28
|
+
return url;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return `${url}/`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return url;
|
|
35
|
+
}
|
|
36
|
+
// ignore
|
|
37
|
+
return url;
|
|
38
|
+
}
|
|
39
|
+
export function generateCanonical(url, options) {
|
|
40
|
+
return {
|
|
41
|
+
rel: 'canonical',
|
|
42
|
+
href: applyTrailingSlash(url, options.trailingSlash),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function generateMeta(item, variant, options) {
|
|
46
|
+
const tags = [];
|
|
47
|
+
const { defaults, organization } = options;
|
|
48
|
+
const canonicalUrl = applyTrailingSlash(item.url, options.trailingSlash);
|
|
49
|
+
const image = item.image ?? defaults.defaultImage ?? '';
|
|
50
|
+
const ogType = variant === 'article' ? 'article' : variant === 'product' ? 'og:product' : 'website';
|
|
51
|
+
// og:type
|
|
52
|
+
tags.push({ property: 'og:type', content: ogType });
|
|
53
|
+
// og:title
|
|
54
|
+
tags.push({ property: 'og:title', content: item.title });
|
|
55
|
+
// og:description
|
|
56
|
+
if (item.description) {
|
|
57
|
+
tags.push({ property: 'og:description', content: item.description });
|
|
58
|
+
}
|
|
59
|
+
// og:url
|
|
60
|
+
tags.push({ property: 'og:url', content: canonicalUrl });
|
|
61
|
+
// og:image
|
|
62
|
+
if (image) {
|
|
63
|
+
tags.push({ property: 'og:image', content: image });
|
|
64
|
+
tags.push({ property: 'og:image:width', content: '1200' });
|
|
65
|
+
tags.push({ property: 'og:image:height', content: '630' });
|
|
66
|
+
}
|
|
67
|
+
// og:site_name
|
|
68
|
+
tags.push({ property: 'og:site_name', content: organization.name });
|
|
69
|
+
// og:locale
|
|
70
|
+
const locale = item.locale ?? defaults.locale;
|
|
71
|
+
tags.push({ property: 'og:locale', content: locale });
|
|
72
|
+
// og:locale:alternate
|
|
73
|
+
if (item.alternateLocales?.length) {
|
|
74
|
+
for (const alt of item.alternateLocales) {
|
|
75
|
+
tags.push({ property: 'og:locale:alternate', content: alt.lang });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// twitter:card
|
|
79
|
+
tags.push({ name: 'twitter:card', content: defaults.twitterCardType });
|
|
80
|
+
// twitter:site
|
|
81
|
+
if (defaults.twitterSite) {
|
|
82
|
+
tags.push({ name: 'twitter:site', content: defaults.twitterSite });
|
|
83
|
+
}
|
|
84
|
+
// twitter:title
|
|
85
|
+
tags.push({ name: 'twitter:title', content: item.title });
|
|
86
|
+
// twitter:description
|
|
87
|
+
if (item.description) {
|
|
88
|
+
tags.push({ name: 'twitter:description', content: item.description });
|
|
89
|
+
}
|
|
90
|
+
// twitter:image
|
|
91
|
+
if (image) {
|
|
92
|
+
tags.push({ name: 'twitter:image', content: image });
|
|
93
|
+
}
|
|
94
|
+
// robots
|
|
95
|
+
tags.push({ name: 'robots', content: 'max-image-preview:large' });
|
|
96
|
+
// Article-specific
|
|
97
|
+
if (variant === 'article') {
|
|
98
|
+
if (item.datePublished) {
|
|
99
|
+
tags.push({ property: 'article:published_time', content: item.datePublished });
|
|
100
|
+
}
|
|
101
|
+
if (item.dateModified) {
|
|
102
|
+
tags.push({ property: 'article:modified_time', content: item.dateModified });
|
|
103
|
+
}
|
|
104
|
+
if (item.authors?.length) {
|
|
105
|
+
for (const author of item.authors) {
|
|
106
|
+
tags.push({ property: 'article:author', content: author.url ?? author.name });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Product-specific
|
|
111
|
+
if (variant === 'product' && item.product) {
|
|
112
|
+
const p = item.product;
|
|
113
|
+
tags.push({ property: 'product:price:amount', content: String(p.price) });
|
|
114
|
+
tags.push({ property: 'product:price:currency', content: p.currency });
|
|
115
|
+
tags.push({ property: 'product:availability', content: p.availability });
|
|
116
|
+
if (p.brand) {
|
|
117
|
+
tags.push({ property: 'product:brand', content: p.brand });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return tags;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/utils/meta.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ResolvedSeoOptions } from '../options.js';
|
|
2
|
+
import type { ContentItem } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Convert ISO 8601 duration (e.g. PT8M30S, PT1H2M3S) to M:SS or H:MM:SS
|
|
5
|
+
*/
|
|
6
|
+
export declare function convertIso8601Duration(duration: string): string;
|
|
7
|
+
export declare function generatePodcastFeed(episodes: ContentItem[], options: ResolvedSeoOptions): string;
|
|
8
|
+
//# sourceMappingURL=podcast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"podcast.d.ts","sourceRoot":"","sources":["../../src/utils/podcast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAW9C;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAe/D;AAMD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAwEhG"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
function escapeXml(str) {
|
|
2
|
+
return str
|
|
3
|
+
.replace(/&/g, '&')
|
|
4
|
+
.replace(/</g, '<')
|
|
5
|
+
.replace(/>/g, '>')
|
|
6
|
+
.replace(/"/g, '"')
|
|
7
|
+
.replace(/'/g, ''');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Convert ISO 8601 duration (e.g. PT8M30S, PT1H2M3S) to M:SS or H:MM:SS
|
|
11
|
+
*/
|
|
12
|
+
export function convertIso8601Duration(duration) {
|
|
13
|
+
const match = duration.match(/^PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/);
|
|
14
|
+
if (!match)
|
|
15
|
+
return duration;
|
|
16
|
+
const hours = parseInt(match[1] ?? '0', 10);
|
|
17
|
+
const minutes = parseInt(match[2] ?? '0', 10);
|
|
18
|
+
const seconds = parseInt(match[3] ?? '0', 10);
|
|
19
|
+
if (hours > 0) {
|
|
20
|
+
const mm = String(minutes).padStart(2, '0');
|
|
21
|
+
const ss = String(seconds).padStart(2, '0');
|
|
22
|
+
return `${hours}:${mm}:${ss}`;
|
|
23
|
+
}
|
|
24
|
+
const ss = String(seconds).padStart(2, '0');
|
|
25
|
+
return `${minutes}:${ss}`;
|
|
26
|
+
}
|
|
27
|
+
function toRfc822(dateStr) {
|
|
28
|
+
return new Date(dateStr).toUTCString();
|
|
29
|
+
}
|
|
30
|
+
export function generatePodcastFeed(episodes, options) {
|
|
31
|
+
const { site, organization } = options;
|
|
32
|
+
const podcast = options.podcast;
|
|
33
|
+
// Use podcast config if available, fall back to organization
|
|
34
|
+
const author = podcast?.author ?? organization.name;
|
|
35
|
+
const podcastTitle = podcast?.title ?? organization.name;
|
|
36
|
+
const podcastDescription = podcast?.description ?? '';
|
|
37
|
+
const podcastImage = podcast?.image ?? organization.logo;
|
|
38
|
+
const podcastCategory = podcast?.category ?? 'Technology';
|
|
39
|
+
const podcastLanguage = podcast?.language ?? 'en';
|
|
40
|
+
const podcastExplicit = podcast?.explicit ?? false;
|
|
41
|
+
const podcastType = podcast?.type ?? 'episodic';
|
|
42
|
+
const ownerEmail = podcast?.email ?? '';
|
|
43
|
+
const episodesXml = episodes
|
|
44
|
+
.map((item) => {
|
|
45
|
+
const pubDate = item.datePublished ? toRfc822(item.datePublished) : '';
|
|
46
|
+
const pubDateTag = pubDate ? `\n <pubDate>${escapeXml(pubDate)}</pubDate>` : '';
|
|
47
|
+
const descTag = item.description
|
|
48
|
+
? `\n <description>${escapeXml(item.description)}</description>`
|
|
49
|
+
: '';
|
|
50
|
+
const enclosureTag = item.audio
|
|
51
|
+
? `\n <enclosure url="${escapeXml(item.audio.url)}" type="audio/mpeg" length="0"/>`
|
|
52
|
+
: '';
|
|
53
|
+
const durationTag = item.audio?.duration
|
|
54
|
+
? `\n <itunes:duration>${escapeXml(convertIso8601Duration(item.audio.duration))}</itunes:duration>`
|
|
55
|
+
: '';
|
|
56
|
+
const ep = item.podcastEpisode;
|
|
57
|
+
const episodeTag = ep?.episodeNumber != null
|
|
58
|
+
? `\n <itunes:episode>${ep.episodeNumber}</itunes:episode>`
|
|
59
|
+
: '';
|
|
60
|
+
const seasonTag = ep?.seasonNumber != null ? `\n <itunes:season>${ep.seasonNumber}</itunes:season>` : '';
|
|
61
|
+
const episodeTypeTag = ep?.episodeType
|
|
62
|
+
? `\n <itunes:episodeType>${escapeXml(ep.episodeType)}</itunes:episodeType>`
|
|
63
|
+
: '';
|
|
64
|
+
return ` <item>
|
|
65
|
+
<title>${escapeXml(item.title)}</title>
|
|
66
|
+
<link>${escapeXml(item.url)}</link>
|
|
67
|
+
<guid isPermaLink="true">${escapeXml(item.url)}</guid>${pubDateTag}${descTag}${enclosureTag}${durationTag}${episodeTag}${seasonTag}${episodeTypeTag}
|
|
68
|
+
</item>`;
|
|
69
|
+
})
|
|
70
|
+
.join('\n');
|
|
71
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
72
|
+
<rss version="2.0"
|
|
73
|
+
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
|
|
74
|
+
xmlns:podcast="https://podcastindex.org/namespace/1.0"
|
|
75
|
+
xmlns:atom="http://www.w3.org/2005/Atom">
|
|
76
|
+
<channel>
|
|
77
|
+
<title>${escapeXml(podcastTitle)}</title>
|
|
78
|
+
<description>${escapeXml(podcastDescription)}</description>
|
|
79
|
+
<link>${escapeXml(site)}</link>
|
|
80
|
+
<language>${escapeXml(podcastLanguage)}</language>
|
|
81
|
+
<itunes:author>${escapeXml(author)}</itunes:author>
|
|
82
|
+
<itunes:owner>
|
|
83
|
+
<itunes:name>${escapeXml(author)}</itunes:name>
|
|
84
|
+
<itunes:email>${escapeXml(ownerEmail)}</itunes:email>
|
|
85
|
+
</itunes:owner>
|
|
86
|
+
<itunes:image href="${escapeXml(podcastImage)}"/>
|
|
87
|
+
<itunes:category text="${escapeXml(podcastCategory)}"/>
|
|
88
|
+
<itunes:explicit>${podcastExplicit ? 'true' : 'false'}</itunes:explicit>
|
|
89
|
+
<itunes:type>${escapeXml(podcastType)}</itunes:type>
|
|
90
|
+
${episodesXml}
|
|
91
|
+
</channel>
|
|
92
|
+
</rss>`;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=podcast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"podcast.js","sourceRoot":"","sources":["../../src/utils/podcast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../../src/utils/robots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAGvD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CA4BrE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SITEMAP_INDEX_PATH } from './sitemap.js';
|
|
2
|
+
export function generateRobotsTxt(options) {
|
|
3
|
+
const { site, robots } = options;
|
|
4
|
+
const lines = [];
|
|
5
|
+
// Default rules
|
|
6
|
+
lines.push('User-agent: *');
|
|
7
|
+
lines.push('Allow: /');
|
|
8
|
+
lines.push(`Sitemap: ${new URL(SITEMAP_INDEX_PATH, site).toString()}`);
|
|
9
|
+
// Additional rules
|
|
10
|
+
if (robots.additionalRules?.length) {
|
|
11
|
+
for (const rule of robots.additionalRules) {
|
|
12
|
+
lines.push('');
|
|
13
|
+
lines.push(`User-agent: ${rule.userAgent}`);
|
|
14
|
+
if (rule.allow?.length) {
|
|
15
|
+
for (const path of rule.allow) {
|
|
16
|
+
lines.push(`Allow: ${path}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (rule.disallow?.length) {
|
|
20
|
+
for (const path of rule.disallow) {
|
|
21
|
+
lines.push(`Disallow: ${path}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return `${lines.join('\n')}\n`;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=robots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"robots.js","sourceRoot":"","sources":["../../src/utils/robots.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAEjD,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC5D,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAChC,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,gBAAgB;IAChB,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;IAC3B,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACtB,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IAEtE,mBAAmB;IACnB,IAAI,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;QACpC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACd,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;YAC3C,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;gBACxB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAA;gBAC7B,CAAC;YACF,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;gBAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;gBAChC,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rss.d.ts","sourceRoot":"","sources":["../../src/utils/rss.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAe9C,wBAAgB,eAAe,CAC9B,KAAK,EAAE,WAAW,EAAE,EACpB,OAAO,EAAE,kBAAkB,EAC3B,WAAW,CAAC,EAAE,MAAM,GAClB,MAAM,CA2CR"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function escapeXml(str) {
|
|
2
|
+
return str
|
|
3
|
+
.replace(/&/g, '&')
|
|
4
|
+
.replace(/</g, '<')
|
|
5
|
+
.replace(/>/g, '>')
|
|
6
|
+
.replace(/"/g, '"')
|
|
7
|
+
.replace(/'/g, ''');
|
|
8
|
+
}
|
|
9
|
+
function toRfc822(dateStr) {
|
|
10
|
+
return new Date(dateStr).toUTCString();
|
|
11
|
+
}
|
|
12
|
+
export function generateRssFeed(items, options, description) {
|
|
13
|
+
const { site, organization, defaults } = options;
|
|
14
|
+
const feedDescription = description ?? organization.name;
|
|
15
|
+
const language = defaults.locale.replace('_', '-').toLowerCase();
|
|
16
|
+
const lastBuildDate = new Date().toUTCString();
|
|
17
|
+
const itemsXml = items
|
|
18
|
+
.map((item) => {
|
|
19
|
+
const pubDate = item.datePublished ? toRfc822(item.datePublished) : '';
|
|
20
|
+
const pubDateTag = pubDate ? `\n <pubDate>${escapeXml(pubDate)}</pubDate>` : '';
|
|
21
|
+
const descTag = item.description
|
|
22
|
+
? `\n <description>${escapeXml(item.description)}</description>`
|
|
23
|
+
: '';
|
|
24
|
+
const creatorsXml = (item.authors ?? [])
|
|
25
|
+
.map((a) => `\n <dc:creator>${escapeXml(a.name)}</dc:creator>`)
|
|
26
|
+
.join('');
|
|
27
|
+
const enclosureTag = item.audio
|
|
28
|
+
? `\n <enclosure url="${escapeXml(item.audio.url)}" type="audio/mpeg" length="0"/>`
|
|
29
|
+
: '';
|
|
30
|
+
return ` <item>
|
|
31
|
+
<title>${escapeXml(item.title)}</title>
|
|
32
|
+
<link>${escapeXml(item.url)}</link>
|
|
33
|
+
<guid isPermaLink="true">${escapeXml(item.url)}</guid>${pubDateTag}${descTag}${creatorsXml}${enclosureTag}
|
|
34
|
+
</item>`;
|
|
35
|
+
})
|
|
36
|
+
.join('\n');
|
|
37
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
38
|
+
<rss version="2.0"
|
|
39
|
+
xmlns:atom="http://www.w3.org/2005/Atom"
|
|
40
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
41
|
+
xmlns:content="http://purl.org/rss/1.0/modules/content/">
|
|
42
|
+
<channel>
|
|
43
|
+
<title>${escapeXml(organization.name)}</title>
|
|
44
|
+
<description>${escapeXml(feedDescription)}</description>
|
|
45
|
+
<link>${escapeXml(site)}</link>
|
|
46
|
+
<language>${escapeXml(language)}</language>
|
|
47
|
+
<atom:link href="${escapeXml(`${site}/feed.xml`)}" rel="self" type="application/rss+xml"/>
|
|
48
|
+
<lastBuildDate>${lastBuildDate}</lastBuildDate>
|
|
49
|
+
${itemsXml}
|
|
50
|
+
</channel>
|
|
51
|
+
</rss>`;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=rss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rss.js","sourceRoot":"","sources":["../../src/utils/rss.ts"],"names":[],"mappings":"AAGA,SAAS,SAAS,CAAC,GAAW;IAC7B,OAAO,GAAG;SACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AAC1B,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAChC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAC9B,KAAoB,EACpB,OAA2B,EAC3B,WAAoB;IAEpB,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,eAAe,GAAG,WAAW,IAAI,YAAY,CAAC,IAAI,CAAA;IACxD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;IAChE,MAAM,aAAa,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAE9C,MAAM,QAAQ,GAAG,KAAK;SACpB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACtE,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,oBAAoB,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;QACpF,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW;YAC/B,CAAC,CAAC,wBAAwB,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,gBAAgB;YACrE,CAAC,CAAC,EAAE,CAAA;QACL,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;aACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC;aACnE,IAAI,CAAC,EAAE,CAAC,CAAA;QACV,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK;YAC9B,CAAC,CAAC,2BAA2B,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC;YACxF,CAAC,CAAC,EAAE,CAAA;QAEL,OAAO;eACK,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;cACtB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;iCACA,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY;YACnG,CAAA;IACV,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;IAEZ,OAAO;;;;;;aAMK,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC;mBACtB,SAAS,CAAC,eAAe,CAAC;YACjC,SAAS,CAAC,IAAI,CAAC;gBACX,SAAS,CAAC,QAAQ,CAAC;uBACZ,SAAS,CAAC,GAAG,IAAI,WAAW,CAAC;qBAC/B,aAAa;EAChC,QAAQ;;OAEH,CAAA;AACP,CAAC"}
|