vowel 0.1.41 → 0.1.43
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/CHANGELOG.md +9 -0
- package/bin.js +2 -2
- package/package.json +1 -1
- package/src/lib/components/Page.svelte +0 -2
- package/src/lib/utilities/getMetadata.js +46 -0
- package/src/lib/utilities/index.js +2 -1
- package/src/lib/utilities/mutateMarkdownAST.js +28 -45
- package/src/lib/utilities/mutateMarkdownFrontmatter.js +24 -54
- package/src/lib/utilities/processMarkdownFiles.js +1 -1
- package/src/lib/utilities/readMarkdownFile.js +2 -2
- package/src/lib/utilities/sendWebmention.js +12 -23
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.1.43](https://github.com/samlfair/vowel/compare/v0.1.42...v0.1.43) (2024-10-18)
|
|
6
|
+
|
|
7
|
+
## [0.1.42](https://github.com/samlfair/vowel/compare/v0.1.41...v0.1.42) (2024-10-18)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* un-hardcode webmention urls ([3421a69](https://github.com/samlfair/vowel/commit/3421a6998aa4ba20613b84c707e62fe273ddf327))
|
|
13
|
+
|
|
5
14
|
## [0.1.41](https://github.com/samlfair/vowel/compare/v0.1.40...v0.1.41) (2024-10-17)
|
|
6
15
|
|
|
7
16
|
|
package/bin.js
CHANGED
|
@@ -28,7 +28,7 @@ if (args._.includes('publish')) {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
if (!args.verbose) {
|
|
31
|
-
filterConsole(['jsconfig', 'vite', 'Vite', 'tsconfig', `--host`]);
|
|
31
|
+
// filterConsole(['jsconfig', 'vite', 'Vite', 'tsconfig', `--host`]);
|
|
32
32
|
console.log(`\n\n`);
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -54,7 +54,7 @@ child.stdout.on('data', (data) => {
|
|
|
54
54
|
console.log(`\n\n`);
|
|
55
55
|
processedFiles = 0;
|
|
56
56
|
foundFiles = 0;
|
|
57
|
-
} else if(
|
|
57
|
+
} else if(true) { // Toggle to true to reveal all console output
|
|
58
58
|
console.log(message)
|
|
59
59
|
} else if (message.match('http://localhost:')) {
|
|
60
60
|
const url = message.match(/http:\/\/localhost:\S+/);
|
package/package.json
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { XMLParser } from "fast-xml-parser"
|
|
2
|
+
import urlMetadata from 'url-metadata';
|
|
3
|
+
|
|
4
|
+
export default async function getMetadata({ cache, url }) {
|
|
5
|
+
if (!cache[url]) {
|
|
6
|
+
try {
|
|
7
|
+
const urlObject = new URL(url);
|
|
8
|
+
const allMetadata = await urlMetadata(urlObject.href, {
|
|
9
|
+
includeResponseBody: true,
|
|
10
|
+
ensureSecureImageRequest: true
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const parser = new XMLParser({
|
|
14
|
+
unpairedTags: ["!doctype", "meta", "link", "hr", "br", "img"],
|
|
15
|
+
ignoreAttributes: false,
|
|
16
|
+
stopNodes: ["*.pre", "*.script"],
|
|
17
|
+
processEntities: true,
|
|
18
|
+
htmlEntities: true
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
let parsedData = parser.parse(allMetadata.body)
|
|
22
|
+
const webmentionEndpoint = parsedData?.html?.head?.link?.find(link => {
|
|
23
|
+
return link["@_rel"] === "webmention"
|
|
24
|
+
})?.["@_href"]
|
|
25
|
+
|
|
26
|
+
const metadata = {
|
|
27
|
+
image: allMetadata['og:image'],
|
|
28
|
+
ogURL: allMetadata['og:url'],
|
|
29
|
+
canonicalURL: allMetadata.canonical,
|
|
30
|
+
title: allMetadata.title,
|
|
31
|
+
ogTitle: allMetadata['og:title'],
|
|
32
|
+
author: allMetadata.author,
|
|
33
|
+
description: allMetadata.description,
|
|
34
|
+
webmentionEndpoint
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
cache[url] = metadata;
|
|
38
|
+
|
|
39
|
+
return { metadata }
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.log({ fetchingMetadataError: error })
|
|
42
|
+
return { metadata: undefined }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { metadata: cache[url] }
|
|
46
|
+
}
|
|
@@ -18,4 +18,5 @@ export { default as resolveHomeDirPath } from './resolveHomeDirPath';
|
|
|
18
18
|
export { default as createPageClass } from './createPageClass';
|
|
19
19
|
export { default as createFolderClass } from './createFolderClass';
|
|
20
20
|
export { default as isActiveLink } from './isActiveLink';
|
|
21
|
-
export { default as sendWebmention } from "./sendWebmention"
|
|
21
|
+
export { default as sendWebmention } from "./sendWebmention"
|
|
22
|
+
export { default as getMetadata } from "./getMetadata"
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { sendWebmention } from './';
|
|
1
|
+
import { sendWebmention, getMetadata } from './';
|
|
3
2
|
|
|
4
3
|
function isURL(string) {
|
|
5
4
|
try {
|
|
@@ -10,8 +9,9 @@ function isURL(string) {
|
|
|
10
9
|
}
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
export default async function mutateMarkdownAST(ast, cache, webmentions) {
|
|
14
12
|
|
|
13
|
+
|
|
14
|
+
export default async function mutateMarkdownAST(ast, cache, webmentions, pageURL) {
|
|
15
15
|
const promises = ast.map(async (node) => {
|
|
16
16
|
// TODO: Improve this URL regex
|
|
17
17
|
if (node.type === 'paragraph') {
|
|
@@ -25,55 +25,38 @@ export default async function mutateMarkdownAST(ast, cache, webmentions) {
|
|
|
25
25
|
node.type = 'url';
|
|
26
26
|
const { url } = node.children[0];
|
|
27
27
|
node.url = url
|
|
28
|
-
if (!cache[node.url]) {
|
|
29
|
-
try {
|
|
30
|
-
const urlObject = new URL(url);
|
|
31
|
-
const response = await urlMetadata(urlObject.href, {
|
|
32
|
-
includeResponseBody: true,
|
|
33
|
-
ensureSecureImageRequest: true
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
console.log(!!webmentions)
|
|
37
|
-
console.log({webmentions})
|
|
38
|
-
console.log(webmentions.find(webmention => webmention.target === url))
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if(webmentions && !webmentions.find(webmention => webmention.target === url)) {
|
|
42
|
-
webmentions.push({
|
|
43
|
-
target: url,
|
|
44
|
-
status: "new"
|
|
45
|
-
})
|
|
46
|
-
} else if (webmentions) {
|
|
47
|
-
const webmention = webmentions.find(webmention => webmention.target === url)
|
|
48
|
-
if(webmention.status === "new") {
|
|
49
|
-
webmention.status = await sendWebmention(response.responseBody)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
28
|
|
|
53
|
-
|
|
54
|
-
image: response['og:image'],
|
|
55
|
-
ogURL: response['og:url'],
|
|
56
|
-
canonicalURL: response.canonical,
|
|
57
|
-
title: response.title,
|
|
58
|
-
ogTitle: response['og:title'],
|
|
59
|
-
author: response.author,
|
|
60
|
-
description: response.description
|
|
61
|
-
};
|
|
29
|
+
console.log("It's a URL")
|
|
62
30
|
|
|
31
|
+
const { metadata } = await getMetadata({ cache, url })
|
|
63
32
|
|
|
33
|
+
console.log({metadata})
|
|
34
|
+
console.log("Hey there!")
|
|
35
|
+
console.log({webmentions})
|
|
64
36
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
37
|
+
node.metadata = metadata;
|
|
38
|
+
node.value = url;
|
|
39
|
+
delete node.children;
|
|
68
40
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
41
|
+
try {
|
|
42
|
+
console.log("Looking for webmentions")
|
|
43
|
+
if (webmentions && !webmentions.find(webmention => webmention.target === url)) {
|
|
44
|
+
console.log("Found new page")
|
|
45
|
+
webmentions.push({
|
|
46
|
+
target: url,
|
|
47
|
+
status: "new"
|
|
48
|
+
})
|
|
49
|
+
} else if (webmentions) {
|
|
50
|
+
console.log("Found new webmention")
|
|
51
|
+
const webmention = webmentions.find(webmention => webmention.target === url)
|
|
52
|
+
if (webmention.status === "new" || webmention.status === "failure" || webmention.status === "429") {
|
|
53
|
+
console.log("Sending webmention")
|
|
54
|
+
webmention.status = await sendWebmention({ endpoint: metadata.webmentionEndpoint, target: webmention.target, source: pageURL })
|
|
55
|
+
}
|
|
72
56
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.log({ webmentionError: error })
|
|
75
59
|
}
|
|
76
|
-
|
|
77
60
|
} else if (node.children[0].type === 'image') {
|
|
78
61
|
node.type = 'figure';
|
|
79
62
|
if (node?.children[1]?.type === 'text') {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import urlMetadata from 'url-metadata';
|
|
2
|
-
import { regexPatterns, isObject, parseDate, sendWebmention } from '.';
|
|
2
|
+
import { regexPatterns, isObject, parseDate, sendWebmention, getMetadata } from '.';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Description
|
|
@@ -24,7 +24,7 @@ function imputeType(value) {
|
|
|
24
24
|
return 'other';
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export default async function mutateMarkdownFrontmatter(frontmatter, cache, webmentions) {
|
|
27
|
+
export default async function mutateMarkdownFrontmatter(frontmatter, cache, webmentions, pageURL) {
|
|
28
28
|
const keys = Object.keys(frontmatter);
|
|
29
29
|
|
|
30
30
|
const promises = keys.map(async (key) => {
|
|
@@ -74,62 +74,32 @@ export default async function mutateMarkdownFrontmatter(frontmatter, cache, webm
|
|
|
74
74
|
break;
|
|
75
75
|
}
|
|
76
76
|
case 'url': {
|
|
77
|
+
const { metadata } = await getMetadata({
|
|
78
|
+
cache,
|
|
79
|
+
url: input
|
|
80
|
+
})
|
|
77
81
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
ensureSecureImageRequest: true
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const selectedMetadata = {
|
|
87
|
-
url: metadata.url,
|
|
88
|
-
canonical: metadata.canonical,
|
|
89
|
-
title: metadata.title,
|
|
90
|
-
image: metadata.image,
|
|
91
|
-
favicons: url.favicons,
|
|
92
|
-
og_url: url['og:url'],
|
|
93
|
-
og_title: url['og:title'],
|
|
94
|
-
og_description: url['og:description'],
|
|
95
|
-
og_site_name: url['og:side_name'],
|
|
96
|
-
og_image: url['og:image']
|
|
97
|
-
};
|
|
82
|
+
frontmatter[key] = {
|
|
83
|
+
type: 'url',
|
|
84
|
+
output: metadata || input,
|
|
85
|
+
input
|
|
86
|
+
};
|
|
98
87
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
88
|
+
try {
|
|
89
|
+
if (webmentions && !webmentions.find(webmention => webmention.target === input)) {
|
|
90
|
+
webmentions.push({
|
|
91
|
+
target: input,
|
|
92
|
+
status: "new"
|
|
93
|
+
})
|
|
94
|
+
} else if (webmentions) {
|
|
95
|
+
const webmention = webmentions.find(webmention => webmention.target === input)
|
|
96
|
+
if (webmention.status === "new") {
|
|
97
|
+
webmention.status = await sendWebmention({ endpoint: metadata.webmentionEndpoint, target: webmention.target, source: pageURL })
|
|
109
98
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
cache[input] = selectedMetadata;
|
|
113
|
-
|
|
114
|
-
frontmatter[key] = {
|
|
115
|
-
type: 'url',
|
|
116
|
-
output: selectedMetadata,
|
|
117
|
-
input
|
|
118
|
-
};
|
|
119
|
-
} catch (e) {
|
|
120
|
-
console.error(`Error on URL in frontmatter: ${frontmatter[key]}`);
|
|
121
|
-
frontmatter[key] = {
|
|
122
|
-
type: 'string',
|
|
123
|
-
output: input,
|
|
124
|
-
input
|
|
125
|
-
};
|
|
126
99
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
output: cache[input],
|
|
131
|
-
input
|
|
132
|
-
};
|
|
100
|
+
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.log({ webmentionsError: error })
|
|
133
103
|
}
|
|
134
104
|
break;
|
|
135
105
|
}
|
|
@@ -147,7 +147,7 @@ async function readFile(file, parents, cache, folderPath, hidden, publishedData)
|
|
|
147
147
|
filePublishedData = publishedData.at(-1)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
const { ast, frontmatter, imputedProperties } = await readMarkdownFile(filePath, cache, filePublishedData);
|
|
150
|
+
const { ast, frontmatter, imputedProperties } = await readMarkdownFile(filePath, cache, filePublishedData, url);
|
|
151
151
|
|
|
152
152
|
const loadTime = (performance.now() - startLoad).toFixed(2);
|
|
153
153
|
// console.log(`📄 ${shortPath} (${loadTime}ms)`);
|
|
@@ -110,7 +110,7 @@ function imputeTitleFromAST(ast) {
|
|
|
110
110
|
* @returns {Promise<ParsedMarkdown>}
|
|
111
111
|
* @throws {Error} Will throw an error if the file cannot be read or parsed.
|
|
112
112
|
*/
|
|
113
|
-
export default async function readMarkdownFile(filePath, cache, publishedData) {
|
|
113
|
+
export default async function readMarkdownFile(filePath, cache, publishedData, url) {
|
|
114
114
|
const fileName = path.basename(filePath.slice(0, -3));
|
|
115
115
|
|
|
116
116
|
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
@@ -170,7 +170,7 @@ export default async function readMarkdownFile(filePath, cache, publishedData) {
|
|
|
170
170
|
|
|
171
171
|
const webmentions = publishedData?.webmentions
|
|
172
172
|
|
|
173
|
-
const promises = [mutateMarkdownAST(ast.children, cache, webmentions)];
|
|
173
|
+
const promises = [mutateMarkdownAST(ast.children, cache, webmentions, url)];
|
|
174
174
|
|
|
175
175
|
// Don't mutate frontmatter on the settings pages
|
|
176
176
|
if (!filePath.endsWith('settings.md'))
|
|
@@ -1,28 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export default async function sendWebmention(body) {
|
|
1
|
+
export default async function sendWebmention({ endpoint, source, target }) {
|
|
5
2
|
try {
|
|
6
|
-
|
|
7
|
-
unpairedTags: ["!doctype", "meta", "link", "hr", "br", "img"],
|
|
8
|
-
ignoreAttributes: false,
|
|
9
|
-
stopNodes: ["*.pre", "*.script"],
|
|
10
|
-
processEntities: true,
|
|
11
|
-
htmlEntities: true
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
let parsedData = parser.parse(body)
|
|
15
|
-
const webmentionEndpoint = parsedData?.html?.head?.link?.find(link => {
|
|
16
|
-
return link["@_rel"] === "webmention"
|
|
17
|
-
})?.["@_href"]
|
|
18
|
-
|
|
19
|
-
if (webmentionEndpoint) {
|
|
3
|
+
if (endpoint) {
|
|
20
4
|
const params = new URLSearchParams()
|
|
21
|
-
params.append('source',
|
|
22
|
-
params.append('target',
|
|
5
|
+
params.append('source', source)
|
|
6
|
+
params.append('target', target)
|
|
23
7
|
|
|
24
8
|
|
|
25
|
-
const response = await fetch(
|
|
9
|
+
const response = await fetch(endpoint, {
|
|
26
10
|
method: "POST",
|
|
27
11
|
body: params,
|
|
28
12
|
headers: {
|
|
@@ -30,16 +14,21 @@ export default async function sendWebmention(body) {
|
|
|
30
14
|
}
|
|
31
15
|
})
|
|
32
16
|
|
|
17
|
+
console.log({
|
|
18
|
+
webmentionResponse: await response.json()
|
|
19
|
+
})
|
|
20
|
+
|
|
33
21
|
if(response.status === 429) {
|
|
34
22
|
return "429"
|
|
35
23
|
} else if (response.status >= 200 && response.status < 300) {
|
|
36
24
|
return "success"
|
|
37
25
|
} else {
|
|
26
|
+
console.log({ failure: await response.json() })
|
|
38
27
|
return "failure"
|
|
39
28
|
}
|
|
40
29
|
}
|
|
41
|
-
} catch (
|
|
42
|
-
console.log(
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.log({ error })
|
|
43
32
|
return "error"
|
|
44
33
|
}
|
|
45
34
|
}
|