@evanp/activitypub-bot 0.20.0 → 0.21.0

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.
@@ -2,6 +2,10 @@ import BotMaker from './botmaker.js'
2
2
  import assert from 'node:assert'
3
3
  import as2 from './activitystreams.js'
4
4
  import PQueue from 'p-queue'
5
+ import * as ttlcachePkg from '@isaacs/ttlcache'
6
+
7
+ const TTLCache =
8
+ ttlcachePkg.TTLCache ?? ttlcachePkg.default ?? ttlcachePkg
5
9
 
6
10
  const NS = 'https://www.w3.org/ns/activitystreams#'
7
11
 
@@ -19,7 +23,8 @@ const COLLECTION_TYPES = [
19
23
  export class ActivityDeliverer {
20
24
  static #MAX_ALL_QUEUE = 16
21
25
  static #MAX_BOT_QUEUE = 32
22
-
26
+ static #TTL_SEEN_PUBLIC = 3 * 24 * 60 * 60 * 1000 // 3 days
27
+ static #MAX_SEEN_PUBLIC = 1000000
23
28
  #actorStorage
24
29
  #activityHandler
25
30
  #formatter
@@ -27,6 +32,7 @@ export class ActivityDeliverer {
27
32
  #client
28
33
  #deliverAllQueue
29
34
  #deliverBotQueue
35
+ #seenPublic
30
36
 
31
37
  constructor (actorStorage, activityHandler, formatter, logger, client) {
32
38
  this.#actorStorage = actorStorage
@@ -36,6 +42,10 @@ export class ActivityDeliverer {
36
42
  this.#logger = logger.child({ class: this.constructor.name })
37
43
  this.#deliverAllQueue = new PQueue({ max: ActivityDeliverer.#MAX_ALL_QUEUE })
38
44
  this.#deliverBotQueue = new PQueue({ max: ActivityDeliverer.#MAX_BOT_QUEUE })
45
+ this.#seenPublic = new TTLCache({
46
+ ttl: ActivityDeliverer.#TTL_SEEN_PUBLIC,
47
+ max: ActivityDeliverer.#MAX_SEEN_PUBLIC
48
+ })
39
49
  }
40
50
 
41
51
  getActor (activity) {
@@ -53,6 +63,38 @@ export class ActivityDeliverer {
53
63
  return r
54
64
  }
55
65
 
66
+ isPublic (activity) {
67
+ for (const prop of ['to', 'cc', 'audience']) {
68
+ const vals = activity.get(prop)
69
+ if (vals) {
70
+ for (const val of vals) {
71
+ if (this.#isPublic(val)) {
72
+ return true
73
+ }
74
+ }
75
+ }
76
+ }
77
+ return false
78
+ }
79
+
80
+ async deliverPublic (activity, bots) {
81
+ if (!this.#seenPublic.has(activity.id)) {
82
+ await Promise.all(Object.values(bots).map(async (bot) => {
83
+ let result
84
+ try {
85
+ result = await bot.onPublic(activity)
86
+ } catch (err) {
87
+ this.#logger.warn(
88
+ { err, activity: activity.id, bot: bot.id },
89
+ 'Error handling public activity for bot'
90
+ )
91
+ }
92
+ return result
93
+ }))
94
+ this.#seenPublic.set(activity.id, true)
95
+ }
96
+ }
97
+
56
98
  async deliverTo (activity, bot) {
57
99
  this.#deliverBotQueue.add(() =>
58
100
  this.#deliverTo(activity, bot)
@@ -99,7 +141,7 @@ export class ActivityDeliverer {
99
141
  this.#logger.debug(`Checking recipient ${recipient.id}`)
100
142
  if (this.#isPublic(recipient)) {
101
143
  this.#logger.debug(`Public recipient for ${activity.id}`)
102
- await this.#deliverPublic(activity, bots)
144
+ await this.deliverPublic(activity, bots)
103
145
  } else if (this.#isLocal(recipient)) {
104
146
  this.#logger.debug(`Local recipient for ${activity.id}`)
105
147
  const parts = this.#formatter.unformat(recipient.id)
@@ -242,10 +284,6 @@ export class ActivityDeliverer {
242
284
  return !!recipient.inbox?.first?.id
243
285
  }
244
286
 
245
- async #deliverPublic (activity, bots) {
246
- await Promise.all(Object.values(bots).map(bot => bot.onPublic(activity)))
247
- }
248
-
249
287
  async #deliverLocalFollowersCollection (activity, username, bots, deliveredTo) {
250
288
  const id = this.#formatter.format({ username })
251
289
  const followed = await as2.import({ id })
@@ -17,7 +17,7 @@ export default class RelayServerBot extends Bot {
17
17
  }
18
18
 
19
19
  get description () {
20
- return 'A bot for subscribing to relays'
20
+ return 'A bot for accepting relay subscriptions'
21
21
  }
22
22
 
23
23
  async handleActivity (activity) {
@@ -65,6 +65,10 @@ router.post('/user/:username/inbox', async (req, res, next) => {
65
65
 
66
66
  await deliverer.deliverTo(activity, bot)
67
67
 
68
+ if (deliverer.isPublic(activity)) {
69
+ await deliverer.deliverPublic(activity, bots)
70
+ }
71
+
68
72
  res.status(202)
69
73
  res.type('text/plain')
70
74
  res.send(http.STATUS_CODES[202])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanp/activitypub-bot",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "server-side ActivityPub bot framework",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",