@rmdes/indiekit-endpoint-activitypub 2.11.0 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -326,6 +326,38 @@ export default class ActivityPubEndpoint {
326
326
  const router = express.Router(); // eslint-disable-line new-cap
327
327
  const self = this;
328
328
 
329
+ // Intercept Micropub delete actions to broadcast Delete to fediverse.
330
+ // Wraps res.json to detect successful delete responses, then fires
331
+ // broadcastDelete asynchronously so remote servers remove the post.
332
+ router.use((req, res, next) => {
333
+ if (req.method !== "POST") return next();
334
+ if (!req.path.endsWith("/micropub")) return next();
335
+
336
+ const action = req.query?.action || req.body?.action;
337
+ if (action !== "delete") return next();
338
+
339
+ const postUrl = req.query?.url || req.body?.url;
340
+ if (!postUrl) return next();
341
+
342
+ const originalJson = res.json.bind(res);
343
+ res.json = function (body) {
344
+ // Fire broadcastDelete after successful delete (status 200)
345
+ if (res.statusCode === 200 && body?.success === "delete") {
346
+ console.info(
347
+ `[ActivityPub] Micropub delete detected for ${postUrl}, broadcasting Delete to followers`,
348
+ );
349
+ self.broadcastDelete(postUrl).catch((error) => {
350
+ console.warn(
351
+ `[ActivityPub] broadcastDelete after Micropub delete failed: ${error.message}`,
352
+ );
353
+ });
354
+ }
355
+ return originalJson(body);
356
+ };
357
+
358
+ return next();
359
+ });
360
+
329
361
  // Let Fedify handle NodeInfo data (/nodeinfo/2.1)
330
362
  // Only pass GET/HEAD requests — POST/PUT/DELETE must not go through
331
363
  // Fedify here, because fromExpressRequest() consumes the body stream,
@@ -483,6 +515,7 @@ export default class ActivityPubEndpoint {
483
515
  resolvedMentions.push({
484
516
  handle,
485
517
  actorUrl: mentionedActor.id.href,
518
+ profileUrl: mentionedActor.url?.href || null,
486
519
  });
487
520
  mentionRecipients.push({
488
521
  handle,
package/lib/jf2-to-as2.js CHANGED
@@ -60,18 +60,18 @@ export function parseMentions(text) {
60
60
 
61
61
  /**
62
62
  * Replace @user@domain patterns in HTML with linked mentions.
63
- * resolvedMentions: [{ handle, actorUrl }]
64
- * Unresolved handles get a WebFinger-style link as fallback.
63
+ * resolvedMentions: [{ handle, actorUrl, profileUrl? }]
64
+ * Uses profileUrl (human-readable) for href, falls back to Mastodon-style URL.
65
65
  */
66
66
  function linkifyMentions(html, resolvedMentions) {
67
67
  if (!html || !resolvedMentions?.length) return html;
68
- for (const { handle, actorUrl } of resolvedMentions) {
68
+ for (const { handle, profileUrl } of resolvedMentions) {
69
69
  // Escape handle for regex (dots, hyphens)
70
70
  const escaped = handle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
71
71
  // Match @handle not already inside an HTML tag attribute or anchor text
72
72
  const pattern = new RegExp(`(?<!["\\/\\w])@${escaped}(?![\\w])`, "gi");
73
73
  const parts = handle.split("@");
74
- const url = actorUrl || `https://${parts[1]}/@${parts[0]}`;
74
+ const url = profileUrl || `https://${parts[1]}/@${parts[0]}`;
75
75
  html = html.replace(
76
76
  pattern,
77
77
  `<a href="${url}" class="mention" rel="nofollow noopener" target="_blank">@${handle}</a>`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-activitypub",
3
- "version": "2.11.0",
3
+ "version": "2.11.2",
4
4
  "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
5
5
  "keywords": [
6
6
  "indiekit",