fix: resolve posts by AP URL in search when resolve=true
Deploy Indiekit Server / deploy (push) Successful in 1m14s
Deploy Indiekit Server / deploy (push) Successful in 1m14s
Phanpy calls GET /api/v2/search?q=<post_url>&resolve=true&type=statuses before liking or boosting a remote post. The search endpoint only did content-text regex matching — never found posts by URL — so it returned statuses:[] and Phanpy showed "Failed to load post." Patch ap-search-url-resolve adds a URL-based ap_timeline lookup (by uid or url) when resolve=true and the query starts with "http", covering Threads posts and any other AP posts already in the timeline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -152,4 +152,71 @@ for (const f of ACCOUNTS_CANDIDATES) {
|
|||||||
}
|
}
|
||||||
if (!hashDone) console.log(`[postinstall] ${SCRIPT}: ap-accounts-id-hash — no target file found or no changes`);
|
if (!hashDone) console.log(`[postinstall] ${SCRIPT}: ap-accounts-id-hash — no target file found or no changes`);
|
||||||
|
|
||||||
|
// ── patch-ap-search-url-resolve: resolve posts by URL when resolve=true ────────
|
||||||
|
// Phanpy calls GET /api/v2/search?q=<post_url>&resolve=true&type=statuses before
|
||||||
|
// liking/boosting a remote post. The search endpoint only did content-text regex
|
||||||
|
// search — never found posts by URL → statuses:[] → "Failed to load post" error.
|
||||||
|
// Fix: when resolve=true and query is a URL, look up ap_timeline by uid/url first.
|
||||||
|
// Two targeted replacements:
|
||||||
|
// A) inject URL-resolve block before the content search (unique anchor: "results.statuses = items.map")
|
||||||
|
// B) change assignment to push so existing array stays intact
|
||||||
|
|
||||||
|
const SEARCH_MARKER = "// [patch] ap-search-url-resolve";
|
||||||
|
const SEARCH_CANDIDATES = apPath("lib/mastodon/routes/search.js");
|
||||||
|
|
||||||
|
// Replacement A: inject URL-resolve block + switch assignment to push
|
||||||
|
// Anchor chosen because it is unique in search.js.
|
||||||
|
const SEARCH_OLD_A = " results.statuses = items.map((item) =>";
|
||||||
|
const SEARCH_NEW_A = [
|
||||||
|
" // URL resolve: find post by AP URL before content search. " + SEARCH_MARKER,
|
||||||
|
" if (resolve && query.startsWith(\"http\")) { " + SEARCH_MARKER,
|
||||||
|
" const resolvedItem = await collections.ap_timeline.findOne({ " + SEARCH_MARKER,
|
||||||
|
" isContext: { $ne: true }, " + SEARCH_MARKER,
|
||||||
|
" $or: [{ uid: query }, { url: query }], " + SEARCH_MARKER,
|
||||||
|
" }); " + SEARCH_MARKER,
|
||||||
|
" if (resolvedItem) { " + SEARCH_MARKER,
|
||||||
|
" results.statuses.push(serializeStatus(resolvedItem, { " + SEARCH_MARKER,
|
||||||
|
" baseUrl, favouritedIds: new Set(), rebloggedIds: new Set(), " + SEARCH_MARKER,
|
||||||
|
" bookmarkedIds: new Set(), pinnedIds: new Set(), " + SEARCH_MARKER,
|
||||||
|
" })); " + SEARCH_MARKER,
|
||||||
|
" } " + SEARCH_MARKER,
|
||||||
|
" } " + SEARCH_MARKER,
|
||||||
|
" results.statuses.push(...items.map((item) =>",
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
// Replacement B: close the push call (was ` );` → ` ));`)
|
||||||
|
// Unique because it is immediately followed by the closing brace + Hashtag comment.
|
||||||
|
const SEARCH_OLD_B = " }),\n );\n }\n\n // ─── Hashtag";
|
||||||
|
const SEARCH_NEW_B = " }),\n ));\n }\n\n // ─── Hashtag";
|
||||||
|
|
||||||
|
let searchDone = false;
|
||||||
|
for (const f of SEARCH_CANDIDATES) {
|
||||||
|
if (!(await fileExists(f))) continue;
|
||||||
|
const src = await readFile(f, "utf8");
|
||||||
|
if (src.includes(SEARCH_MARKER)) {
|
||||||
|
console.log(`[postinstall] ${SCRIPT}: ap-search-url-resolve already applied in ${f}`);
|
||||||
|
searchDone = true; break;
|
||||||
|
}
|
||||||
|
let updated = src;
|
||||||
|
let changed = false;
|
||||||
|
if (updated.includes(SEARCH_OLD_A)) {
|
||||||
|
updated = updated.replace(SEARCH_OLD_A, SEARCH_NEW_A);
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
console.warn(`[postinstall] ${SCRIPT}: ap-search-url-resolve A — anchor not found in ${f}`);
|
||||||
|
}
|
||||||
|
if (updated.includes(SEARCH_OLD_B)) {
|
||||||
|
updated = updated.replace(SEARCH_OLD_B, SEARCH_NEW_B);
|
||||||
|
} else {
|
||||||
|
console.warn(`[postinstall] ${SCRIPT}: ap-search-url-resolve B — closing anchor not found in ${f}`);
|
||||||
|
changed = false; // both must succeed
|
||||||
|
}
|
||||||
|
if (changed && updated !== src) {
|
||||||
|
await writeFile(f, updated, "utf8");
|
||||||
|
console.log(`[postinstall] ${SCRIPT}: applied ap-search-url-resolve to ${f}`);
|
||||||
|
total++; searchDone = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!searchDone) console.log(`[postinstall] ${SCRIPT}: ap-search-url-resolve — no target file found or no changes`);
|
||||||
|
|
||||||
console.log(`[postinstall] ${SCRIPT}: done (${total} patch(es) applied)`);
|
console.log(`[postinstall] ${SCRIPT}: done (${total} patch(es) applied)`);
|
||||||
|
|||||||
Reference in New Issue
Block a user