@evanp/activitypub-bot 0.45.17 → 0.45.19

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,24 @@ and this project adheres to
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.45.19] - 2026-05-14
13
+
14
+ ### Changed
15
+
16
+ - Use connection keep-alive for outgoing requests in SafeAgent.
17
+
18
+ ### Fixed
19
+
20
+ - Use AbortSignal.timeout() in fetch() in ActivityPubClient instead of obsolete
21
+ and ignored `timeout` option.
22
+
23
+ ## [0.45.18] - 2026-05-12
24
+
25
+ ### Fixed
26
+
27
+ - Changed how AbortSignal is used in JobQueue to prevent
28
+ memory leak.
29
+
12
30
  ## [0.45.17] - 2026-05-11
13
31
 
14
32
  ### Changed
@@ -538,7 +538,7 @@ export class ActivityPubClient {
538
538
  const fullOptions = {
539
539
  ...options,
540
540
  agent: this.#agent ?? undefined,
541
- timeout: 10000,
541
+ signal: options?.signal ?? AbortSignal.timeout(10000),
542
542
  size: 1024 * 1024,
543
543
  follow: 10
544
544
  }
package/lib/jobqueue.js CHANGED
@@ -46,17 +46,25 @@ export class JobQueue {
46
46
  'dequeueing job'
47
47
  )
48
48
 
49
- while (!res) {
50
- res = await this.#claimNextJob(queueId, jobRunnerId)
51
- if (res) break
52
- delay = Math.min(delay * 2, MAX_DELAY)
53
- this.#logger.debug({ method: 'dequeue', delay }, 'sleeping')
54
- try {
55
- await sleep(delay, null, { signal: AbortSignal.any([this.#ac.signal, this.#wakeAc.signal]) })
56
- } catch (err) {
57
- if (this.#ac.signal.aborted) throw err
58
- delay = 50
49
+ let armed = this.#armCombined()
50
+ try {
51
+ while (!res) {
52
+ res = await this.#claimNextJob(queueId, jobRunnerId)
53
+ if (res) break
54
+ delay = Math.min(delay * 2, MAX_DELAY)
55
+ this.#logger.debug({ method: 'dequeue', delay }, 'sleeping')
56
+ try {
57
+ await sleep(delay, null, { signal: armed.signal })
58
+ } catch (err) {
59
+ if (this.#ac.signal.aborted) throw err
60
+ delay = 50
61
+ // Wake fired — tear down old listeners and arm a fresh combined signal.
62
+ this.#disarmCombined(armed)
63
+ armed = this.#armCombined()
64
+ }
59
65
  }
66
+ } finally {
67
+ this.#disarmCombined(armed)
60
68
  }
61
69
 
62
70
  const jobId = res.job_id
@@ -67,6 +75,24 @@ export class JobQueue {
67
75
  return { jobId, payload, attempts }
68
76
  }
69
77
 
78
+ // Build a combined abort signal manually, avoiding AbortSignal.any() which
79
+ // registers a FinalizationRegistry callback per call (Node's
80
+ // sourceSignalsCleanupRegistry). Under the dequeue loop's call rate, those
81
+ // registrations dominate heap growth.
82
+ #armCombined () {
83
+ const combinedAc = new AbortController()
84
+ const onAbort = () => combinedAc.abort()
85
+ const wakeAc = this.#wakeAc
86
+ this.#ac.signal.addEventListener('abort', onAbort, { once: true })
87
+ wakeAc.signal.addEventListener('abort', onAbort, { once: true })
88
+ return { signal: combinedAc.signal, onAbort, wakeAc }
89
+ }
90
+
91
+ #disarmCombined (armed) {
92
+ this.#ac.signal.removeEventListener('abort', armed.onAbort)
93
+ armed.wakeAc.signal.removeEventListener('abort', armed.onAbort)
94
+ }
95
+
70
96
  async complete (jobId, jobRunnerId) {
71
97
  await this.#connection.query(`
72
98
  DELETE FROM job
package/lib/safeagent.js CHANGED
@@ -19,6 +19,16 @@ class PrivateNetworkError extends Error {
19
19
  }
20
20
 
21
21
  export class SafeAgent extends https.Agent {
22
+ constructor (options = {}) {
23
+ super({
24
+ keepAlive: true,
25
+ keepAliveMsecs: 1000,
26
+ maxSockets: 64,
27
+ maxFreeSockets: 256,
28
+ ...options
29
+ })
30
+ }
31
+
22
32
  createConnection (options, callback) {
23
33
  dns.lookup(options.hostname, (err, address) => {
24
34
  if (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanp/activitypub-bot",
3
- "version": "0.45.17",
3
+ "version": "0.45.19",
4
4
  "description": "server-side ActivityPub bot framework",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",