From 965a10f9732798a0cffa77ee434e108ea0fcc01a Mon Sep 17 00:00:00 2001 From: Sven Date: Sat, 25 Apr 2026 17:23:02 +0200 Subject: [PATCH] chore: remove AP enrich-actor + stubs patches now in fork source Both patches are now in svemagie/indiekit-endpoint-activitypub@83d6af6: - enrich-actor-data (Fedify async getIcon/getImage + @user@domain handle) - stubs-remove-duplicate-routes (removed accounts/:id sub-routes from stubs.js) Updates package-lock.json to reference the new fork commit. Co-Authored-By: Claude Sonnet 4.6 --- package-lock.json | 2 +- package.json | 4 +- scripts/patch-ap-enrich-actor-data.mjs | 237 ------------------ ...patch-ap-stubs-remove-duplicate-routes.mjs | 108 -------- 4 files changed, 3 insertions(+), 348 deletions(-) delete mode 100644 scripts/patch-ap-enrich-actor-data.mjs delete mode 100644 scripts/patch-ap-stubs-remove-duplicate-routes.mjs diff --git a/package-lock.json b/package-lock.json index 9fc0e72b..7a5dd188 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2419,7 +2419,7 @@ }, "node_modules/@rmdes/indiekit-endpoint-activitypub": { "version": "3.13.4", - "resolved": "git+https://gitea.giersig.eu/svemagie/indiekit-endpoint-activitypub#cfe35b28e834e22d15358ec6a061adc30fe65363", + "resolved": "git+https://gitea.giersig.eu/svemagie/indiekit-endpoint-activitypub#83d6af6cc92abbd41b16dd8ef9f84042a1c2eea0", "license": "MIT", "dependencies": { "@fedify/debugger": "^2.1.0", diff --git a/package.json b/package.json index 0eb2f220..01624ea0 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "index.js", "scripts": { "preinstall": "node scripts/setup-gitea-url-rewrite.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-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-podroll-opml-upload.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.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-github-contributions-log.mjs && node scripts/patch-store-github-error-message.mjs && node scripts/patch-store-github-update-fallback.mjs && node scripts/patch-store-github-gitea-methods.mjs && node scripts/patch-store-github-put-fallback.mjs && node scripts/patch-store-github-content-type.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-syndicate-normalize-syndication-array.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-micropub-session-token.mjs && node scripts/patch-indiekit-endpoint-urls-protocol.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-reset-stale.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs && node scripts/patch-bluesky-syndicator-media-type-guard.mjs && node scripts/patch-bluesky-og-own-post-title.mjs && node scripts/patch-bluesky-syndicator-delete.mjs && node scripts/patch-micropub-delete-propagation.mjs && node scripts/patch-micropub-category-from-posts.mjs && node scripts/patch-tag-input-autocomplete.mjs && node scripts/patch-microsub-compose-draft-guard.mjs && node scripts/patch-microsub-no-bookmark-autofollow.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node scripts/patch-microsub-batch-concurrency.mjs && node scripts/patch-ap-enrich-actor-data.mjs && node scripts/patch-ap-stubs-remove-duplicate-routes.mjs && node scripts/patch-session-maxage.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/preflight-startup-gate.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-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-podroll-opml-upload.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.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-github-contributions-log.mjs && node scripts/patch-store-github-error-message.mjs && node scripts/patch-store-github-update-fallback.mjs && node scripts/patch-store-github-gitea-methods.mjs && node scripts/patch-store-github-put-fallback.mjs && node scripts/patch-store-github-content-type.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node scripts/patch-microsub-compose-draft-guard.mjs && node scripts/patch-microsub-no-bookmark-autofollow.mjs && node scripts/patch-microsub-batch-concurrency.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-syndicate-normalize-syndication-array.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-micropub-session-token.mjs && node scripts/patch-indiekit-endpoint-urls-protocol.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-reset-stale.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs && node scripts/patch-bluesky-syndicator-media-type-guard.mjs && node scripts/patch-bluesky-og-own-post-title.mjs && node scripts/patch-bluesky-syndicator-delete.mjs && node scripts/patch-micropub-delete-propagation.mjs && node scripts/patch-micropub-category-from-posts.mjs && node scripts/patch-tag-input-autocomplete.mjs && node scripts/patch-ap-enrich-actor-data.mjs && node scripts/patch-ap-stubs-remove-duplicate-routes.mjs && node scripts/patch-session-maxage.mjs && node --max-old-space-size=1024 --max-semi-space-size=32 --require ./metrics-shim.cjs 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-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-podroll-opml-upload.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.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-github-contributions-log.mjs && node scripts/patch-store-github-error-message.mjs && node scripts/patch-store-github-update-fallback.mjs && node scripts/patch-store-github-gitea-methods.mjs && node scripts/patch-store-github-put-fallback.mjs && node scripts/patch-store-github-content-type.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-syndicate-normalize-syndication-array.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-micropub-session-token.mjs && node scripts/patch-indiekit-endpoint-urls-protocol.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-reset-stale.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs && node scripts/patch-bluesky-syndicator-media-type-guard.mjs && node scripts/patch-bluesky-og-own-post-title.mjs && node scripts/patch-bluesky-syndicator-delete.mjs && node scripts/patch-micropub-delete-propagation.mjs && node scripts/patch-micropub-category-from-posts.mjs && node scripts/patch-tag-input-autocomplete.mjs && node scripts/patch-microsub-compose-draft-guard.mjs && node scripts/patch-microsub-no-bookmark-autofollow.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node scripts/patch-microsub-batch-concurrency.mjs && node scripts/patch-session-maxage.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/preflight-startup-gate.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-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-podroll-opml-upload.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.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-github-contributions-log.mjs && node scripts/patch-store-github-error-message.mjs && node scripts/patch-store-github-update-fallback.mjs && node scripts/patch-store-github-gitea-methods.mjs && node scripts/patch-store-github-put-fallback.mjs && node scripts/patch-store-github-content-type.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node scripts/patch-microsub-compose-draft-guard.mjs && node scripts/patch-microsub-no-bookmark-autofollow.mjs && node scripts/patch-microsub-batch-concurrency.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-syndicate-normalize-syndication-array.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-micropub-session-token.mjs && node scripts/patch-indiekit-endpoint-urls-protocol.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-reset-stale.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs && node scripts/patch-bluesky-syndicator-media-type-guard.mjs && node scripts/patch-bluesky-og-own-post-title.mjs && node scripts/patch-bluesky-syndicator-delete.mjs && node scripts/patch-micropub-delete-propagation.mjs && node scripts/patch-micropub-category-from-posts.mjs && node scripts/patch-tag-input-autocomplete.mjs && node scripts/patch-session-maxage.mjs && node --max-old-space-size=1024 --max-semi-space-size=32 --require ./metrics-shim.cjs 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-ap-enrich-actor-data.mjs b/scripts/patch-ap-enrich-actor-data.mjs deleted file mode 100644 index 9a47acd5..00000000 --- a/scripts/patch-ap-enrich-actor-data.mjs +++ /dev/null @@ -1,237 +0,0 @@ -/** - * patch-ap-enrich-actor-data.mjs - * - * Fixes avatar and handle extraction in three code paths: - * 1. followActor() in index.js — outbound follow stores wrong handle + empty avatar - * 2. inbox-listeners.js — incoming Follow stores wrong handle + empty avatar - * 3. inbox-handlers.js — Update handler refreshes with wrong handle + empty avatar - * - * Root cause: All three use `remoteActor.preferredUsername` (no domain) for handle - * and `remoteActor.icon` (sync property, often falsy) for avatar. - * Fix: Use `getIcon()` async getter and build `@user@domain` from URL. - */ -import { readFileSync, writeFileSync } from "node:fs"; -import { resolve } from "node:path"; - -const BASE = resolve("/usr/local/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub"); - -const patchSpecs = [ - // ─── Patch 1: followActor() in index.js ───────────────────────────────── - { - name: "followActor-avatar-handle", - marker: "// [patch] ap-enrich-actor-follow", - candidates: [resolve(BASE, "index.js")], - oldSnippet: ` const actorHandle = - actorInfo.handle || - remoteActor.preferredUsername?.toString() || - ""; - const avatar = - actorInfo.photo || - (remoteActor.icon - ? (await remoteActor.icon)?.url?.href || "" - : "");`, - newSnippet: ` // [patch] ap-enrich-actor-follow - let _enrichedAvatar = ""; // [patch] ap-enrich-actor-follow - try { // [patch] ap-enrich-actor-follow - if (typeof remoteActor.getIcon === "function") { // [patch] ap-enrich-actor-follow - const _iconObj = await remoteActor.getIcon(); // [patch] ap-enrich-actor-follow - _enrichedAvatar = _iconObj?.url?.href || ""; // [patch] ap-enrich-actor-follow - } // [patch] ap-enrich-actor-follow - } catch { /* icon fetch failed */ } // [patch] ap-enrich-actor-follow - let _enrichedHandle = ""; // [patch] ap-enrich-actor-follow - try { // [patch] ap-enrich-actor-follow - const _username = remoteActor.preferredUsername?.toString() || ""; // [patch] ap-enrich-actor-follow - if (_username && actorUrl) { // [patch] ap-enrich-actor-follow - const _domain = new URL(actorUrl).hostname; // [patch] ap-enrich-actor-follow - _enrichedHandle = \`@\${_username}@\${_domain}\`; // [patch] ap-enrich-actor-follow - } // [patch] ap-enrich-actor-follow - } catch { /* URL parse failed */ } // [patch] ap-enrich-actor-follow - let _enrichedBanner = ""; // [patch] ap-enrich-actor-follow - try { // [patch] ap-enrich-actor-follow - if (typeof remoteActor.getImage === "function") { // [patch] ap-enrich-actor-follow - const _imgObj = await remoteActor.getImage(); // [patch] ap-enrich-actor-follow - _enrichedBanner = _imgObj?.url?.href || ""; // [patch] ap-enrich-actor-follow - } // [patch] ap-enrich-actor-follow - } catch { /* banner fetch failed */ } // [patch] ap-enrich-actor-follow - const actorHandle = actorInfo.handle || _enrichedHandle || remoteActor.preferredUsername?.toString() || ""; // [patch] ap-enrich-actor-follow - const avatar = actorInfo.photo || _enrichedAvatar || ""; // [patch] ap-enrich-actor-follow`, - }, - - // ─── Patch 2: Also store banner in followActor updateOne ──────────────── - { - name: "followActor-store-banner", - marker: "// [patch] ap-enrich-actor-follow-banner", - candidates: [resolve(BASE, "index.js")], - oldSnippet: ` sharedInbox, - followedAt: new Date().toISOString(), - source: "reader",`, - newSnippet: ` sharedInbox, - banner: _enrichedBanner || "", // [patch] ap-enrich-actor-follow-banner - followedAt: new Date().toISOString(), - source: "reader",`, - }, - - // ─── Patch 3: inbox-listeners.js follower creation ────────────────────── - { - name: "inbox-listeners-follower-avatar-handle", - marker: "// [patch] ap-enrich-follower-data", - candidates: [resolve(BASE, "lib/inbox-listeners.js")], - oldSnippet: ` const followerData = { - actorUrl: followerUrl, - handle: followerActor.preferredUsername?.toString() || "", - name: followerName, - avatar: followerActor.icon - ? (await followerActor.icon)?.url?.href || "" - : "", - inbox: followerActor.inbox?.id?.href || "", - sharedInbox: followerActor.endpoints?.sharedInbox?.href || "", - };`, - newSnippet: ` // Enrich avatar and handle using proper Fedify async getters // [patch] ap-enrich-follower-data - let _fAvatar = ""; // [patch] ap-enrich-follower-data - try { // [patch] ap-enrich-follower-data - if (typeof followerActor.getIcon === "function") { // [patch] ap-enrich-follower-data - const _fIcon = await followerActor.getIcon(); // [patch] ap-enrich-follower-data - _fAvatar = _fIcon?.url?.href || ""; // [patch] ap-enrich-follower-data - } // [patch] ap-enrich-follower-data - } catch { /* icon fetch failed */ } // [patch] ap-enrich-follower-data - let _fHandle = ""; // [patch] ap-enrich-follower-data - try { // [patch] ap-enrich-follower-data - const _fUsername = followerActor.preferredUsername?.toString() || ""; // [patch] ap-enrich-follower-data - if (_fUsername && followerUrl) { // [patch] ap-enrich-follower-data - const _fDomain = new URL(followerUrl).hostname; // [patch] ap-enrich-follower-data - _fHandle = \`@\${_fUsername}@\${_fDomain}\`; // [patch] ap-enrich-follower-data - } // [patch] ap-enrich-follower-data - } catch { /* URL parse failed */ } // [patch] ap-enrich-follower-data - let _fBanner = ""; // [patch] ap-enrich-follower-data - try { // [patch] ap-enrich-follower-data - if (typeof followerActor.getImage === "function") { // [patch] ap-enrich-follower-data - const _fImg = await followerActor.getImage(); // [patch] ap-enrich-follower-data - _fBanner = _fImg?.url?.href || ""; // [patch] ap-enrich-follower-data - } // [patch] ap-enrich-follower-data - } catch { /* banner fetch failed */ } // [patch] ap-enrich-follower-data - const followerData = { // [patch] ap-enrich-follower-data - actorUrl: followerUrl, - handle: _fHandle || followerActor.preferredUsername?.toString() || "", - name: followerName, - avatar: _fAvatar, - banner: _fBanner, - inbox: followerActor.inbox?.id?.href || "", - sharedInbox: followerActor.endpoints?.sharedInbox?.href || "", - };`, - }, - - // ─── Patch 4: inbox-handlers.js Update handler ───────────────────────── - { - name: "inbox-handlers-update-avatar-handle", - marker: "// [patch] ap-enrich-update-handler", - candidates: [resolve(BASE, "lib/inbox-handlers.js")], - oldSnippet: ` const existing = await collections.ap_followers.findOne({ actorUrl }); - if (existing) { - await collections.ap_followers.updateOne( - { actorUrl }, - { - $set: { - name: - actorObj.name?.toString() || - actorObj.preferredUsername?.toString() || - actorUrl, - handle: actorObj.preferredUsername?.toString() || "", - avatar: actorObj.icon - ? (await actorObj.icon)?.url?.href || "" - : "", - updatedAt: new Date().toISOString(), - }, - }, - ); - } -}`, - newSnippet: ` const existing = await collections.ap_followers.findOne({ actorUrl }); - if (existing) { // [patch] ap-enrich-update-handler - let _uAvatar = ""; // [patch] ap-enrich-update-handler - try { // [patch] ap-enrich-update-handler - if (typeof actorObj.getIcon === "function") { // [patch] ap-enrich-update-handler - const _uIcon = await actorObj.getIcon(); // [patch] ap-enrich-update-handler - _uAvatar = _uIcon?.url?.href || ""; // [patch] ap-enrich-update-handler - } // [patch] ap-enrich-update-handler - } catch { /* icon fetch failed */ } // [patch] ap-enrich-update-handler - let _uHandle = ""; // [patch] ap-enrich-update-handler - try { // [patch] ap-enrich-update-handler - const _uUsername = actorObj.preferredUsername?.toString() || ""; // [patch] ap-enrich-update-handler - if (_uUsername && actorUrl) { // [patch] ap-enrich-update-handler - const _uDomain = new URL(actorUrl).hostname; // [patch] ap-enrich-update-handler - _uHandle = \`@\${_uUsername}@\${_uDomain}\`; // [patch] ap-enrich-update-handler - } // [patch] ap-enrich-update-handler - } catch { /* URL parse failed */ } // [patch] ap-enrich-update-handler - let _uBanner = ""; // [patch] ap-enrich-update-handler - try { // [patch] ap-enrich-update-handler - if (typeof actorObj.getImage === "function") { // [patch] ap-enrich-update-handler - const _uImg = await actorObj.getImage(); // [patch] ap-enrich-update-handler - _uBanner = _uImg?.url?.href || ""; // [patch] ap-enrich-update-handler - } // [patch] ap-enrich-update-handler - } catch { /* banner fetch failed */ } // [patch] ap-enrich-update-handler - const _updateFields = { // [patch] ap-enrich-update-handler - name: actorObj.name?.toString() || actorObj.preferredUsername?.toString() || actorUrl, - handle: _uHandle || actorObj.preferredUsername?.toString() || "", - avatar: _uAvatar, - updatedAt: new Date().toISOString(), - }; // [patch] ap-enrich-update-handler - if (_uBanner) _updateFields.banner = _uBanner; // [patch] ap-enrich-update-handler - await collections.ap_followers.updateOne( // [patch] ap-enrich-update-handler - { actorUrl }, - { $set: _updateFields }, - ); - // Also update ap_following if we follow this actor // [patch] ap-enrich-update-handler - const existingFollowing = await collections.ap_following.findOne({ actorUrl }); // [patch] ap-enrich-update-handler - if (existingFollowing) { // [patch] ap-enrich-update-handler - await collections.ap_following.updateOne( // [patch] ap-enrich-update-handler - { actorUrl }, // [patch] ap-enrich-update-handler - { $set: _updateFields }, // [patch] ap-enrich-update-handler - ); // [patch] ap-enrich-update-handler - } // [patch] ap-enrich-update-handler - } -}`, - }, -]; - -let applied = 0; -let skipped = 0; - -for (const spec of patchSpecs) { - const { name, marker, candidates, oldSnippet, newSnippet } = spec; - - let targetFile = null; - for (const candidate of candidates) { - try { - readFileSync(candidate, "utf8"); - targetFile = candidate; - break; - } catch { /* try next */ } - } - - if (!targetFile) { - console.warn(`[${name}] No target file found among candidates`); - skipped++; - continue; - } - - const content = readFileSync(targetFile, "utf8"); - - if (content.includes(marker)) { - console.log(`[${name}] Already applied (marker found), skipping`); - skipped++; - continue; - } - - if (!content.includes(oldSnippet)) { - console.warn(`[${name}] Old snippet not found in ${targetFile}`); - skipped++; - continue; - } - - const patched = content.replace(oldSnippet, newSnippet); - writeFileSync(targetFile, patched, "utf8"); - console.log(`[${name}] ✅ Patched ${targetFile}`); - applied++; -} - -console.log(`\nDone: ${applied} applied, ${skipped} skipped`); diff --git a/scripts/patch-ap-stubs-remove-duplicate-routes.mjs b/scripts/patch-ap-stubs-remove-duplicate-routes.mjs deleted file mode 100644 index 5e0168f8..00000000 --- a/scripts/patch-ap-stubs-remove-duplicate-routes.mjs +++ /dev/null @@ -1,108 +0,0 @@ -/** - * patch-ap-stubs-remove-duplicate-routes.mjs - * - * Removes duplicate account sub-routes from stubs.js that are already - * properly implemented in accounts.js. Since accountsRouter is registered - * before stubsRouter in router.js, these are dead code that could confuse - * maintenance. - * - * Removes: - * - GET /api/v1/accounts/:id/statuses (duplicate of accounts.js) - * - GET /api/v1/accounts/:id/followers (duplicate of accounts.js) - * - GET /api/v1/accounts/:id/following (duplicate of accounts.js) - */ -import { readFileSync, writeFileSync } from "node:fs"; -import { resolve } from "node:path"; - -const MARKER = "// [patch] ap-stubs-dedup-account-routes"; -const TARGET = resolve( - "/usr/local/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/routes/stubs.js", -); - -let content; -try { - content = readFileSync(TARGET, "utf8"); -} catch { - console.warn("Target file not found:", TARGET); - process.exit(0); -} - -if (content.includes(MARKER)) { - console.log("Already applied (marker found), skipping"); - process.exit(0); -} - -// Remove the duplicate /api/v1/accounts/:id/statuses handler -const statusesBlock = `// ─── Account statuses ─────────────────────────────────────────────────────── - -router.get("/api/v1/accounts/:id/statuses", async (req, res, next) => { - try { - const collections = req.app.locals.mastodonCollections; - const baseUrl = \`\${req.protocol}://\${req.get("host")}\`; - - // Try to find the profile to see if this is the local user - const profile = await collections.ap_profile.findOne({}); - const isLocal = profile && profile._id.toString() === req.params.id; - - if (isLocal && profile?.url) { - // Return statuses authored by local user - const { serializeStatus } = await import("../entities/status.js"); - const { parseLimit } = await import("../helpers/pagination.js"); - - const limit = parseLimit(req.query.limit); - const items = await collections.ap_timeline - .find({ "author.url": profile.url, isContext: { $ne: true } }) - .sort({ _id: -1 }) - .limit(limit) - .toArray(); - - const statuses = items.map((item) => - serializeStatus(item, { - baseUrl, - favouritedIds: new Set(), - rebloggedIds: new Set(), - bookmarkedIds: new Set(), - pinnedIds: new Set(), - }), - ); - - return res.json(statuses); - } - - // Remote account or unknown — return empty - res.json([]); - } catch (error) { - next(error); - } -});`; - -const followersBlock = `// ─── Account followers/following ──────────────────────────────────────────── - -router.get("/api/v1/accounts/:id/followers", (req, res) => { - res.json([]); -}); - -router.get("/api/v1/accounts/:id/following", (req, res) => { - res.json([]); -});`; - -let patched = content; - -if (patched.includes(statusesBlock)) { - patched = patched.replace(statusesBlock, `${MARKER} — removed duplicate accounts/:id/statuses, /followers, /following (implemented in accounts.js)`); -} else { - console.warn("Could not find statuses block to remove"); -} - -if (patched.includes(followersBlock)) { - patched = patched.replace(followersBlock, ""); -} else { - console.warn("Could not find followers/following block to remove"); -} - -if (patched !== content) { - writeFileSync(TARGET, patched, "utf8"); - console.log("✅ Removed duplicate account routes from stubs.js"); -} else { - console.warn("No changes made"); -}