@rmdes/indiekit-endpoint-activitypub 2.4.2 → 2.4.3

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.
@@ -92,7 +92,7 @@ export function mapMastodonStatusToItem(status, instance) {
92
92
  }
93
93
  }
94
94
 
95
- return {
95
+ const item = {
96
96
  uid: status.url || status.uri || "",
97
97
  url: status.url || status.uri || "",
98
98
  type: "note",
@@ -116,7 +116,43 @@ export function mapMastodonStatusToItem(status, instance) {
116
116
  video,
117
117
  audio,
118
118
  inReplyTo: status.in_reply_to_id ? `https://${instance}/web/statuses/${status.in_reply_to_id}` : "",
119
+ quoteUrl: status.quote?.url || status.quote?.uri || "",
119
120
  createdAt: new Date().toISOString(),
120
121
  _explore: true,
121
122
  };
123
+
124
+ // Map quoted post data if present (Mastodon 4.3+ quote support)
125
+ if (status.quote) {
126
+ const q = status.quote;
127
+ const qAccount = q.account || {};
128
+ const qAcct = qAccount.acct || "";
129
+ const qHandle = qAcct.includes("@") ? `@${qAcct}` : `@${qAcct}@${instance}`;
130
+ const qPhoto = [];
131
+ for (const att of q.media_attachments || []) {
132
+ const attUrl = att.url || att.remote_url || "";
133
+ if (attUrl && (att.type === "image" || att.type === "gifv")) {
134
+ qPhoto.push(attUrl);
135
+ }
136
+ }
137
+
138
+ item.quote = {
139
+ url: q.url || q.uri || "",
140
+ uid: q.uri || q.url || "",
141
+ author: {
142
+ name: sanitizeHtml(qAccount.display_name || qAccount.username || "Unknown", { allowedTags: [], allowedAttributes: {} }),
143
+ url: qAccount.url || "",
144
+ photo: qAccount.avatar || qAccount.avatar_static || "",
145
+ handle: qHandle,
146
+ },
147
+ content: {
148
+ text: (q.content || "").replace(/<[^>]*>/g, ""),
149
+ html: sanitizeContent(q.content || ""),
150
+ },
151
+ published: q.created_at || "",
152
+ name: "",
153
+ photo: qPhoto.slice(0, 1),
154
+ };
155
+ }
156
+
157
+ return item;
122
158
  }
@@ -8,6 +8,7 @@
8
8
  import { searchInstances, checkInstanceTimeline, getPopularAccounts } from "../fedidb.js";
9
9
  import { getToken } from "../csrf.js";
10
10
  import { validateInstance, validateHashtag, mapMastodonStatusToItem } from "./explore-utils.js";
11
+ import { stripQuoteReferenceHtml } from "../og-unfurl.js";
11
12
 
12
13
  const FETCH_TIMEOUT_MS = 10_000;
13
14
  const MAX_RESULTS = 20;
@@ -98,6 +99,14 @@ export function exploreController(mountPath) {
98
99
 
99
100
  items = statuses.map((s) => mapMastodonStatusToItem(s, instance));
100
101
 
102
+ // Strip "RE:" paragraphs from items that have quote embeds
103
+ for (const item of items) {
104
+ const quoteRef = item.quoteUrl || item.quote?.url || item.quote?.uid;
105
+ if (item.quote && quoteRef && item.content?.html) {
106
+ item.content.html = stripQuoteReferenceHtml(item.content.html, quoteRef);
107
+ }
108
+ }
109
+
101
110
  // Get next max_id from last item for pagination
102
111
  if (statuses.length === MAX_RESULTS && statuses.length > 0) {
103
112
  const last = statuses[statuses.length - 1];
@@ -181,6 +190,14 @@ export function exploreApiController(mountPath) {
181
190
 
182
191
  const items = statuses.map((s) => mapMastodonStatusToItem(s, instance));
183
192
 
193
+ // Strip "RE:" paragraphs from items that have quote embeds
194
+ for (const item of items) {
195
+ const quoteRef = item.quoteUrl || item.quote?.url || item.quote?.uid;
196
+ if (item.quote && quoteRef && item.content?.html) {
197
+ item.content.html = stripQuoteReferenceHtml(item.content.html, quoteRef);
198
+ }
199
+ }
200
+
184
201
  let nextMaxId = null;
185
202
  if (statuses.length === MAX_RESULTS && statuses.length > 0) {
186
203
  const last = statuses[statuses.length - 1];
@@ -18,6 +18,7 @@
18
18
 
19
19
  import { validateHashtag, mapMastodonStatusToItem } from "./explore-utils.js";
20
20
  import { getToken } from "../csrf.js";
21
+ import { stripQuoteReferenceHtml } from "../og-unfurl.js";
21
22
 
22
23
  const FETCH_TIMEOUT_MS = 10_000;
23
24
  const PAGE_SIZE = 20;
@@ -183,6 +184,14 @@ export function hashtagExploreApiController(mountPath) {
183
184
  mapMastodonStatusToItem(status, domain)
184
185
  );
185
186
 
187
+ // Strip "RE:" paragraphs from items that have quote embeds
188
+ for (const item of items) {
189
+ const quoteRef = item.quoteUrl || item.quote?.url || item.quote?.uid;
190
+ if (item.quote && quoteRef && item.content?.html) {
191
+ item.content.html = stripQuoteReferenceHtml(item.content.html, quoteRef);
192
+ }
193
+ }
194
+
186
195
  // Render HTML AFTER merge/dedup/paginate (don't waste CPU on discarded items)
187
196
  const csrfToken = getToken(request.session);
188
197
  const templateData = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-activitypub",
3
- "version": "2.4.2",
3
+ "version": "2.4.3",
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",