UNPKG

ghost

Version:

The professional publishing platform

72 lines (65 loc) 2.19 kB
const oembedService = require('../oembed'); module.exports = class WebmentionMetadata { /** * Helpers that change the URL for which metadata for a given external resource is fetched. Return undefined to now handle the URL. * @type {((url: URL) => URL|undefined)[]} */ #mappers = []; /** * @param {(url: URL) => URL|undefined} mapper */ addMapper(mapper) { this.#mappers.push(mapper); } /** * * @param {URL} url */ #getMappedUrl(url) { for (const mapper of this.#mappers) { const mappedUrl = mapper(url); if (mappedUrl) { return this.#getMappedUrl(mappedUrl); } } return url; } /** * @param {URL} url * @returns {Promise<import('./MentionsAPI').WebmentionMetadata>} */ async fetch(url) { const mappedUrl = this.#getMappedUrl(url); const data = await oembedService.fetchOembedDataFromUrl(mappedUrl.href, 'mention', { timeout: 15000, retry: { // Only retry on network issues, or specific HTTP status codes limit: 3 } }); const result = { siteTitle: data.metadata.publisher, title: data.metadata.title, excerpt: data.metadata.description, author: data.metadata.author, image: data.metadata.thumbnail ? new URL(data.metadata.thumbnail) : null, favicon: data.metadata.icon ? new URL(data.metadata.icon) : null, body: data.body, contentType: data.contentType }; if (mappedUrl.href !== url.href) { // Still need to fetch body and contentType separately now // For verification const {body, contentType} = await oembedService.fetchPageHtml(url, { timeout: 15000, retry: { // Only retry on network issues, or specific HTTP status codes limit: 3 } }); result.body = body; result.contentType = contentType; } return result; } };