82319432db
Deploy Indiekit Server / deploy (push) Successful in 1m18s
fetchOpenGraphData() used _toInternalUrl() to rewrite own-blog URLs to the Node.js jail, which serves Indiekit admin (requiring auth) rather than the static Eleventy output. This caused og:title "Indiekit Authenticate" to end up as the Bluesky link card title. New patch (patch-bluesky-og-own-post-title) skips fetchOpenGraphData() for own-domain post URLs and instead derives title/description from the JF2 properties passed by the caller. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
127 lines
4.7 KiB
JavaScript
127 lines
4.7 KiB
JavaScript
/**
|
|
* Patch @rmdes/indiekit-syndicator-bluesky so that own-domain post URLs
|
|
* don't fetch OG metadata via the internal URL.
|
|
*
|
|
* Problem: fetchOpenGraphData() rewrites own-blog URLs to the Node.js
|
|
* internal address (INTERNAL_FETCH_URL). But static Eleventy pages are
|
|
* served by nginx on the web jail — not by the Node.js process. The
|
|
* internal fetch therefore hits Indiekit's CMS which responds with an
|
|
* authentication page whose og:title is "Indiekit Authenticate", so
|
|
* Bluesky cards end up titled "Indiekit Authenticate".
|
|
*
|
|
* Fix:
|
|
* 1. createExternalEmbed() accepts optional `title`/`description` in
|
|
* options and skips fetchOpenGraphData() when they are provided for
|
|
* own-domain URLs.
|
|
* 2. post() passes title/description derived from JF2 properties when
|
|
* the embed URL is an own-domain post permalink.
|
|
*/
|
|
|
|
import { access, readFile, writeFile } from "node:fs/promises";
|
|
|
|
const MARKER = "// [patch] bluesky-og-own-post-title";
|
|
|
|
const TARGET =
|
|
"node_modules/@rmdes/indiekit-syndicator-bluesky/lib/bluesky.js";
|
|
|
|
// ── Replacement 1: createExternalEmbed — skip fetchOpenGraphData for own posts
|
|
const OLD_OG_FETCH = ` // Fetch OG metadata from HTML (needed for title/description,
|
|
// and as image fallback for external URLs)
|
|
const ogData = await fetchOpenGraphData(url);`;
|
|
|
|
const NEW_OG_FETCH = ` // Fetch OG metadata from HTML (needed for title/description,
|
|
// and as image fallback for external URLs).
|
|
// For own-domain posts skip the HTML fetch: _toInternalUrl() rewrites
|
|
// to the Node.js jail which serves Indiekit admin (auth page), not the
|
|
// static Eleventy output. Use caller-supplied title/description instead.
|
|
${MARKER}
|
|
const ogData =
|
|
isOwnPost && (options.title || options.description)
|
|
? {
|
|
title: options.title || url,
|
|
description: options.description || "",
|
|
imageUrl: null,
|
|
}
|
|
: await fetchOpenGraphData(url);`;
|
|
|
|
// ── Replacement 2: post() — pass title/description for own-domain embed URLs
|
|
const OLD_EMBED_CALL = ` // Create OG embed:
|
|
// - External URL exists → use it as OG card (permalink is in text)
|
|
// - No external URL → use permalink as OG card
|
|
let externalEmbed = null;
|
|
if (!images?.length) {
|
|
const embedUrl = externalUrl || properties.url;
|
|
if (embedUrl) {
|
|
externalEmbed = await this.createExternalEmbed(embedUrl, { me });
|
|
}
|
|
}`;
|
|
|
|
const NEW_EMBED_CALL = ` // Create OG embed:
|
|
// - External URL exists → use it as OG card (permalink is in text)
|
|
// - No external URL → use permalink as OG card
|
|
let externalEmbed = null;
|
|
if (!images?.length) {
|
|
const embedUrl = externalUrl || properties.url;
|
|
if (embedUrl) {
|
|
// For own-domain post URLs the internal fetch would hit the Indiekit
|
|
// auth page instead of the static HTML. Supply title/description from
|
|
// JF2 properties so fetchOpenGraphData() is bypassed. ${MARKER}
|
|
const _meNorm = me?.replace(/\\/+$/, "");
|
|
const _isOwnEmbed = _meNorm && embedUrl.startsWith(_meNorm);
|
|
let _embedOpts = { me };
|
|
if (_isOwnEmbed) {
|
|
const _rawText =
|
|
properties.content?.text ||
|
|
(properties.content?.html
|
|
? properties.content.html
|
|
.replace(/<[^>]+>/g, " ")
|
|
.replace(/\\s+/g, " ")
|
|
.trim()
|
|
: "");
|
|
_embedOpts.title =
|
|
(properties.name || _rawText.slice(0, 100).trim() || embedUrl);
|
|
_embedOpts.description = _rawText.slice(0, 300).trim();
|
|
}
|
|
externalEmbed = await this.createExternalEmbed(embedUrl, _embedOpts);
|
|
}
|
|
}`;
|
|
|
|
async function exists(p) {
|
|
try {
|
|
await access(p);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!(await exists(TARGET))) {
|
|
console.log(`[postinstall] bluesky-og-own-post-title: ${TARGET} not found — skipping`);
|
|
process.exit(0);
|
|
}
|
|
|
|
const source = await readFile(TARGET, "utf8");
|
|
|
|
if (source.includes(MARKER)) {
|
|
console.log("[postinstall] bluesky-og-own-post-title: already applied");
|
|
process.exit(0);
|
|
}
|
|
|
|
const missing = [];
|
|
if (!source.includes(OLD_OG_FETCH)) missing.push("OG fetch snippet");
|
|
if (!source.includes(OLD_EMBED_CALL)) missing.push("embed call snippet");
|
|
|
|
if (missing.length) {
|
|
console.warn(
|
|
`[postinstall] bluesky-og-own-post-title: snippets not found — skipping (${missing.join(", ")})`,
|
|
);
|
|
process.exit(0);
|
|
}
|
|
|
|
const updated = source
|
|
.replace(OLD_OG_FETCH, NEW_OG_FETCH)
|
|
.replace(OLD_EMBED_CALL, NEW_EMBED_CALL);
|
|
|
|
await writeFile(TARGET, updated, "utf8");
|
|
console.log(`[postinstall] Patched bluesky-og-own-post-title in ${TARGET}`);
|