@indiekit/endpoint-syndicate
Version:
Syndication endpoint for Indiekit. Provides an endpoint you can ping to check that recently published posts have been posted to configured syndication targets.
99 lines (84 loc) • 3.15 kB
JavaScript
import { IndiekitError } from "@indiekit/error";
import { findBearerToken } from "../token.js";
import { getPostData, syndicateToTargets } from "../utils.js";
export const syndicateController = {
async post(request, response, next) {
try {
const { application, publication } = request.app.locals;
const bearerToken = findBearerToken(request);
const sourceUrl =
request.query.source_url || request.body?.syndication?.source_url;
const redirectUri =
request.query.redirect_uri || request.body?.syndication?.redirect_uri;
const postsCollection = application?.collections?.get("posts");
if (!postsCollection) {
throw IndiekitError.notImplemented(
response.locals.__("NotImplementedError.database"),
);
}
// Get syndication targets
const { syndicationTargets } = publication;
if (syndicationTargets.length === 0) {
return response.json({
success: "OK",
success_description: "No syndication targets have been configured",
});
}
// Get post data
const postData = await getPostData(postsCollection, sourceUrl);
if (!postData && sourceUrl) {
return response.json({
success: "OK",
success_description: `No post record available for ${sourceUrl}`,
});
}
if (!postData) {
return response.json({
success: "OK",
success_description: "No posts awaiting syndication",
});
}
// Syndicate to targets
const { failedTargets, syndicatedUrls } = await syndicateToTargets(
publication,
postData.properties,
);
// Update post with syndicated URL(s) and remaining syndication target(s)
const micropubResponse = await fetch(application.micropubEndpoint, {
method: "POST",
headers: {
accept: "application/json",
authorization: `Bearer ${bearerToken}`,
"content-type": "application/json",
},
body: JSON.stringify({
action: "update",
url: postData.properties.url,
...(!failedTargets && { delete: ["mp-syndicate-to"] }),
replace: {
...(failedTargets && { "mp-syndicate-to": failedTargets }),
...(syndicatedUrls && { syndication: syndicatedUrls }),
},
}),
});
if (!micropubResponse.ok) {
throw await IndiekitError.fromFetch(micropubResponse);
}
/** @type {object} */
const body = await micropubResponse.json();
// Include failed syndication targets in ‘success’ response
if (failedTargets) {
body.success_description +=
". The following target(s) did not return a URL: " +
failedTargets.join(" ");
}
if (redirectUri && redirectUri.startsWith("/")) {
const message = encodeURIComponent(body.success_description);
return response.redirect(`${redirectUri}?success=${message}`);
}
return response.status(micropubResponse.status).json(body);
} catch (error) {
next(error);
}
},
};