@chrisburnell/eleventy-cache-webmentions 2.1.10 → 2.1.12
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"cachedAt":
|
|
1
|
+
{"cachedAt":1761155512715,"type":"json","metadata":{}}
|
package/README.md
CHANGED
|
@@ -31,6 +31,8 @@ Check it out: [Webmention Setup for Eleventy](https://chrisburnell.com/article/w
|
|
|
31
31
|
- **With npm:** `npm install @chrisburnell/eleventy-cache-webmentions`
|
|
32
32
|
- **Direct download:** [https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip](https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip)
|
|
33
33
|
|
|
34
|
+
*Important Note: This plugin uses Node.js features only present in versions 18+. If you’re deploying your website somewhere, check to make sure that your Node.js version is set to 18 or greater. ([Cloudflare Pages](https://community.cloudflare.com/t/pages-node-js-version/295548/3), [GitHub Actions](https://github.com/actions/setup-node), [Netlify](https://answers.netlify.com/t/specifying-a-node-version/9701))*
|
|
35
|
+
|
|
34
36
|
Inside your Eleventy config file, use `addPlugin()` to add it to your project:
|
|
35
37
|
|
|
36
38
|
```javascript
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
const sanitizeHTML = require("sanitize-html");
|
|
2
2
|
const { AssetCache } = require("@11ty/eleventy-fetch");
|
|
3
|
-
const
|
|
3
|
+
const { styleText } = require("node:util");
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @type {Object}
|
|
7
|
+
*/
|
|
5
8
|
const defaults = {
|
|
6
9
|
refresh: false,
|
|
7
10
|
duration: "1d",
|
|
@@ -19,14 +22,21 @@ const defaults = {
|
|
|
19
22
|
maximumHtmlText: "mentioned this in",
|
|
20
23
|
};
|
|
21
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} url
|
|
27
|
+
* @param {string} domain
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
22
30
|
const absoluteURL = (url, domain) => {
|
|
23
31
|
try {
|
|
24
32
|
return new URL(url, domain).toString();
|
|
25
33
|
} catch (e) {
|
|
26
34
|
console.error(
|
|
27
|
-
`Trying to convert ${
|
|
35
|
+
`Trying to convert ${styleText(
|
|
36
|
+
"bold",
|
|
28
37
|
url,
|
|
29
|
-
)} to be an absolute url with base ${
|
|
38
|
+
)} to be an absolute url with base ${styleText(
|
|
39
|
+
"bold",
|
|
30
40
|
domain,
|
|
31
41
|
)} and failed.`,
|
|
32
42
|
);
|
|
@@ -34,12 +44,21 @@ const absoluteURL = (url, domain) => {
|
|
|
34
44
|
}
|
|
35
45
|
};
|
|
36
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @param {string} url
|
|
49
|
+
* @returns {string}
|
|
50
|
+
*/
|
|
37
51
|
const baseUrl = (url) => {
|
|
38
52
|
let hashSplit = url.split("#");
|
|
39
53
|
let queryparamSplit = hashSplit[0].split("?");
|
|
40
54
|
return queryparamSplit[0];
|
|
41
55
|
};
|
|
42
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @param {string} url
|
|
59
|
+
* @param {Object} urlReplacements
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
43
62
|
const fixUrl = (url, urlReplacements) => {
|
|
44
63
|
return Object.entries(urlReplacements).reduce(
|
|
45
64
|
(accumulator, [key, value]) => {
|
|
@@ -50,18 +69,30 @@ const fixUrl = (url, urlReplacements) => {
|
|
|
50
69
|
);
|
|
51
70
|
};
|
|
52
71
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} url
|
|
74
|
+
* @returns {string}
|
|
75
|
+
*/
|
|
76
|
+
const hostname = (url) => {
|
|
77
|
+
if (typeof url === "string" && url.includes("//")) {
|
|
78
|
+
const urlObject = new URL(url);
|
|
56
79
|
return urlObject.hostname;
|
|
57
80
|
}
|
|
58
|
-
return
|
|
81
|
+
return url;
|
|
59
82
|
};
|
|
60
83
|
|
|
61
|
-
|
|
62
|
-
|
|
84
|
+
/**
|
|
85
|
+
* @param {string|number|Date} date
|
|
86
|
+
* @returns {number}
|
|
87
|
+
*/
|
|
88
|
+
const epoch = (date) => {
|
|
89
|
+
return new Date(date).getTime();
|
|
63
90
|
};
|
|
64
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @param {Object} date
|
|
94
|
+
* @returns {string|undefined}
|
|
95
|
+
*/
|
|
65
96
|
const getPublished = (webmention) => {
|
|
66
97
|
return (
|
|
67
98
|
webmention?.["data"]?.["published"] ||
|
|
@@ -71,6 +102,10 @@ const getPublished = (webmention) => {
|
|
|
71
102
|
);
|
|
72
103
|
};
|
|
73
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @param {Object} webmention
|
|
107
|
+
* @returns {string|undefined}
|
|
108
|
+
*/
|
|
74
109
|
const getReceived = (webmention) => {
|
|
75
110
|
return (
|
|
76
111
|
webmention["wm-received"] ||
|
|
@@ -80,6 +115,10 @@ const getReceived = (webmention) => {
|
|
|
80
115
|
);
|
|
81
116
|
};
|
|
82
117
|
|
|
118
|
+
/**
|
|
119
|
+
* @param {Object} webmention
|
|
120
|
+
* @returns {string}
|
|
121
|
+
*/
|
|
83
122
|
const getContent = (webmention) => {
|
|
84
123
|
return (
|
|
85
124
|
webmention?.["contentSanitized"] ||
|
|
@@ -91,6 +130,10 @@ const getContent = (webmention) => {
|
|
|
91
130
|
);
|
|
92
131
|
};
|
|
93
132
|
|
|
133
|
+
/**
|
|
134
|
+
* @param {Object} webmention
|
|
135
|
+
* @returns {string}
|
|
136
|
+
*/
|
|
94
137
|
const getSource = (webmention) => {
|
|
95
138
|
return (
|
|
96
139
|
webmention["wm-source"] ||
|
|
@@ -100,6 +143,10 @@ const getSource = (webmention) => {
|
|
|
100
143
|
);
|
|
101
144
|
};
|
|
102
145
|
|
|
146
|
+
/**
|
|
147
|
+
* @param {Object} webmention
|
|
148
|
+
* @returns {string}
|
|
149
|
+
*/
|
|
103
150
|
const getURL = (webmention) => {
|
|
104
151
|
return (
|
|
105
152
|
webmention?.["data"]?.["url"] ||
|
|
@@ -109,10 +156,18 @@ const getURL = (webmention) => {
|
|
|
109
156
|
);
|
|
110
157
|
};
|
|
111
158
|
|
|
159
|
+
/**
|
|
160
|
+
* @param {Object} webmention
|
|
161
|
+
* @returns {string}
|
|
162
|
+
*/
|
|
112
163
|
const getTarget = (webmention) => {
|
|
113
164
|
return webmention["wm-target"] || webmention["target"];
|
|
114
165
|
};
|
|
115
166
|
|
|
167
|
+
/**
|
|
168
|
+
* @param {Object} webmention
|
|
169
|
+
* @returns {string|undefined}
|
|
170
|
+
*/
|
|
116
171
|
const getType = (webmention) => {
|
|
117
172
|
return (
|
|
118
173
|
webmention["wm-property"] ||
|
|
@@ -121,18 +176,32 @@ const getType = (webmention) => {
|
|
|
121
176
|
);
|
|
122
177
|
};
|
|
123
178
|
|
|
124
|
-
|
|
179
|
+
/**
|
|
180
|
+
* @param {Object[]} webmentions
|
|
181
|
+
* @param {string} type
|
|
182
|
+
* @returns {Object[]}
|
|
183
|
+
*/
|
|
184
|
+
const getByType = (webmentions, type) => {
|
|
125
185
|
return webmentions.filter((webmention) => {
|
|
126
|
-
return
|
|
186
|
+
return type === getType(webmention);
|
|
127
187
|
});
|
|
128
188
|
};
|
|
129
189
|
|
|
130
|
-
|
|
190
|
+
/**
|
|
191
|
+
* @param {Object[]} webmentions
|
|
192
|
+
* @param {string[]} types
|
|
193
|
+
* @returns {Object[]}
|
|
194
|
+
*/
|
|
195
|
+
const getByTypes = (webmentions, types) => {
|
|
131
196
|
return webmentions.filter((webmention) => {
|
|
132
|
-
return
|
|
197
|
+
return types.includes(getType(webmention));
|
|
133
198
|
});
|
|
134
199
|
};
|
|
135
200
|
|
|
201
|
+
/**
|
|
202
|
+
* @param {Object[]} webmentions
|
|
203
|
+
* @returns {Object[]}
|
|
204
|
+
*/
|
|
136
205
|
const removeDuplicates = (webmentions) => {
|
|
137
206
|
return [
|
|
138
207
|
...webmentions
|
|
@@ -150,6 +219,11 @@ const removeDuplicates = (webmentions) => {
|
|
|
150
219
|
];
|
|
151
220
|
};
|
|
152
221
|
|
|
222
|
+
/**
|
|
223
|
+
* @param {Object[]} webmentions
|
|
224
|
+
* @param {string[]} blocklist
|
|
225
|
+
* @returns {Object[]}
|
|
226
|
+
*/
|
|
153
227
|
const processBlocklist = (webmentions, blocklist) => {
|
|
154
228
|
return webmentions.filter((webmention) => {
|
|
155
229
|
let url = getSource(webmention);
|
|
@@ -166,6 +240,11 @@ const processBlocklist = (webmentions, blocklist) => {
|
|
|
166
240
|
});
|
|
167
241
|
};
|
|
168
242
|
|
|
243
|
+
/**
|
|
244
|
+
* @param {Object[]} webmentions
|
|
245
|
+
* @param {string[]} allowlist
|
|
246
|
+
* @returns {Object[]}
|
|
247
|
+
*/
|
|
169
248
|
const processAllowlist = (webmentions, allowlist) => {
|
|
170
249
|
return webmentions.filter((webmention) => {
|
|
171
250
|
let url = getSource(webmention);
|
|
@@ -182,6 +261,12 @@ const processAllowlist = (webmentions, allowlist) => {
|
|
|
182
261
|
});
|
|
183
262
|
};
|
|
184
263
|
|
|
264
|
+
/**
|
|
265
|
+
* @param {Object} options
|
|
266
|
+
* @param {Object[]} webmentions
|
|
267
|
+
* @param {string} url
|
|
268
|
+
* @returns {Promise<{found:number,filtered:Object[]}>}
|
|
269
|
+
*/
|
|
185
270
|
const performFetch = async (options, webmentions, url) => {
|
|
186
271
|
return await fetch(url)
|
|
187
272
|
.then(async (response) => {
|
|
@@ -193,9 +278,10 @@ const performFetch = async (options, webmentions, url) => {
|
|
|
193
278
|
|
|
194
279
|
if (!options.key in feed) {
|
|
195
280
|
console.log(
|
|
196
|
-
`${
|
|
281
|
+
`${styleText("grey", `[${hostname(options.domain)}]`)} ${
|
|
197
282
|
options.key
|
|
198
|
-
} was not found as a key in the response from ${
|
|
283
|
+
} was not found as a key in the response from ${styleText(
|
|
284
|
+
"bold",
|
|
199
285
|
hostname(options.feed),
|
|
200
286
|
)}!`,
|
|
201
287
|
);
|
|
@@ -226,9 +312,11 @@ const performFetch = async (options, webmentions, url) => {
|
|
|
226
312
|
})
|
|
227
313
|
.catch((error) => {
|
|
228
314
|
console.warn(
|
|
229
|
-
`${
|
|
315
|
+
`${styleText(
|
|
316
|
+
"grey",
|
|
230
317
|
`[${hostname(options.domain)}]`,
|
|
231
|
-
)} Something went wrong with your Webmention request to ${
|
|
318
|
+
)} Something went wrong with your Webmention request to ${styleText(
|
|
319
|
+
"bold",
|
|
232
320
|
hostname(options.feed),
|
|
233
321
|
)}!`,
|
|
234
322
|
);
|
|
@@ -241,6 +329,10 @@ const performFetch = async (options, webmentions, url) => {
|
|
|
241
329
|
});
|
|
242
330
|
};
|
|
243
331
|
|
|
332
|
+
/**
|
|
333
|
+
* @param {Object} options
|
|
334
|
+
* @returns {Promise<Object[]>}
|
|
335
|
+
*/
|
|
244
336
|
const fetchWebmentions = async (options) => {
|
|
245
337
|
if (!options.domain) {
|
|
246
338
|
throw new Error(
|
|
@@ -353,9 +445,14 @@ const fetchWebmentions = async (options) => {
|
|
|
353
445
|
// Add a console message with the number of fetched and processed Webmentions, if any
|
|
354
446
|
if (webmentionsCachedLength < webmentions.length) {
|
|
355
447
|
console.log(
|
|
356
|
-
`${
|
|
357
|
-
|
|
358
|
-
|
|
448
|
+
`${styleText(
|
|
449
|
+
"grey",
|
|
450
|
+
`[${hostname(options.domain)}]`,
|
|
451
|
+
)} ${styleText(
|
|
452
|
+
"bold",
|
|
453
|
+
String(webmentions.length - webmentionsCachedLength),
|
|
454
|
+
)} new Webmentions fetched into cache in ${styleText(
|
|
455
|
+
"bold",
|
|
359
456
|
(performance[0] + performance[1] / 1e9).toFixed(3) +
|
|
360
457
|
" seconds",
|
|
361
458
|
)}.`,
|
|
@@ -367,6 +464,11 @@ const fetchWebmentions = async (options) => {
|
|
|
367
464
|
};
|
|
368
465
|
|
|
369
466
|
let filtered = {};
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* @param {Object} options
|
|
470
|
+
* @returns {Promise<Object<string, Object[]>>}
|
|
471
|
+
*/
|
|
370
472
|
const filteredWebmentions = async (options) => {
|
|
371
473
|
if (Object.entries(filtered).length) {
|
|
372
474
|
return filtered;
|
|
@@ -394,7 +496,13 @@ const filteredWebmentions = async (options) => {
|
|
|
394
496
|
return filtered;
|
|
395
497
|
};
|
|
396
498
|
|
|
397
|
-
|
|
499
|
+
/**
|
|
500
|
+
* @param {Object} options
|
|
501
|
+
* @param {string} url
|
|
502
|
+
* @param {string[]|Object} [types={}]
|
|
503
|
+
* @returns {Promise<Object[]>}
|
|
504
|
+
*/
|
|
505
|
+
const getWebmentions = async (options, url, types = {}) => {
|
|
398
506
|
const webmentions = await filteredWebmentions(options);
|
|
399
507
|
url = absoluteURL(url, options.domain);
|
|
400
508
|
|
|
@@ -406,9 +514,8 @@ const getWebmentions = async (options, url, allowedTypes = {}) => {
|
|
|
406
514
|
webmentions[url]
|
|
407
515
|
// Filter webmentions by allowed response post types
|
|
408
516
|
.filter((entry) => {
|
|
409
|
-
return typeof
|
|
410
|
-
|
|
411
|
-
? allowedTypes.includes(getType(entry))
|
|
517
|
+
return typeof types === "object" && Object.keys(types).length
|
|
518
|
+
? types.includes(getType(entry))
|
|
412
519
|
: true;
|
|
413
520
|
})
|
|
414
521
|
// Sanitize content of webmentions against HTML limit
|
|
@@ -438,6 +545,10 @@ const getWebmentions = async (options, url, allowedTypes = {}) => {
|
|
|
438
545
|
);
|
|
439
546
|
};
|
|
440
547
|
|
|
548
|
+
/**
|
|
549
|
+
* @param {Object} eleventyConfig
|
|
550
|
+
* @param {Object} [options={}]
|
|
551
|
+
*/
|
|
441
552
|
const eleventyCacheWebmentions = (eleventyConfig, options = {}) => {
|
|
442
553
|
options = Object.assign(defaults, options);
|
|
443
554
|
|
package/eslint.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrisburnell/eleventy-cache-webmentions",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.12",
|
|
4
4
|
"description": "Cache webmentions using eleventy-fetch and make them available to use in collections, layouts, pages, etc. in Eleventy.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -55,11 +55,10 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@11ty/eleventy-fetch": "^5.1.0",
|
|
58
|
-
"chalk": "4.1.2",
|
|
59
58
|
"sanitize-html": "^2.17.0"
|
|
60
59
|
},
|
|
61
60
|
"devDependencies": {
|
|
62
|
-
"eslint": "^9.
|
|
63
|
-
"nock": "^14.0.
|
|
61
|
+
"eslint": "^9.38.0",
|
|
62
|
+
"nock": "^14.0.10"
|
|
64
63
|
}
|
|
65
64
|
}
|