docs/_data/webmentions.cjs
const fs = require('fs');
const unionBy = require('lodash/unionBy');
const domain = 'daily-dev-tips.com';
// Load .env variables with dotenv
require('dotenv').config();
// Define Cache Location and API Endpoint
const CACHE_DIR = '_cache';
const API = 'https://webmention.io/api';
const TOKEN = process.env.WEBMENTION_IO_TOKEN;
async function fetchWebmentions(since, perPage = 10000) {
if (!domain) {
// If we dont have a domain name, abort
console.warn('>>> unable to fetch webmentions: no domain name specified in site.json');
return false;
}
if (!TOKEN) {
// If we dont have a domain access token, abort
console.warn('>>> unable to fetch webmentions: no access token specified in environment.');
return false;
}
let url = `${API}/mentions.jf2?domain=${domain}&token=${TOKEN}&per-page=${perPage}`;
if (since) url += `&since=${since}`;
const fetch = await import('node-fetch');
const response = await fetch(url);
if (response.ok) {
const feed = await response.json();
console.log(`>>> ${feed.children.length} new webmentions fetched from ${API}`);
return feed;
}
return null;
}
// Merge fresh webmentions with cached entries, unique per id
function mergeWebmentions(a, b) {
return unionBy(a.children, b.children, 'wm-id');
}
// save combined webmentions in cache file
function writeToCache(data) {
const filePath = `${CACHE_DIR}/webmentions.json`;
const fileContent = JSON.stringify(data, null, 2);
// create cache folder if it doesnt exist already
if (!fs.existsSync(CACHE_DIR)) {
fs.mkdirSync(CACHE_DIR);
}
// write data to cache json file
fs.writeFile(filePath, fileContent, err => {
if (err) throw err;
console.log(`>>> webmentions cached to ${filePath}`);
})
}
// get cache contents from json file
function readFromCache() {
const filePath = `${CACHE_DIR}/webmentions.json`;
if (fs.existsSync(filePath)) {
const cacheFile = fs.readFileSync(filePath);
const cachedWebmentions = JSON.parse(cacheFile);
// merge cache with wms for legacy domain
return {
lastFetched: cachedWebmentions.lastFetched,
children: cachedWebmentions.children
};
}
// no cache found.
return {
lastFetched: null,
children: {}
};
}
module.exports = async function () {
const cache = readFromCache();
if (cache.children.length) {
console.log(`>>> ${cache.children.length} webmentions loaded from cache`);
}
// Only fetch new mentions in production
if (process.env.NODE_ENV === 'production') {
const feed = await fetchWebmentions(cache.lastFetched);
if (feed) {
const webmentions = {
lastFetched: new Date().toISOString(),
children: mergeWebmentions(cache, feed)
}
writeToCache(webmentions);
return webmentions;
}
}
return cache;
}