@chrisburnell/eleventy-cache-webmentions 1.1.5 → 1.2.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/README.md +90 -90
- package/eleventy-cache-webmentions.js +97 -25
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@ I wrote a quicker and simpler guide to getting this Eleventy plugin working that
|
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- **With npm:** `npm install @chrisburnell/eleventy-cache-webmentions`
|
|
12
|
+
- **Direct download:** [https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip](https://github.com/chrisburnell/eleventy-cache-webmentions/archive/master.zip)
|
|
13
13
|
|
|
14
14
|
Once installed there are **two** more **required** set-up steps:
|
|
15
15
|
|
|
@@ -21,12 +21,12 @@ Inside your Eleventy config file (typically `.eleventy.js`), use `addPlugin`:
|
|
|
21
21
|
const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")
|
|
22
22
|
|
|
23
23
|
module.exports = function (eleventyConfig) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
eleventyConfig.addPlugin(pluginWebmentions, {
|
|
25
|
+
// these 3 fields are all required!
|
|
26
|
+
domain: "https://example.com",
|
|
27
|
+
feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
|
|
28
|
+
key: "children",
|
|
29
|
+
})
|
|
30
30
|
}
|
|
31
31
|
```
|
|
32
32
|
|
|
@@ -38,51 +38,51 @@ Advanced control over how the Webmentions are cached and processed is done by pa
|
|
|
38
38
|
const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")
|
|
39
39
|
|
|
40
40
|
module.exports = function (eleventyConfig) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
41
|
+
eleventyConfig.addPlugin(pluginWebmentions, {
|
|
42
|
+
// domain: required or the plugin will not function
|
|
43
|
+
// this is the website that you want to pull in Webmentions for
|
|
44
|
+
domain: "https://example.com",
|
|
45
|
+
// feed: required or the plugin will not function
|
|
46
|
+
// defines the URL of your Webmention server where a feed of Webmentions for your domain can be found
|
|
47
|
+
feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
|
|
48
|
+
// key: required or the plugin will not function
|
|
49
|
+
// dictates the key inside the feed where the array of Webmentions is located
|
|
50
|
+
key: "children",
|
|
51
|
+
// directory: ".cache" by default
|
|
52
|
+
// see https://www.11ty.dev/docs/plugins/cache/#cache-directory for more info
|
|
53
|
+
directory: ".cache",
|
|
54
|
+
// duration: "1d" by default
|
|
55
|
+
// see https://www.11ty.dev/docs/plugins/cache/#change-the-cache-duration for more info
|
|
56
|
+
duration: "1d",
|
|
57
|
+
// uniquekey: "webmentions" by default
|
|
58
|
+
// dictates the name sent to eleventy-fetch to name the file
|
|
59
|
+
uniqueKey: "webmentions",
|
|
60
|
+
// allowedHTML: Object by default
|
|
61
|
+
// see https://www.npmjs.com/package/sanitize-html for more info
|
|
62
|
+
allowedHTML: {
|
|
63
|
+
allowedTags: ["b", "i", "em", "strong", "a"],
|
|
64
|
+
allowedAttributes: {
|
|
65
|
+
a: ["href"],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
// allowlist: [] by default
|
|
69
|
+
// array of root URLs from which webmentions are wanted exclusively
|
|
70
|
+
allowlist: [],
|
|
71
|
+
// blocklist: [] by default
|
|
72
|
+
// array of root URLs from which webmentions are not wanted
|
|
73
|
+
// exclusively
|
|
74
|
+
blocklist: [],
|
|
75
|
+
// urlReplacements: {} by default
|
|
76
|
+
// object of key:value pairs containing from:to URL replacements
|
|
77
|
+
urlReplacements: {},
|
|
78
|
+
// maximumHtmlLength: 2000 by default
|
|
79
|
+
// number of characters in the HTML content at which a different
|
|
80
|
+
// message is shown instead of the content
|
|
81
|
+
maximumHtmlLength: 2000,
|
|
82
|
+
// maximumHtmlText: "mentioned this in" by default
|
|
83
|
+
// message shown when maximumHtmlLength is reached
|
|
84
|
+
maximumHtmlText: "mentioned this in",
|
|
85
|
+
})
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
@@ -92,9 +92,9 @@ Accessing the plugin in JavaScript in the way shown below will give you an Objec
|
|
|
92
92
|
|
|
93
93
|
```javascript
|
|
94
94
|
const Webmentions = require("@chrisburnell/eleventy-cache-webmentions")(null, {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
domain: "https://example.com",
|
|
96
|
+
feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
|
|
97
|
+
key: "children",
|
|
98
98
|
})
|
|
99
99
|
|
|
100
100
|
const webmentionsByUrl = await Webmentions()
|
|
@@ -104,28 +104,28 @@ This can prove to be very useful when building out your pages. Using [Eleventy
|
|
|
104
104
|
|
|
105
105
|
```javascript
|
|
106
106
|
const Webmentions = require("@chrisburnell/eleventy-cache-webmentions")(null, {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
domain: "https://example.com",
|
|
108
|
+
feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
|
|
109
|
+
key: "children",
|
|
110
110
|
})
|
|
111
111
|
|
|
112
112
|
module.exports = async () => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
113
|
+
const webmentionsByUrl = await Webmentions()
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
eleventyComputed: {
|
|
117
|
+
webmentions: (data) => {
|
|
118
|
+
const webmentionsForUrl = webmentionsByUrl["https://example.com" + data.page.url] || []
|
|
119
|
+
|
|
120
|
+
if (webmentionsForUrl.length) {
|
|
121
|
+
return webmentionsForUrl.sort((a, b) => {
|
|
122
|
+
return (b.data.published || b.verified_date) - (a.data.published || a.verified_date)
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
return []
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
129
|
}
|
|
130
130
|
```
|
|
131
131
|
|
|
@@ -133,11 +133,11 @@ You can now use this data in a number of useful ways, not limited to things like
|
|
|
133
133
|
|
|
134
134
|
```javascript
|
|
135
135
|
module.exports = (eleventyConfig) => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
eleventyConfig.addCollection("popular", (collection) => {
|
|
137
|
+
return collection.sort((a, b) => {
|
|
138
|
+
return b.data.webmentions.length - a.data.webmentions.length
|
|
139
|
+
})
|
|
139
140
|
})
|
|
140
|
-
})
|
|
141
141
|
}
|
|
142
142
|
```
|
|
143
143
|
|
|
@@ -166,7 +166,7 @@ And, if you need it, the entire Object of sorted Webmentions is available too:
|
|
|
166
166
|
|
|
167
167
|
```twig
|
|
168
168
|
{% raw %}{% set count = 0 %}
|
|
169
|
-
{% for url, array in
|
|
169
|
+
{% for url, array in webmentionsAll %}
|
|
170
170
|
{% set count = array.length + count %}
|
|
171
171
|
{% endfor %}
|
|
172
172
|
<p>This site has received {{ count }} Webmentions!</p>{% endraw %}
|
|
@@ -190,11 +190,11 @@ WEBMENTION_IO_TOKEN=njJql0lKXnotreal4x3Wmd
|
|
|
190
190
|
const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")
|
|
191
191
|
|
|
192
192
|
module.exports = function (eleventyConfig) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
eleventyConfig.addPlugin(pluginWebmentions, {
|
|
194
|
+
domain: "https://example.com",
|
|
195
|
+
feed: `https://webmention.io/api/mentions.jf2?domain=example.com&per-page=9001&token=${process.env.WEBMENTION_IO_TOKEN}`,
|
|
196
|
+
key: "children",
|
|
197
|
+
})
|
|
198
198
|
}
|
|
199
199
|
```
|
|
200
200
|
|
|
@@ -216,11 +216,11 @@ GO_JAMMING_TOKEN=njJql0lKXnotreal4x3Wmd
|
|
|
216
216
|
const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")
|
|
217
217
|
|
|
218
218
|
module.exports = function (eleventyConfig) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
219
|
+
eleventyConfig.addPlugin(pluginWebmentions, {
|
|
220
|
+
domain: "https://example.com",
|
|
221
|
+
feed: `https://jam.example.com/webmention/example.com/${process.env.GO_JAMMING_TOKEN}`,
|
|
222
|
+
key: "json",
|
|
223
|
+
})
|
|
224
224
|
}
|
|
225
225
|
```
|
|
226
226
|
|
|
@@ -7,7 +7,9 @@ const absoluteURL = (url, domain) => {
|
|
|
7
7
|
try {
|
|
8
8
|
return new URL(url, domain).toString()
|
|
9
9
|
} catch (e) {
|
|
10
|
-
console.log(
|
|
10
|
+
console.log(
|
|
11
|
+
`Trying to convert ${url} to be an absolute url with base ${domain} and failed.`
|
|
12
|
+
)
|
|
11
13
|
return url
|
|
12
14
|
}
|
|
13
15
|
}
|
|
@@ -19,10 +21,13 @@ const baseUrl = (url) => {
|
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const fixUrl = (url, urlReplacements) => {
|
|
22
|
-
return Object.entries(urlReplacements).reduce(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
return Object.entries(urlReplacements).reduce(
|
|
25
|
+
(accumulator, [key, value]) => {
|
|
26
|
+
const regex = new RegExp(key, "g")
|
|
27
|
+
return accumulator.replace(regex, value)
|
|
28
|
+
},
|
|
29
|
+
url
|
|
30
|
+
)
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
const hostname = (value) => {
|
|
@@ -38,15 +43,30 @@ const epoch = (value) => {
|
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
const getPublished = (webmention) => {
|
|
41
|
-
return
|
|
46
|
+
return (
|
|
47
|
+
webmention["wm-received"] ||
|
|
48
|
+
webmention?.["data"]["published"] ||
|
|
49
|
+
webmention["verified_date"] ||
|
|
50
|
+
webmention["published"]
|
|
51
|
+
)
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
const getContent = (webmention) => {
|
|
45
|
-
return
|
|
55
|
+
return (
|
|
56
|
+
webmention?.["content"]?.["html"] ||
|
|
57
|
+
webmention?.["content"] ||
|
|
58
|
+
webmention?.["data"]?.["content"] ||
|
|
59
|
+
""
|
|
60
|
+
)
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
const getSource = (webmention) => {
|
|
49
|
-
return
|
|
64
|
+
return (
|
|
65
|
+
webmention["url"] ||
|
|
66
|
+
webmention?.["data"]["url"] ||
|
|
67
|
+
webmention["wm-source"] ||
|
|
68
|
+
webmention["source"]
|
|
69
|
+
)
|
|
50
70
|
}
|
|
51
71
|
|
|
52
72
|
const getTarget = (webmention) => {
|
|
@@ -54,7 +74,11 @@ const getTarget = (webmention) => {
|
|
|
54
74
|
}
|
|
55
75
|
|
|
56
76
|
const getType = (webmention) => {
|
|
57
|
-
return
|
|
77
|
+
return (
|
|
78
|
+
webmention["wm-property"] ||
|
|
79
|
+
webmention?.["activity"]["type"] ||
|
|
80
|
+
webmention["type"]
|
|
81
|
+
)
|
|
58
82
|
}
|
|
59
83
|
|
|
60
84
|
const defaults = {
|
|
@@ -74,19 +98,27 @@ const defaults = {
|
|
|
74
98
|
|
|
75
99
|
const fetchWebmentions = async (options) => {
|
|
76
100
|
if (!options.domain) {
|
|
77
|
-
throw new Error(
|
|
101
|
+
throw new Error(
|
|
102
|
+
"domain is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information."
|
|
103
|
+
)
|
|
78
104
|
}
|
|
79
105
|
|
|
80
106
|
if (!options.feed) {
|
|
81
|
-
throw new Error(
|
|
107
|
+
throw new Error(
|
|
108
|
+
"feed is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information."
|
|
109
|
+
)
|
|
82
110
|
}
|
|
83
111
|
|
|
84
112
|
if (!options.key) {
|
|
85
|
-
throw new Error(
|
|
113
|
+
throw new Error(
|
|
114
|
+
"key is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information."
|
|
115
|
+
)
|
|
86
116
|
}
|
|
87
117
|
|
|
88
118
|
if (!options.uniqueKey) {
|
|
89
|
-
throw new Error(
|
|
119
|
+
throw new Error(
|
|
120
|
+
"uniqueKey is a required field when attempting to retrieve Webmentions. See https://www.npmjs.com/package/@chrisburnell/eleventy-cache-webmentions#installation for more information."
|
|
121
|
+
)
|
|
90
122
|
}
|
|
91
123
|
|
|
92
124
|
let asset = new AssetCache(options.uniqueKey, options.directory)
|
|
@@ -103,16 +135,27 @@ const fetchWebmentions = async (options) => {
|
|
|
103
135
|
// results since the most recent webmention
|
|
104
136
|
if (!asset.isCacheValid(options.duration)) {
|
|
105
137
|
const since = webmentions.length ? getPublished(webmentions[0]) : false
|
|
106
|
-
const url = `${options.feed}${
|
|
138
|
+
const url = `${options.feed}${
|
|
139
|
+
since
|
|
140
|
+
? `${options.feed.includes("?") ? "&" : "?"}since=${since}`
|
|
141
|
+
: ""
|
|
142
|
+
}`
|
|
107
143
|
await fetch(url)
|
|
108
144
|
.then(async (response) => {
|
|
109
145
|
if (response.ok) {
|
|
110
146
|
const feed = await response.json()
|
|
111
147
|
if (feed[options.key].length) {
|
|
112
|
-
webmentions = uniqBy(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
148
|
+
webmentions = uniqBy(
|
|
149
|
+
[...feed[options.key], ...webmentions],
|
|
150
|
+
(entry) => {
|
|
151
|
+
return getSource(entry)
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
console.log(
|
|
155
|
+
`[${hostname(options.domain)}] ${
|
|
156
|
+
feed[options.key].length
|
|
157
|
+
} new Webmentions fetched into cache.`
|
|
158
|
+
)
|
|
116
159
|
}
|
|
117
160
|
await asset.save(webmentions, "json")
|
|
118
161
|
return webmentions
|
|
@@ -120,7 +163,14 @@ const fetchWebmentions = async (options) => {
|
|
|
120
163
|
return Promise.reject(response)
|
|
121
164
|
})
|
|
122
165
|
.catch((error) => {
|
|
123
|
-
console.log(
|
|
166
|
+
console.log(
|
|
167
|
+
`[${hostname(
|
|
168
|
+
options.domain
|
|
169
|
+
)}] Something went wrong with your request to ${hostname(
|
|
170
|
+
options.feed
|
|
171
|
+
)}!`,
|
|
172
|
+
error
|
|
173
|
+
)
|
|
124
174
|
})
|
|
125
175
|
}
|
|
126
176
|
|
|
@@ -168,8 +218,12 @@ const filteredWebmentions = async (options) => {
|
|
|
168
218
|
// Fix local URLs based on urlReplacements and sort Webmentions into groups
|
|
169
219
|
// by target base URL
|
|
170
220
|
rawWebmentions.forEach((webmention) => {
|
|
171
|
-
let url = baseUrl(
|
|
172
|
-
|
|
221
|
+
let url = baseUrl(
|
|
222
|
+
fixUrl(
|
|
223
|
+
getTarget(webmention).replace(/\/?$/, "/"),
|
|
224
|
+
options.urlReplacements
|
|
225
|
+
)
|
|
226
|
+
)
|
|
173
227
|
|
|
174
228
|
if (!filtered[url]) {
|
|
175
229
|
filtered[url] = []
|
|
@@ -200,7 +254,10 @@ const getWebmentions = async (options, url, allowedTypes = {}) => {
|
|
|
200
254
|
webmentions[url]
|
|
201
255
|
// filter webmentions by allowed response post types
|
|
202
256
|
.filter((entry) => {
|
|
203
|
-
return typeof allowedTypes === "object" &&
|
|
257
|
+
return typeof allowedTypes === "object" &&
|
|
258
|
+
Object.keys(allowedTypes).length
|
|
259
|
+
? allowedTypes.includes(getType(entry))
|
|
260
|
+
: true
|
|
204
261
|
})
|
|
205
262
|
// sanitize content of webmentions against HTML limit
|
|
206
263
|
.map((entry) => {
|
|
@@ -209,7 +266,9 @@ const getWebmentions = async (options, url, allowedTypes = {}) => {
|
|
|
209
266
|
if (html.length) {
|
|
210
267
|
entry.content = sanitizeHTML(html, options.allowedHTML)
|
|
211
268
|
if (html.length > options.maximumHtmlLength) {
|
|
212
|
-
entry.content = `${
|
|
269
|
+
entry.content = `${
|
|
270
|
+
options.maximumHtmlText
|
|
271
|
+
} <a href="${getSource(entry)}">${getSource(entry)}</a>`
|
|
213
272
|
}
|
|
214
273
|
}
|
|
215
274
|
|
|
@@ -236,13 +295,26 @@ module.exports = (eleventyConfig, options = {}) => {
|
|
|
236
295
|
|
|
237
296
|
if (eleventyConfig) {
|
|
238
297
|
// Global Data
|
|
239
|
-
|
|
298
|
+
const filtered = async () => await filteredWebmentions(options)
|
|
299
|
+
eleventyConfig.addGlobalData("webmentionsByUrl", filtered)
|
|
300
|
+
const unfiltered = async () =>
|
|
301
|
+
await filteredWebmentions(options).then((filtered) =>
|
|
302
|
+
Object.values(filtered).reduce(
|
|
303
|
+
(array, webmentions) => [...array, ...webmentions],
|
|
304
|
+
[]
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
eleventyConfig.addGlobalData("webmentionsAll", unfiltered)
|
|
308
|
+
eleventyConfig.addGlobalData("webmentions", unfiltered)
|
|
240
309
|
|
|
241
310
|
// Liquid Filter
|
|
242
311
|
eleventyConfig.addLiquidFilter("getWebmentions", getWebmentionsFilter)
|
|
243
312
|
|
|
244
313
|
// Nunjucks Filter
|
|
245
|
-
eleventyConfig.addNunjucksAsyncFilter(
|
|
314
|
+
eleventyConfig.addNunjucksAsyncFilter(
|
|
315
|
+
"getWebmentions",
|
|
316
|
+
getWebmentionsFilter
|
|
317
|
+
)
|
|
246
318
|
}
|
|
247
319
|
|
|
248
320
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrisburnell/eleventy-cache-webmentions",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Fetch and cache webmentions using eleventy-fetch.",
|
|
5
5
|
"author": "Chris Burnell <me@chrisburnell.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
"webmention"
|
|
21
21
|
],
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"eslint": "^8.
|
|
23
|
+
"eslint": "^8.41.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@11ty/eleventy-fetch": "^
|
|
26
|
+
"@11ty/eleventy-fetch": "^4.0.0",
|
|
27
27
|
"lodash": "^4.17.21",
|
|
28
|
-
"node-fetch": "^
|
|
29
|
-
"sanitize-html": "^2.
|
|
28
|
+
"node-fetch": "^3.3.1",
|
|
29
|
+
"sanitize-html": "^2.10.0"
|
|
30
30
|
},
|
|
31
31
|
"main": "eleventy-cache-webmentions.js",
|
|
32
32
|
"scripts": {
|