diff --git a/scripts/patch-ap-mastodon-misc.mjs b/scripts/patch-ap-mastodon-misc.mjs index d1eb40c8..04115dcd 100644 --- a/scripts/patch-ap-mastodon-misc.mjs +++ b/scripts/patch-ap-mastodon-misc.mjs @@ -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).