fix: fetch remote AP object in search resolve when not in local timeline
Deploy Indiekit Server / deploy (push) Successful in 1m21s

The v1 ap-search-url-resolve patch only found posts already stored in
ap_timeline. Threads posts (and any not yet federated here) were never
there, so boost/like still failed with "Failed to load post."

New ap-search-url-resolve-remote patch: when the local lookup misses,
fetch the AP object remotely via lookupWithSecurity → extractObjectData
→ addTimelineItem, then return the stored status to the client. This
makes like/boost work for any public post reachable from the federation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sven
2026-04-15 21:15:19 +02:00
parent a0ff51e289
commit a0ba049b6e
+57
View File
@@ -219,6 +219,63 @@ for (const f of SEARCH_CANDIDATES) {
}
if (!searchDone) console.log(`[postinstall] ${SCRIPT}: ap-search-url-resolve — no target file found or no changes`);
// ── patch-ap-search-url-resolve-remote: fetch AP object when not in local timeline ──
// The v1 patch only looked up posts already in ap_timeline. Posts from Threads
// (or any instance not yet federated to this server) were never stored there, so
// the resolve block returned nothing. This patch adds an `else if` that fetches
// the AP object remotely via lookupWithSecurity, stores it via extractObjectData +
// addTimelineItem, then returns it. This makes like/boost work on any public post,
// not just ones already in the local timeline.
const SEARCH_REMOTE_MARKER = "// [patch] ap-search-url-resolve-remote";
// Anchor: the two consecutive closing braces at the end of the v1 URL-resolve block.
// They appear exactly once in the patched search.js.
const SEARCH_REMOTE_OLD = ` } // [patch] ap-search-url-resolve
} // [patch] ap-search-url-resolve`;
const SEARCH_REMOTE_NEW = [
` } else if (pluginOptions.federation) { ${SEARCH_REMOTE_MARKER}`,
` try { ${SEARCH_REMOTE_MARKER}`,
` const { lookupWithSecurity } = await import("../../lookup-helpers.js"); ${SEARCH_REMOTE_MARKER}`,
` const { extractObjectData } = await import("../../timeline-store.js"); ${SEARCH_REMOTE_MARKER}`,
` const { addTimelineItem } = await import("../../storage/timeline.js"); ${SEARCH_REMOTE_MARKER}`,
` const _rCtx = pluginOptions.federation.createContext(new URL(pluginOptions.publicationUrl), { handle: pluginOptions.handle, publicationUrl: pluginOptions.publicationUrl }); ${SEARCH_REMOTE_MARKER}`,
` const _rDl = await _rCtx.getDocumentLoader({ identifier: pluginOptions.handle }); ${SEARCH_REMOTE_MARKER}`,
` const _rObj = await lookupWithSecurity(_rCtx, new URL(query), { documentLoader: _rDl }); ${SEARCH_REMOTE_MARKER}`,
` if (_rObj) { ${SEARCH_REMOTE_MARKER}`,
` const _rData = await extractObjectData(_rObj, { documentLoader: _rDl }); ${SEARCH_REMOTE_MARKER}`,
` const _rStored = await addTimelineItem(collections, _rData); ${SEARCH_REMOTE_MARKER}`,
` if (_rStored) { ${SEARCH_REMOTE_MARKER}`,
` results.statuses.push(serializeStatus(_rStored, { ${SEARCH_REMOTE_MARKER}`,
` baseUrl, favouritedIds: new Set(), rebloggedIds: new Set(), ${SEARCH_REMOTE_MARKER}`,
` bookmarkedIds: new Set(), pinnedIds: new Set(), ${SEARCH_REMOTE_MARKER}`,
` })); ${SEARCH_REMOTE_MARKER}`,
` } ${SEARCH_REMOTE_MARKER}`,
` } ${SEARCH_REMOTE_MARKER}`,
` } catch (_rErr) { ${SEARCH_REMOTE_MARKER}`,
` console.warn(\`[Mastodon API] search resolve remote fetch failed for \${query}: \${_rErr.message}\`); ${SEARCH_REMOTE_MARKER}`,
` } ${SEARCH_REMOTE_MARKER}`,
` } // [patch] ap-search-url-resolve`,
` } // [patch] ap-search-url-resolve`,
].join("\n");
let searchRemoteDone = false;
for (const f of SEARCH_CANDIDATES) {
if (!(await fileExists(f))) continue;
const src = await readFile(f, "utf8");
if (src.includes(SEARCH_REMOTE_MARKER)) {
console.log(`[postinstall] ${SCRIPT}: ap-search-url-resolve-remote already applied in ${f}`);
searchRemoteDone = true; break;
}
if (!src.includes(SEARCH_REMOTE_OLD)) {
console.warn(`[postinstall] ${SCRIPT}: ap-search-url-resolve-remote — anchor not found in ${f} (v1 patch not applied?)`);
continue;
}
await writeFile(f, src.replace(SEARCH_REMOTE_OLD, SEARCH_REMOTE_NEW), "utf8");
console.log(`[postinstall] ${SCRIPT}: applied ap-search-url-resolve-remote to ${f}`);
total++; searchRemoteDone = true; break;
}
if (!searchRemoteDone) console.log(`[postinstall] ${SCRIPT}: ap-search-url-resolve-remote — no target file found or no changes`);
// ── patch-ap-resolve-actor-timeout: cap actor lookup at 8 s + log failures ───
// When Mastodon client clicks a @mention handle, /api/v1/accounts/lookup calls
// resolveRemoteAccount → lookupWithSecurity → ctx.lookupObject (no timeout).