4bfc6e2120
Deploy Indiekit Server / deploy (push) Successful in 1m47s
federation-setup.js calls countDocuments() with no filter 4 times for the AP followers/following collection dispatchers (pagination totalItems + counter). All are wrapped in cachedQuery() but on cache miss they run full aggregate scans. estimatedDocumentCount() reads collection metadata — O(1), no scan.
78 lines
2.6 KiB
JavaScript
78 lines
2.6 KiB
JavaScript
/**
|
||
* Patch: replace countDocuments() with estimatedDocumentCount() in
|
||
* federation-setup.js followers/following collection dispatchers.
|
||
*
|
||
* All four calls are already wrapped in cachedQuery(), but on cache miss
|
||
* countDocuments() runs a full aggregate scan. estimatedDocumentCount()
|
||
* reads collection metadata — O(1).
|
||
*
|
||
* Covers: ap_followers (×2) and ap_following (×2) in collection pagination
|
||
* and counter dispatchers.
|
||
*/
|
||
|
||
import { access, readFile, writeFile } from "node:fs/promises";
|
||
|
||
const candidates = [
|
||
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-setup.js",
|
||
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-setup.js",
|
||
];
|
||
|
||
const MARKER = "// [patch] collection-count-estimate";
|
||
|
||
const replacements = [
|
||
{
|
||
old: ` const t = await collections.ap_followers.countDocuments();
|
||
return [d, t];`,
|
||
new: ` const t = await collections.ap_followers.estimatedDocumentCount(); ${MARKER}
|
||
return [d, t];`,
|
||
},
|
||
{
|
||
old: ` return await collections.ap_followers.countDocuments();`,
|
||
new: ` return await collections.ap_followers.estimatedDocumentCount(); ${MARKER}`,
|
||
},
|
||
{
|
||
old: ` const t = await collections.ap_following.countDocuments();
|
||
return [d, t];`,
|
||
new: ` const t = await collections.ap_following.estimatedDocumentCount(); ${MARKER}
|
||
return [d, t];`,
|
||
},
|
||
{
|
||
old: ` return await collections.ap_following.countDocuments();`,
|
||
new: ` return await collections.ap_following.estimatedDocumentCount(); ${MARKER}`,
|
||
},
|
||
];
|
||
|
||
async function exists(p) {
|
||
try { await access(p); return true; } catch { return false; }
|
||
}
|
||
|
||
let patched = false;
|
||
for (const filePath of candidates) {
|
||
if (!(await exists(filePath))) continue;
|
||
let src = await readFile(filePath, "utf8");
|
||
if (src.includes(MARKER)) {
|
||
console.log(`[postinstall] patch-ap-collection-count-estimate: already applied in ${filePath}`);
|
||
patched = true;
|
||
break;
|
||
}
|
||
let changed = 0;
|
||
for (const { old, new: replacement } of replacements) {
|
||
if (src.includes(old)) {
|
||
src = src.replace(old, replacement);
|
||
changed++;
|
||
}
|
||
}
|
||
if (changed === 0) {
|
||
console.log(`[postinstall] patch-ap-collection-count-estimate: target snippets not found in ${filePath}`);
|
||
continue;
|
||
}
|
||
await writeFile(filePath, src, "utf8");
|
||
console.log(`[postinstall] patch-ap-collection-count-estimate: applied ${changed}/4 replacements in ${filePath}`);
|
||
patched = true;
|
||
break;
|
||
}
|
||
|
||
if (!patched) {
|
||
console.log("[postinstall] patch-ap-collection-count-estimate: no target file found");
|
||
}
|