@rmdes/indiekit-endpoint-activitypub 1.0.26 → 1.0.28
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
|
@@ -149,11 +149,11 @@ export default class ActivityPubEndpoint {
|
|
|
149
149
|
router.get("/admin/following", followingController(mp));
|
|
150
150
|
router.get("/admin/activities", activitiesController(mp));
|
|
151
151
|
router.get("/admin/featured", featuredGetController(mp));
|
|
152
|
-
router.post("/admin/featured/pin", featuredPinController());
|
|
153
|
-
router.post("/admin/featured/unpin", featuredUnpinController());
|
|
152
|
+
router.post("/admin/featured/pin", featuredPinController(mp));
|
|
153
|
+
router.post("/admin/featured/unpin", featuredUnpinController(mp));
|
|
154
154
|
router.get("/admin/tags", featuredTagsGetController(mp));
|
|
155
|
-
router.post("/admin/tags/add", featuredTagsAddController());
|
|
156
|
-
router.post("/admin/tags/remove", featuredTagsRemoveController());
|
|
155
|
+
router.post("/admin/tags/add", featuredTagsAddController(mp));
|
|
156
|
+
router.post("/admin/tags/remove", featuredTagsRemoveController(mp));
|
|
157
157
|
router.get("/admin/profile", profileGetController(mp));
|
|
158
158
|
router.post("/admin/profile", profilePostController(mp));
|
|
159
159
|
router.get("/admin/migrate", migrateGetController(mp, this.options));
|
|
@@ -12,6 +12,9 @@ export function dashboardController(mountPath) {
|
|
|
12
12
|
const followingCollection = application?.collections?.get("ap_following");
|
|
13
13
|
const activitiesCollection =
|
|
14
14
|
application?.collections?.get("ap_activities");
|
|
15
|
+
const featuredCollection = application?.collections?.get("ap_featured");
|
|
16
|
+
const featuredTagsCollection =
|
|
17
|
+
application?.collections?.get("ap_featured_tags");
|
|
15
18
|
|
|
16
19
|
const followerCount = followersCollection
|
|
17
20
|
? await followersCollection.countDocuments()
|
|
@@ -19,6 +22,12 @@ export function dashboardController(mountPath) {
|
|
|
19
22
|
const followingCount = followingCollection
|
|
20
23
|
? await followingCollection.countDocuments()
|
|
21
24
|
: 0;
|
|
25
|
+
const pinnedCount = featuredCollection
|
|
26
|
+
? await featuredCollection.countDocuments()
|
|
27
|
+
: 0;
|
|
28
|
+
const tagCount = featuredTagsCollection
|
|
29
|
+
? await featuredTagsCollection.countDocuments()
|
|
30
|
+
: 0;
|
|
22
31
|
|
|
23
32
|
const recentActivities = activitiesCollection
|
|
24
33
|
? await activitiesCollection
|
|
@@ -38,6 +47,8 @@ export function dashboardController(mountPath) {
|
|
|
38
47
|
title: response.locals.__("activitypub.title"),
|
|
39
48
|
followerCount,
|
|
40
49
|
followingCount,
|
|
50
|
+
pinnedCount,
|
|
51
|
+
tagCount,
|
|
41
52
|
recentActivities,
|
|
42
53
|
refollowStatus,
|
|
43
54
|
mountPath,
|
|
@@ -24,7 +24,7 @@ export function featuredTagsGetController(mountPath) {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function featuredTagsAddController() {
|
|
27
|
+
export function featuredTagsAddController(mountPath) {
|
|
28
28
|
return async (request, response, next) => {
|
|
29
29
|
try {
|
|
30
30
|
const { application } = request.app.locals;
|
|
@@ -44,14 +44,14 @@ export function featuredTagsAddController() {
|
|
|
44
44
|
{ upsert: true },
|
|
45
45
|
);
|
|
46
46
|
|
|
47
|
-
response.redirect(
|
|
47
|
+
response.redirect(`${mountPath}/admin/tags`);
|
|
48
48
|
} catch (error) {
|
|
49
49
|
next(error);
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export function featuredTagsRemoveController() {
|
|
54
|
+
export function featuredTagsRemoveController(mountPath) {
|
|
55
55
|
return async (request, response, next) => {
|
|
56
56
|
try {
|
|
57
57
|
const { application } = request.app.locals;
|
|
@@ -63,7 +63,7 @@ export function featuredTagsRemoveController() {
|
|
|
63
63
|
|
|
64
64
|
await collection.deleteOne({ tag });
|
|
65
65
|
|
|
66
|
-
response.redirect(
|
|
66
|
+
response.redirect(`${mountPath}/admin/tags`);
|
|
67
67
|
} catch (error) {
|
|
68
68
|
next(error);
|
|
69
69
|
}
|
|
@@ -69,7 +69,7 @@ export function featuredGetController(mountPath) {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export function featuredPinController() {
|
|
72
|
+
export function featuredPinController(mountPath) {
|
|
73
73
|
return async (request, response, next) => {
|
|
74
74
|
try {
|
|
75
75
|
const { application } = request.app.locals;
|
|
@@ -90,14 +90,14 @@ export function featuredPinController() {
|
|
|
90
90
|
{ upsert: true },
|
|
91
91
|
);
|
|
92
92
|
|
|
93
|
-
response.redirect(
|
|
93
|
+
response.redirect(`${mountPath}/admin/featured`);
|
|
94
94
|
} catch (error) {
|
|
95
95
|
next(error);
|
|
96
96
|
}
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export function featuredUnpinController() {
|
|
100
|
+
export function featuredUnpinController(mountPath) {
|
|
101
101
|
return async (request, response, next) => {
|
|
102
102
|
try {
|
|
103
103
|
const { application } = request.app.locals;
|
|
@@ -109,7 +109,7 @@ export function featuredUnpinController() {
|
|
|
109
109
|
|
|
110
110
|
await collection.deleteOne({ postUrl });
|
|
111
111
|
|
|
112
|
-
response.redirect(
|
|
112
|
+
response.redirect(`${mountPath}/admin/featured`);
|
|
113
113
|
} catch (error) {
|
|
114
114
|
next(error);
|
|
115
115
|
}
|
package/lib/inbox-listeners.js
CHANGED
|
@@ -85,9 +85,14 @@ export function registerInboxListeners(inboxChain, options) {
|
|
|
85
85
|
});
|
|
86
86
|
})
|
|
87
87
|
.on(Undo, async (ctx, undo) => {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const actorUrl = undo.actorId?.href || "";
|
|
89
|
+
let inner;
|
|
90
|
+
try {
|
|
91
|
+
inner = await undo.getObject();
|
|
92
|
+
} catch {
|
|
93
|
+
// Inner activity not dereferenceable — can't determine what was undone
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
91
96
|
|
|
92
97
|
if (inner instanceof Follow) {
|
|
93
98
|
await collections.ap_followers.deleteOne({ actorUrl });
|
|
@@ -98,14 +103,14 @@ export function registerInboxListeners(inboxChain, options) {
|
|
|
98
103
|
summary: `${actorUrl} unfollowed you`,
|
|
99
104
|
});
|
|
100
105
|
} else if (inner instanceof Like) {
|
|
101
|
-
const objectId =
|
|
106
|
+
const objectId = inner.objectId?.href || "";
|
|
102
107
|
await collections.ap_activities.deleteOne({
|
|
103
108
|
type: "Like",
|
|
104
109
|
actorUrl,
|
|
105
110
|
objectUrl: objectId,
|
|
106
111
|
});
|
|
107
112
|
} else if (inner instanceof Announce) {
|
|
108
|
-
const objectId =
|
|
113
|
+
const objectId = inner.objectId?.href || "";
|
|
109
114
|
await collections.ap_activities.deleteOne({
|
|
110
115
|
type: "Announce",
|
|
111
116
|
actorUrl,
|
|
@@ -194,18 +199,27 @@ export function registerInboxListeners(inboxChain, options) {
|
|
|
194
199
|
}
|
|
195
200
|
})
|
|
196
201
|
.on(Like, async (ctx, like) => {
|
|
197
|
-
|
|
202
|
+
// Use .objectId to get the URL without dereferencing the remote object.
|
|
203
|
+
// Calling .getObject() would trigger an HTTP fetch to the remote server,
|
|
204
|
+
// which fails with 404 when the server has Authorized Fetch (Secure Mode)
|
|
205
|
+
// enabled — causing pointless retries and log spam.
|
|
206
|
+
const objectId = like.objectId?.href || "";
|
|
198
207
|
|
|
199
208
|
// Only log likes of our own content
|
|
200
209
|
const pubUrl = collections._publicationUrl;
|
|
201
210
|
if (!objectId || (pubUrl && !objectId.startsWith(pubUrl))) return;
|
|
202
211
|
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
actorObj
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
const actorUrl = like.actorId?.href || "";
|
|
213
|
+
let actorName = actorUrl;
|
|
214
|
+
try {
|
|
215
|
+
const actorObj = await like.getActor();
|
|
216
|
+
actorName =
|
|
217
|
+
actorObj?.name?.toString() ||
|
|
218
|
+
actorObj?.preferredUsername?.toString() ||
|
|
219
|
+
actorUrl;
|
|
220
|
+
} catch {
|
|
221
|
+
/* actor not dereferenceable — use URL */
|
|
222
|
+
}
|
|
209
223
|
|
|
210
224
|
await logActivity(collections, storeRawActivities, {
|
|
211
225
|
direction: "inbound",
|
|
@@ -217,18 +231,24 @@ export function registerInboxListeners(inboxChain, options) {
|
|
|
217
231
|
});
|
|
218
232
|
})
|
|
219
233
|
.on(Announce, async (ctx, announce) => {
|
|
220
|
-
|
|
234
|
+
// Use .objectId — no remote fetch needed (see Like handler comment)
|
|
235
|
+
const objectId = announce.objectId?.href || "";
|
|
221
236
|
|
|
222
237
|
// Only log boosts of our own content
|
|
223
238
|
const pubUrl = collections._publicationUrl;
|
|
224
239
|
if (!objectId || (pubUrl && !objectId.startsWith(pubUrl))) return;
|
|
225
240
|
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
actorObj
|
|
230
|
-
|
|
231
|
-
|
|
241
|
+
const actorUrl = announce.actorId?.href || "";
|
|
242
|
+
let actorName = actorUrl;
|
|
243
|
+
try {
|
|
244
|
+
const actorObj = await announce.getActor();
|
|
245
|
+
actorName =
|
|
246
|
+
actorObj?.name?.toString() ||
|
|
247
|
+
actorObj?.preferredUsername?.toString() ||
|
|
248
|
+
actorUrl;
|
|
249
|
+
} catch {
|
|
250
|
+
/* actor not dereferenceable — use URL */
|
|
251
|
+
}
|
|
232
252
|
|
|
233
253
|
await logActivity(collections, storeRawActivities, {
|
|
234
254
|
direction: "inbound",
|
|
@@ -240,11 +260,23 @@ export function registerInboxListeners(inboxChain, options) {
|
|
|
240
260
|
});
|
|
241
261
|
})
|
|
242
262
|
.on(Create, async (ctx, create) => {
|
|
243
|
-
|
|
263
|
+
let object;
|
|
264
|
+
try {
|
|
265
|
+
object = await create.getObject();
|
|
266
|
+
} catch {
|
|
267
|
+
// Remote object not dereferenceable (Authorized Fetch, deleted, etc.)
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
244
270
|
if (!object) return;
|
|
245
271
|
|
|
246
|
-
const
|
|
247
|
-
|
|
272
|
+
const actorUrl = create.actorId?.href || "";
|
|
273
|
+
let actorObj;
|
|
274
|
+
try {
|
|
275
|
+
actorObj = await create.getActor();
|
|
276
|
+
} catch {
|
|
277
|
+
// Actor not dereferenceable — use URL as fallback
|
|
278
|
+
actorObj = null;
|
|
279
|
+
}
|
|
248
280
|
const actorName =
|
|
249
281
|
actorObj?.name?.toString() ||
|
|
250
282
|
actorObj?.preferredUsername?.toString() ||
|
|
@@ -284,7 +316,7 @@ export function registerInboxListeners(inboxChain, options) {
|
|
|
284
316
|
});
|
|
285
317
|
})
|
|
286
318
|
.on(Delete, async (ctx, del) => {
|
|
287
|
-
const objectId =
|
|
319
|
+
const objectId = del.objectId?.href || "";
|
|
288
320
|
if (objectId) {
|
|
289
321
|
await collections.ap_activities.deleteMany({ objectUrl: objectId });
|
|
290
322
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rmdes/indiekit-endpoint-activitypub",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
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",
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
title: __("activitypub.activities"),
|
|
23
23
|
url: mountPath + "/admin/activities"
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
title: pinnedCount + " " + __("activitypub.featured"),
|
|
27
|
+
url: mountPath + "/admin/featured"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
title: tagCount + " " + __("activitypub.featuredTags"),
|
|
31
|
+
url: mountPath + "/admin/tags"
|
|
32
|
+
},
|
|
25
33
|
{
|
|
26
34
|
title: __("activitypub.profile.title"),
|
|
27
35
|
url: mountPath + "/admin/profile"
|