@evanp/activitypub-bot 0.48.2 → 0.49.1

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/CHANGELOG.md CHANGED
@@ -9,6 +9,16 @@ and this project adheres to
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.49.1] - 2026-06-28
13
+
14
+ ### Added
15
+
16
+ - Log subject in inbox and shared inbox
17
+
18
+ ## [0.49.0] - 2026-06-28
19
+
20
+ - New forceUnsubscribe argument for MastodonRelayClient, to force it
21
+ to unsubscribe unconditionally to an array of actors.
12
22
  - Missing required `instance` property in /nodeinfo/2.2.
13
23
 
14
24
  ## [0.48.2] - 2026-06-04
package/lib/botcontext.js CHANGED
@@ -33,6 +33,10 @@ export class BotContext {
33
33
  return this.#botId
34
34
  }
35
35
 
36
+ get botActorId () {
37
+ return this.#formatter.format({ username: this.#botId })
38
+ }
39
+
36
40
  get logger () {
37
41
  return this.#logger
38
42
  }
@@ -10,7 +10,7 @@ const ANNOUNCE = `${NS}Announce`
10
10
  export default class MastodonRelayClientBot extends Bot {
11
11
  #relay
12
12
  #relayForwarding
13
-
13
+ #forceUnsubscribe
14
14
  constructor (username, options = {}) {
15
15
  if (typeof username !== 'string') {
16
16
  throw new Error('username must be a string')
@@ -29,6 +29,16 @@ export default class MastodonRelayClientBot extends Bot {
29
29
  this.#relayForwarding = ('relayForwarding' in options)
30
30
  ? options.relayForwarding
31
31
  : true
32
+ if (options.forceUnsubscribe) {
33
+ if (!Array.isArray(options.forceUnsubscribe)) {
34
+ throw new Error('forceUnsubscribe option must be an array')
35
+ }
36
+ const fus = new Set(options.forceUnsubscribe)
37
+ if (this.#relay.some(x => fus.has(x))) {
38
+ throw new Error('forceUnsubscribe option must not overlap with relay option')
39
+ }
40
+ }
41
+ this.#forceUnsubscribe = options.forceUnsubscribe || []
32
42
  }
33
43
 
34
44
  get type () {
@@ -50,6 +60,22 @@ export default class MastodonRelayClientBot extends Bot {
50
60
  'Initialising relay client'
51
61
  )
52
62
 
63
+ assert.ok(Array.isArray(this.#forceUnsubscribe))
64
+
65
+ for (const id of this.#forceUnsubscribe) {
66
+ const actor = await this._context.getObject(id)
67
+ if (actor) {
68
+ try {
69
+ await this.#unfollowRelay(actor)
70
+ } catch (err) {
71
+ this._context.logger.warn(
72
+ { err, actorId: id },
73
+ 'Error unfollowing actor; skipping'
74
+ )
75
+ }
76
+ }
77
+ }
78
+
53
79
  assert.ok(Array.isArray(this.#relay))
54
80
 
55
81
  const toFollow = new Set(this.#relay)
@@ -107,20 +133,36 @@ export default class MastodonRelayClientBot extends Bot {
107
133
  }
108
134
 
109
135
  async #unfollowRelay (actor) {
110
- const activityId = await this.#getFollowActivity(actor)
111
136
  this._context.logger.info(
112
- { relay: actor.id, activity: activityId },
137
+ { relay: actor.id },
113
138
  'Unfollowing relay'
114
139
  )
115
- await this._context.doActivity({
140
+ let activityId
141
+ try {
142
+ activityId = await this.#getFollowActivity(actor)
143
+ this._context.logger.info(
144
+ { relay: actor.id, activityId },
145
+ 'Follow activity found when unfollowing relay'
146
+ )
147
+ } catch (err) {
148
+ this._context.logger.warn(
149
+ { relay: actor.id },
150
+ 'No follow activity found when unfollowing relay'
151
+ )
152
+ }
153
+ const undo = {
116
154
  to: actor.id,
117
155
  type: 'Undo',
118
156
  object: {
119
- id: activityId,
120
157
  type: 'Follow',
158
+ actor: this._context.botActorId,
121
159
  object: 'https://www.w3.org/ns/activitystreams#Public'
122
160
  }
123
- })
161
+ }
162
+ if (activityId) {
163
+ undo.object.id = activityId
164
+ }
165
+ await this._context.doActivity(undo)
124
166
  this._context.logger.info(
125
167
  { relay: actor.id },
126
168
  'Clearing follow data'
@@ -75,7 +75,7 @@ router.post('/user/:username/inbox', async (req, res, next) => {
75
75
  }
76
76
 
77
77
  logger.info(
78
- { reqId: req.id, activity: activity.id, bot: bot.username },
78
+ { reqId: req.id, activity: activity.id, bot: bot.username, subject },
79
79
  'Activity received at bot inbox'
80
80
  )
81
81
 
@@ -72,7 +72,7 @@ router.post('/shared/inbox', async (req, res, next) => {
72
72
  }
73
73
 
74
74
  logger.info(
75
- { reqId: req.id, activity: activity.id },
75
+ { reqId: req.id, activity: activity.id, subject },
76
76
  'Activity received at shared inbox'
77
77
  )
78
78
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanp/activitypub-bot",
3
- "version": "0.48.2",
3
+ "version": "0.49.1",
4
4
  "description": "server-side ActivityPub bot framework",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",