diff --git a/package.json b/package.json index 12080666..8db0dd5f 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "postinstall": "xattr -w com.apple.fileprovider.ignore#P 1 node_modules 2>/dev/null || true && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-docloader-loglevel.mjs && node scripts/patch-endpoint-activitypub-private-url-docloader.mjs && node scripts/patch-endpoint-activitypub-migrate-alias-clear.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-endpoint-activitypub-like-boost-methods.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs", - "serve":"export NODE_ENV=${NODE_ENV:-production} INDIEKIT_DEBUG=${INDIEKIT_DEBUG:-0} && node scripts/preflight-production-security.mjs && node scripts/preflight-mongo-connection.mjs && node scripts/preflight-activitypub-rsa-key.mjs && node scripts/preflight-activitypub-profile-urls.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-docloader-loglevel.mjs && node scripts/patch-endpoint-activitypub-private-url-docloader.mjs && node scripts/patch-endpoint-activitypub-migrate-alias-clear.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-endpoint-activitypub-like-boost-methods.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs", + "postinstall": "xattr -w com.apple.fileprovider.ignore#P 1 node_modules 2>/dev/null || true && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-private-url-docloader.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs", + "serve":"export NODE_ENV=${NODE_ENV:-production} INDIEKIT_DEBUG=${INDIEKIT_DEBUG:-0} && node scripts/preflight-production-security.mjs && node scripts/preflight-mongo-connection.mjs && node scripts/preflight-activitypub-rsa-key.mjs && node scripts/preflight-activitypub-profile-urls.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-private-url-docloader.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], diff --git a/scripts/patch-endpoint-activitypub-docloader-loglevel.mjs b/scripts/patch-endpoint-activitypub-docloader-loglevel.mjs deleted file mode 100644 index a89c7f3f..00000000 --- a/scripts/patch-endpoint-activitypub-docloader-loglevel.mjs +++ /dev/null @@ -1,80 +0,0 @@ -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 oldSnippet = ` loggers: [ - { - // All Fedify logs — federation, vocab, delivery, HTTP signatures - category: ["fedify"], - sinks: ["console"], - lowestLevel: resolvedLevel, - }, - ],`; - -const newSnippet = ` loggers: [ - { - // Noise guard: remote deleted actors often return 404/410 on fetch. - // Keep only fatal events for the docloader category. - category: ["fedify", "runtime", "docloader"], - sinks: ["console"], - lowestLevel: "fatal", - }, - { - // All remaining Fedify logs - federation, vocab, delivery, signatures. - category: ["fedify"], - sinks: ["console"], - lowestLevel: resolvedLevel, - }, - ],`; - -async function exists(filePath) { - try { - await access(filePath); - return true; - } catch { - return false; - } -} - -let filesChecked = 0; -let filesPatched = 0; - -for (const filePath of candidates) { - if (!(await exists(filePath))) { - continue; - } - - filesChecked += 1; - - const source = await readFile(filePath, "utf8"); - - if (source.includes(newSnippet)) { - continue; - } - - if (!source.includes(oldSnippet)) { - continue; - } - - const updated = source.replace(oldSnippet, newSnippet); - - if (updated === source) { - continue; - } - - await writeFile(filePath, updated, "utf8"); - filesPatched += 1; -} - -if (filesChecked === 0) { - console.log("[postinstall] No activitypub federation setup files found"); -} else if (filesPatched === 0) { - console.log("[postinstall] activitypub docloader loglevel patch already applied"); -} else { - console.log( - `[postinstall] Patched activitypub docloader loglevel in ${filesPatched}/${filesChecked} file(s)`, - ); -} \ No newline at end of file diff --git a/scripts/patch-endpoint-activitypub-like-boost-methods.mjs b/scripts/patch-endpoint-activitypub-like-boost-methods.mjs deleted file mode 100644 index eb22e050..00000000 --- a/scripts/patch-endpoint-activitypub-like-boost-methods.mjs +++ /dev/null @@ -1,226 +0,0 @@ -import { access, readFile, writeFile } from "node:fs/promises"; - -const patchSpecs = [ - { - name: "activitypub-resolveAuthor-import", - candidates: [ - "node_modules/@rmdes/indiekit-endpoint-activitypub/index.js", - "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/index.js", - ], - replacements: [ - { - oldSnippet: [ - "import { startBatchRefollow } from \"./lib/batch-refollow.js\";", - "import { logActivity } from \"./lib/activity-log.js\";", - "import { scheduleCleanup } from \"./lib/timeline-cleanup.js\";", - ].join("\n"), - newSnippet: [ - "import { startBatchRefollow } from \"./lib/batch-refollow.js\";", - "import { logActivity } from \"./lib/activity-log.js\";", - "import { resolveAuthor } from \"./lib/resolve-author.js\";", - "import { scheduleCleanup } from \"./lib/timeline-cleanup.js\";", - ].join("\n"), - }, - { - oldSnippet: [ - " await this._collections.ap_following.deleteOne({ actorUrl }).catch(() => {});", - " return { ok: false, error: error.message };", - " }", - " }", - "", - " /**", - " * Send an Update(Person) activity to all followers so remote servers", - ].join("\n"), - newSnippet: [ - " await this._collections.ap_following.deleteOne({ actorUrl }).catch(() => {});", - " return { ok: false, error: error.message };", - " }", - " }", - "", - " /**", - " * Send a native AP Like activity for a post URL (called programmatically,", - " * e.g. when a like is created via Micropub).", - " * @param {string} postUrl - URL of the post being liked", - " * @param {object} [collections] - MongoDB collections map (application.collections)", - " * @returns {Promise<{ok: boolean, error?: string}>}", - " */", - " async likePost(postUrl, collections) {", - " if (!this._federation) {", - " return { ok: false, error: \"Federation not initialized\" };", - " }", - "", - " try {", - " const { Like } = await import(\"@fedify/fedify/vocab\");", - " const handle = this.options.actor.handle;", - " const ctx = this._federation.createContext(", - " new URL(this._publicationUrl),", - " { handle, publicationUrl: this._publicationUrl },", - " );", - " const documentLoader = await ctx.getDocumentLoader({ identifier: handle });", - " const cols = collections || this._collections;", - "", - " const recipient = await resolveAuthor(postUrl, ctx, documentLoader, cols);", - " if (!recipient) {", - " return { ok: false, error: `Could not resolve post author for ${postUrl}` };", - " }", - "", - " const uuid = crypto.randomUUID();", - " const activityId = `${this._publicationUrl.replace(/\\/$/, \"\")}/activitypub/likes/${uuid}`;", - "", - " const like = new Like({", - " id: new URL(activityId),", - " actor: ctx.getActorUri(handle),", - " object: new URL(postUrl),", - " });", - "", - " await ctx.sendActivity({ identifier: handle }, recipient, like, {", - " orderingKey: postUrl,", - " });", - "", - " const interactions = cols?.get?.(\"ap_interactions\") || this._collections.ap_interactions;", - " if (interactions) {", - " await interactions.updateOne(", - " { objectUrl: postUrl, type: \"like\" },", - " { $set: { objectUrl: postUrl, type: \"like\", activityId, recipientUrl: recipient.id?.href || \"\", createdAt: new Date().toISOString() } },", - " { upsert: true },", - " );", - " }", - "", - " console.info(`[ActivityPub] Sent Like for ${postUrl}`);", - " return { ok: true };", - " } catch (error) {", - " console.error(`[ActivityPub] likePost failed for ${postUrl}:`, error.message);", - " return { ok: false, error: error.message };", - " }", - " }", - "", - " /**", - " * Send a native AP Announce (boost) activity for a post URL (called", - " * programmatically, e.g. when a repost is created via Micropub).", - " * @param {string} postUrl - URL of the post being boosted", - " * @param {object} [collections] - MongoDB collections map (application.collections)", - " * @returns {Promise<{ok: boolean, error?: string}>}", - " */", - " async boostPost(postUrl, collections) {", - " if (!this._federation) {", - " return { ok: false, error: \"Federation not initialized\" };", - " }", - "", - " try {", - " const { Announce } = await import(\"@fedify/fedify/vocab\");", - " const handle = this.options.actor.handle;", - " const ctx = this._federation.createContext(", - " new URL(this._publicationUrl),", - " { handle, publicationUrl: this._publicationUrl },", - " );", - " const documentLoader = await ctx.getDocumentLoader({ identifier: handle });", - " const cols = collections || this._collections;", - "", - " const uuid = crypto.randomUUID();", - " const activityId = `${this._publicationUrl.replace(/\\/$/, \"\")}/activitypub/boosts/${uuid}`;", - " const publicAddress = new URL(\"https://www.w3.org/ns/activitystreams#Public\");", - " const followersUri = ctx.getFollowersUri(handle);", - "", - " const announce = new Announce({", - " id: new URL(activityId),", - " actor: ctx.getActorUri(handle),", - " object: new URL(postUrl),", - " to: publicAddress,", - " cc: followersUri,", - " });", - "", - " // Broadcast to followers", - " await ctx.sendActivity({ identifier: handle }, \"followers\", announce, {", - " preferSharedInbox: true,", - " syncCollection: true,", - " orderingKey: postUrl,", - " });", - "", - " // Also deliver directly to original post author", - " const recipient = await resolveAuthor(postUrl, ctx, documentLoader, cols);", - " if (recipient) {", - " await ctx.sendActivity({ identifier: handle }, recipient, announce, {", - " orderingKey: postUrl,", - " }).catch((err) => {", - " console.warn(`[ActivityPub] Direct boost delivery to author failed: ${err.message}`);", - " });", - " }", - "", - " const interactions = cols?.get?.(\"ap_interactions\") || this._collections.ap_interactions;", - " if (interactions) {", - " await interactions.updateOne(", - " { objectUrl: postUrl, type: \"boost\" },", - " { $set: { objectUrl: postUrl, type: \"boost\", activityId, createdAt: new Date().toISOString() } },", - " { upsert: true },", - " );", - " }", - "", - " console.info(`[ActivityPub] Sent Announce (boost) for ${postUrl}`);", - " return { ok: true };", - " } catch (error) {", - " console.error(`[ActivityPub] boostPost failed for ${postUrl}:`, error.message);", - " return { ok: false, error: error.message };", - " }", - " }", - "", - " /**", - " * Send an Update(Person) activity to all followers so remote servers", - ].join("\n"), - }, - ], - }, -]; - -async function exists(filePath) { - try { - await access(filePath); - return true; - } catch { - return false; - } -} - -let filesChecked = 0; -let filesPatched = 0; - -for (const patchSpec of patchSpecs) { - for (const filePath of patchSpec.candidates) { - if (!(await exists(filePath))) { - continue; - } - - filesChecked += 1; - - const source = await readFile(filePath, "utf8"); - let updated = source; - - for (const replacement of patchSpec.replacements) { - if (updated.includes(replacement.newSnippet)) { - continue; - } - - if (!updated.includes(replacement.oldSnippet)) { - continue; - } - - updated = updated.replace(replacement.oldSnippet, replacement.newSnippet); - } - - if (updated === source) { - continue; - } - - await writeFile(filePath, updated, "utf8"); - filesPatched += 1; - } -} - -if (filesChecked === 0) { - console.log("[postinstall] No activitypub like/boost patch targets found"); -} else if (filesPatched === 0) { - console.log("[postinstall] activitypub like/boost methods patch already applied"); -} else { - console.log( - `[postinstall] Patched activitypub likePost/boostPost methods in ${filesPatched}/${filesChecked} file(s)`, - ); -} diff --git a/scripts/patch-endpoint-activitypub-migrate-alias-clear.mjs b/scripts/patch-endpoint-activitypub-migrate-alias-clear.mjs deleted file mode 100644 index febea539..00000000 --- a/scripts/patch-endpoint-activitypub-migrate-alias-clear.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import { access, readFile, writeFile } from "node:fs/promises"; - -const patchSpecs = [ - { - name: "activitypub-migrate-alias-clear", - marker: "allow clearing alsoKnownAs alias by submitting empty value", - oldSnippet: ` const aliasUrl = request.body.aliasUrl?.trim(); - if (aliasUrl && profileCollection) { - await profileCollection.updateOne( - {}, - { $set: { alsoKnownAs: [aliasUrl] } }, - { upsert: true }, - ); - result = { - type: "success", - text: response.locals.__("activitypub.migrate.aliasSuccess"), - }; - }`, - newSnippet: ` const aliasUrl = request.body.aliasUrl?.trim(); - const submittedAliasField = Object.prototype.hasOwnProperty.call( - request.body || {}, - "aliasUrl", - ); - - // allow clearing alsoKnownAs alias by submitting empty value - if (profileCollection && submittedAliasField) { - if (aliasUrl) { - await profileCollection.updateOne( - {}, - { $set: { alsoKnownAs: [aliasUrl] } }, - { upsert: true }, - ); - result = { - type: "success", - text: response.locals.__("activitypub.migrate.aliasSuccess"), - }; - } else { - await profileCollection.updateOne( - {}, - { $set: { alsoKnownAs: [] } }, - { upsert: true }, - ); - result = { - type: "success", - text: "Alias removed - alsoKnownAs is now empty.", - }; - } - }`, - candidates: [ - "node_modules/@rmdes/indiekit-endpoint-activitypub/lib/controllers/migrate.js", - "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/controllers/migrate.js", - ], - }, -]; - -async function exists(filePath) { - try { - await access(filePath); - return true; - } catch { - return false; - } -} - -let filesChecked = 0; -let filesPatched = 0; - -for (const spec of patchSpecs) { - let foundAnyTarget = false; - - for (const filePath of spec.candidates) { - if (!(await exists(filePath))) { - continue; - } - - foundAnyTarget = true; - filesChecked += 1; - - const source = await readFile(filePath, "utf8"); - - if (source.includes(spec.marker)) { - continue; - } - - if (!source.includes(spec.oldSnippet)) { - continue; - } - - const updated = source.replace(spec.oldSnippet, spec.newSnippet); - await writeFile(filePath, updated, "utf8"); - filesPatched += 1; - } - - if (!foundAnyTarget) { - console.log(`[postinstall] ${spec.name}: no target files found`); - } -} - -if (filesChecked === 0) { - console.log("[postinstall] No activitypub migrate alias files found"); -} else if (filesPatched === 0) { - console.log("[postinstall] activitypub migrate alias clear already patched"); -} else { - console.log( - `[postinstall] Patched activitypub migrate alias clear in ${filesPatched}/${filesChecked} file(s)`, - ); -} diff --git a/scripts/patch-federation-unlisted-guards.mjs b/scripts/patch-federation-unlisted-guards.mjs index 62c215ef..47e6d1e2 100644 --- a/scripts/patch-federation-unlisted-guards.mjs +++ b/scripts/patch-federation-unlisted-guards.mjs @@ -1,20 +1,13 @@ import { access, readFile, writeFile } from "node:fs/promises"; +// activitypub index.js and federation-setup.js unlisted guards are now +// built into the fork — only endpoint-syndicate (separate package) needs patching. + const endpointSyndicateCandidates = [ "node_modules/@indiekit/endpoint-syndicate/lib/utils.js", "node_modules/@indiekit/indiekit/node_modules/@indiekit/endpoint-syndicate/lib/utils.js", ]; -const activityPubIndexCandidates = [ - "node_modules/@rmdes/indiekit-endpoint-activitypub/index.js", - "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/index.js", -]; - -const activityPubFederationSetupCandidates = [ - "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 patchSpecs = [ { name: "endpoint-syndicate-source-url-unlisted-guard", @@ -65,89 +58,6 @@ const patchSpecs = [ }, })`, }, - { - name: "activitypub-syndicator-unlisted-guard", - candidates: activityPubIndexCandidates, - oldSnippet: ` async syndicate(properties) { - if (!self._federation) { - return undefined; - } - - try {`, - newSnippet: ` async syndicate(properties) { - if (!self._federation) { - return undefined; - } - - const visibility = String(properties?.visibility || "").toLowerCase(); - if (visibility === "unlisted") { - console.info( - "[ActivityPub] Skipping federation for unlisted post: " + - (properties?.url || "unknown"), - ); - await logActivity(self._collections.ap_activities, { - direction: "outbound", - type: "Syndicate", - actorUrl: self._publicationUrl, - objectUrl: properties?.url, - summary: "Syndication skipped: post visibility is unlisted", - }).catch(() => {}); - return undefined; - } - - try {`, - }, - { - name: "activitypub-outbox-unlisted-guard", - candidates: activityPubFederationSetupCandidates, - oldSnippet: ` const pageSize = 20; - const skip = cursor ? Number.parseInt(cursor, 10) : 0; - const total = await postsCollection.countDocuments(); - - const posts = await postsCollection - .find()`, - newSnippet: ` const pageSize = 20; - const skip = cursor ? Number.parseInt(cursor, 10) : 0; - const federationVisibilityQuery = { - "properties.post-status": { $ne: "draft" }, - "properties.visibility": { $ne: "unlisted" }, - }; - const total = await postsCollection.countDocuments( - federationVisibilityQuery, - ); - - const posts = await postsCollection - .find(federationVisibilityQuery)`, - }, - { - name: "activitypub-outbox-counter-unlisted-guard", - candidates: activityPubFederationSetupCandidates, - oldSnippet: ` .setCounter(async (ctx, identifier) => { - if (identifier !== handle) return 0; - const postsCollection = collections.posts; - if (!postsCollection) return 0; - return await postsCollection.countDocuments(); - })`, - newSnippet: ` .setCounter(async (ctx, identifier) => { - if (identifier !== handle) return 0; - const postsCollection = collections.posts; - if (!postsCollection) return 0; - return await postsCollection.countDocuments({ - "properties.post-status": { $ne: "draft" }, - "properties.visibility": { $ne: "unlisted" }, - }); - })`, - }, - { - name: "activitypub-object-dispatch-unlisted-guard", - candidates: activityPubFederationSetupCandidates, - oldSnippet: ` const post = await collections.posts.findOne({ "properties.url": postUrl }); - if (!post) return null;`, - newSnippet: ` const post = await collections.posts.findOne({ "properties.url": postUrl }); - if (!post) return null; - if (post?.properties?.["post-status"] === "draft") return null; - if (post?.properties?.visibility === "unlisted") return null;`, - }, ]; async function exists(filePath) {