fix(patches): extend internal URL rewrite to microsub, activitypub, and @rmdes posts

The localhost rewrite only covered endpoint-syndicate and endpoint-share.
Add coverage for 4 more files that also self-fetch via the public URL:

- @rmdes/indiekit-endpoint-microsub reader.js (2 fetch calls)
- @rmdes/indiekit-endpoint-activitypub compose.js (2 fetch calls)
- @rmdes/indiekit-endpoint-posts utils.js and endpoint.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sven
2026-03-16 20:35:50 +01:00
parent e3765948e5
commit a2e2764108
+140 -20
View File
@@ -1,13 +1,14 @@
/** /**
* Patch: rewrite micropub self-fetch URLs to localhost in endpoint-syndicate * Patch: rewrite micropub/microsub self-fetch URLs to localhost.
* and endpoint-share.
* *
* Same issue as endpoint-posts: behind a reverse proxy (nginx in a separate * Behind a reverse proxy (nginx in a separate FreeBSD jail), Node can't
* FreeBSD jail), Node can't reach its own public HTTPS URL because port 443 * reach its own public HTTPS URL because port 443 only exists on the
* only exists on the nginx jail. * nginx jail. Rewrites self-referential fetch URLs to use
*
* Rewrites fetch(application.micropubEndpoint, ...) to use
* http://localhost:<PORT> instead. * http://localhost:<PORT> instead.
*
* Covers: endpoint-syndicate, endpoint-share, endpoint-microsub reader,
* endpoint-activitypub compose, endpoint-posts utils, and the @rmdes
* endpoint-posts endpoint.js copy.
*/ */
import { access, readFile, writeFile } from "node:fs/promises"; import { access, readFile, writeFile } from "node:fs/promises";
@@ -29,20 +30,136 @@ function _toInternalUrl(url) {
} }
`; `;
// Each target defines one or more string replacements in a single file.
// The helper block is inserted after the last import statement.
const targets = [ const targets = [
// --- endpoint-syndicate ---
{ {
paths: [ paths: [
"node_modules/@indiekit/endpoint-syndicate/lib/controllers/syndicate.js", "node_modules/@indiekit/endpoint-syndicate/lib/controllers/syndicate.js",
], ],
oldSnippet: ` const micropubResponse = await fetch(application.micropubEndpoint, {`, replacements: [
newSnippet: ` const micropubResponse = await fetch(_toInternalUrl(application.micropubEndpoint), {`, {
old: ` const micropubResponse = await fetch(application.micropubEndpoint, {`,
new: ` const micropubResponse = await fetch(_toInternalUrl(application.micropubEndpoint), {`,
}, },
],
},
// --- endpoint-share ---
{ {
paths: [ paths: [
"node_modules/@indiekit/endpoint-share/lib/controllers/share.js", "node_modules/@indiekit/endpoint-share/lib/controllers/share.js",
], ],
oldSnippet: ` const micropubResponse = await fetch(application.micropubEndpoint, {`, replacements: [
newSnippet: ` const micropubResponse = await fetch(_toInternalUrl(application.micropubEndpoint), {`, {
old: ` const micropubResponse = await fetch(application.micropubEndpoint, {`,
new: ` const micropubResponse = await fetch(_toInternalUrl(application.micropubEndpoint), {`,
},
],
},
// --- microsub reader: URL construction + 2 fetch calls ---
{
paths: [
"node_modules/@rmdes/indiekit-endpoint-microsub/lib/controllers/reader.js",
],
replacements: [
// getSyndicationTargets: rewrite the built micropubUrl
{
old: ` const micropubUrl = micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href;
const configUrl = \`\${micropubUrl}?q=config\`;
const configResponse = await fetch(configUrl, {`,
new: ` const micropubUrl = _toInternalUrl(micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href);
const configUrl = \`\${micropubUrl}?q=config\`;
const configResponse = await fetch(configUrl, {`,
},
// createPost: rewrite the built micropubUrl
{
old: ` const micropubUrl = micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href;`,
new: ` const micropubUrl = _toInternalUrl(micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href);`,
},
],
},
// --- activitypub compose: URL construction + 2 fetch calls ---
{
paths: [
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/controllers/compose.js",
],
replacements: [
// getSyndicationTargets
{
old: ` const micropubUrl = micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href;
const configUrl = \`\${micropubUrl}?q=config\`;
const configResponse = await fetch(configUrl, {`,
new: ` const micropubUrl = _toInternalUrl(micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href);
const configUrl = \`\${micropubUrl}?q=config\`;
const configResponse = await fetch(configUrl, {`,
},
// post handler: rewrite the built micropubUrl
{
old: ` const micropubUrl = micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href;`,
new: ` const micropubUrl = _toInternalUrl(micropubEndpoint.startsWith("http")
? micropubEndpoint
: new URL(micropubEndpoint, application.url).href);`,
},
],
},
// --- @rmdes endpoint-posts utils.js: URL built from micropubEndpoint ---
{
paths: [
"node_modules/@rmdes/indiekit-endpoint-posts/lib/utils.js",
],
replacements: [
{
old: ` const micropubUrl = new URL(micropubEndpoint);`,
new: ` const micropubUrl = new URL(_toInternalUrl(micropubEndpoint));`,
},
],
},
// --- @rmdes endpoint-posts endpoint.js (separate copy from @indiekit override) ---
{
paths: [
"node_modules/@rmdes/indiekit-endpoint-posts/lib/endpoint.js",
],
replacements: [
{
old: ` const endpointResponse = await fetch(url, {
headers: {
accept: "application/json",
authorization: \`Bearer \${accessToken}\`,
},
});`,
new: ` const endpointResponse = await fetch(_toInternalUrl(url), {
headers: {
accept: "application/json",
authorization: \`Bearer \${accessToken}\`,
},
});`,
},
{
old: ` const endpointResponse = await fetch(url, {
method: "POST",`,
new: ` const endpointResponse = await fetch(_toInternalUrl(url), {
method: "POST",`,
},
],
}, },
]; ];
@@ -67,22 +184,23 @@ for (const target of targets) {
continue; continue;
} }
if (!source.includes(target.oldSnippet)) { // Check that all old snippets exist before patching
console.warn(`[postinstall] micropub-fetch-internal-url: snippet not found in ${filePath} — skipping`); const allFound = target.replacements.every((r) => source.includes(r.old));
if (!allFound) {
const missing = target.replacements
.filter((r) => !source.includes(r.old))
.map((r) => r.old.slice(0, 60) + "...");
console.warn(`[postinstall] micropub-fetch-internal-url: snippet not found in ${filePath} — skipping (${missing.length} missing)`);
continue; continue;
} }
// Insert helper block after the last import statement. // Insert helper block after the last import statement
// Find the last "from" keyword followed by a string and semicolon,
// which marks the end of the last import.
const importEndPattern = /;\s*\n/g;
const allImportMatches = [...source.matchAll(/^import\s/gm)]; const allImportMatches = [...source.matchAll(/^import\s/gm)];
if (allImportMatches.length === 0) { if (allImportMatches.length === 0) {
console.warn(`[postinstall] micropub-fetch-internal-url: no imports found in ${filePath} — skipping`); console.warn(`[postinstall] micropub-fetch-internal-url: no imports found in ${filePath} — skipping`);
continue; continue;
} }
// Find the semicolon+newline that ends the last import block
const lastImportStart = allImportMatches.at(-1).index; const lastImportStart = allImportMatches.at(-1).index;
const afterLastImport = source.slice(lastImportStart); const afterLastImport = source.slice(lastImportStart);
const fromMatch = afterLastImport.match(/from\s+["'][^"']+["']\s*;\s*\n/); const fromMatch = afterLastImport.match(/from\s+["'][^"']+["']\s*;\s*\n/);
@@ -97,8 +215,10 @@ for (const target of targets) {
let updated = beforeHelper + "\n" + helperBlock + "\n" + afterHelper; let updated = beforeHelper + "\n" + helperBlock + "\n" + afterHelper;
// Now replace the fetch call // Apply all replacements
updated = updated.replace(target.oldSnippet, target.newSnippet); for (const r of target.replacements) {
updated = updated.replace(r.old, r.new);
}
await writeFile(filePath, updated, "utf8"); await writeFile(filePath, updated, "utf8");
console.log(`[postinstall] Patched micropub-fetch-internal-url in ${filePath}`); console.log(`[postinstall] Patched micropub-fetch-internal-url in ${filePath}`);