@evanp/activitypub-bot 0.53.1 → 0.54.2
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 +43 -1
- package/README.md +30 -1
- package/lib/botcontext.js +17 -3
- package/lib/bots/ok.js +31 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,45 @@ and this project adheres to
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.54.2] - 2026-10-09
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Authenticate Docker Hub pulls for PostgreSQL and Redis service containers
|
|
17
|
+
in the release integration tests using repository secrets, avoiding the
|
|
18
|
+
unauthenticated pull rate limit.
|
|
19
|
+
|
|
20
|
+
## [0.54.1] - 2026-10-09
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Restore "OK" as OKBot's default reply content and update the default
|
|
25
|
+
description to match. Custom response content remains configurable.
|
|
26
|
+
- Update the actor route test to expect OKBot's fullname default of the
|
|
27
|
+
username followed by " bot".
|
|
28
|
+
|
|
29
|
+
## [0.54.0] - 2026-10-09
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Configure OKBot with a fixed response or an array of randomly selected
|
|
34
|
+
responses, a content language, and custom fullname and description.
|
|
35
|
+
- Support an optional `language` option in `BotContext.sendNote()` and a third
|
|
36
|
+
language argument in `sendReply()`. Notes always include `content` and also
|
|
37
|
+
include `contentMap` when a language is supplied.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Default OKBot replies to its username and fullname to its username followed
|
|
42
|
+
by " bot". The shipped `ok` bot now replies with "ok" instead of "OK" and
|
|
43
|
+
uses "ok bot" instead of "OK Bot" as its fullname. Default descriptions
|
|
44
|
+
reflect the configured response content.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- Keep single-language `contentMap` entries synchronized with `content` when
|
|
49
|
+
updating a Note through `BotContext.updateNote()`.
|
|
50
|
+
|
|
12
51
|
## [0.53.1] - 2026-10-09
|
|
13
52
|
|
|
14
53
|
### Security
|
|
@@ -1720,7 +1759,10 @@ Hot patch on the `stable` branch.
|
|
|
1720
1759
|
- Docker multi-platform build workflow.
|
|
1721
1760
|
- Dependabot configuration.
|
|
1722
1761
|
|
|
1723
|
-
[Unreleased]: https://github.com/evanp/activitypub-bot/compare/v0.
|
|
1762
|
+
[Unreleased]: https://github.com/evanp/activitypub-bot/compare/v0.54.2...HEAD
|
|
1763
|
+
[0.54.2]: https://github.com/evanp/activitypub-bot/compare/v0.54.1...v0.54.2
|
|
1764
|
+
[0.54.1]: https://github.com/evanp/activitypub-bot/compare/v0.54.0...v0.54.1
|
|
1765
|
+
[0.54.0]: https://github.com/evanp/activitypub-bot/compare/v0.53.1...v0.54.0
|
|
1724
1766
|
[0.53.1]: https://github.com/evanp/activitypub-bot/compare/v0.53.0...v0.53.1
|
|
1725
1767
|
[0.53.0]: https://github.com/evanp/activitypub-bot/compare/v0.52.2...v0.53.0
|
|
1726
1768
|
[0.52.2]: https://github.com/evanp/activitypub-bot/compare/v0.52.1...v0.52.2
|
package/README.md
CHANGED
|
@@ -198,7 +198,36 @@ The following bot classes are pre-installed with the server.
|
|
|
198
198
|
|
|
199
199
|
#### OKBot
|
|
200
200
|
|
|
201
|
-
An *OKBot* instance
|
|
201
|
+
An *OKBot* instance replies when mentioned, using "OK" as the default
|
|
202
|
+
response. The shipped `ok` bot replies with "OK" and has the fullname "ok bot".
|
|
203
|
+
Each message receives at most one reply. When the author's WebFinger handle is
|
|
204
|
+
available, the reply starts with a mention of that author.
|
|
205
|
+
|
|
206
|
+
The constructor accepts a username and an optional options object:
|
|
207
|
+
|
|
208
|
+
| Option | Behavior | Default |
|
|
209
|
+
| --- | --- | --- |
|
|
210
|
+
| `content` | A response string or a nonempty array of response strings. An array selects one response at random for each new mention; a string behaves like a one-element array. | `"OK"`. |
|
|
211
|
+
| `language` | A BCP 47 language tag, such as `fr` or `fr-CA`, for the outgoing Note's content. | Untagged. |
|
|
212
|
+
| `fullname` | The bot's display name. | The username followed by " bot". |
|
|
213
|
+
| `description` | The bot's profile description. | See below. |
|
|
214
|
+
|
|
215
|
+
With default content or a configured string, the default description is
|
|
216
|
+
`A bot that says "<response>" when mentioned.` With a configured array,
|
|
217
|
+
including a one-element array, it is
|
|
218
|
+
`A bot that says random things when mentioned.` An explicit description
|
|
219
|
+
overrides either default. With no configured content, the description is
|
|
220
|
+
`A bot that says "OK" when mentioned.`
|
|
221
|
+
|
|
222
|
+
Outgoing Notes always include rendered HTML in `content`. When `language` is
|
|
223
|
+
supplied, they also include the same HTML in `contentMap` under that language
|
|
224
|
+
tag. Language keys are normalized to lowercase, so `fr-CA` is published as
|
|
225
|
+
`fr-ca`.
|
|
226
|
+
|
|
227
|
+
For a Magic 8-Ball-style bot, configure `content` with an array of answers such
|
|
228
|
+
as "Yes", "No", and "Ask again later", and set `fullname` to "Magic 8-Ball".
|
|
229
|
+
Other options supported by [Bot](#bot), such as `icon` and `image`, can also be
|
|
230
|
+
supplied.
|
|
202
231
|
|
|
203
232
|
#### DoNothingBot
|
|
204
233
|
|
package/lib/botcontext.js
CHANGED
|
@@ -118,7 +118,7 @@ export class BotContext {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
async sendNote (content, { to, cc, bto, bcc, audience, inReplyTo, thread, context, conversation }) {
|
|
121
|
+
async sendNote (content, { to, cc, bto, bcc, audience, inReplyTo, thread, context, conversation, language }) {
|
|
122
122
|
assert.ok(content)
|
|
123
123
|
assert.equal(typeof content, 'string')
|
|
124
124
|
assert.ok(to || cc || bto || bcc || audience)
|
|
@@ -129,6 +129,7 @@ export class BotContext {
|
|
|
129
129
|
type: 'note',
|
|
130
130
|
nanoid: noteNanoid
|
|
131
131
|
}
|
|
132
|
+
const optional = {}
|
|
132
133
|
if (!inReplyTo) {
|
|
133
134
|
if (!thread) {
|
|
134
135
|
thread = this.#formatter.format({ ...idProps, collection: 'thread' })
|
|
@@ -140,6 +141,9 @@ export class BotContext {
|
|
|
140
141
|
conversation = thread
|
|
141
142
|
}
|
|
142
143
|
}
|
|
144
|
+
if (language) {
|
|
145
|
+
optional.contentMap = { [language]: html }
|
|
146
|
+
}
|
|
143
147
|
const note = await as2.import({
|
|
144
148
|
'@context': [
|
|
145
149
|
'https://www.w3.org/ns/activitystreams',
|
|
@@ -163,7 +167,8 @@ export class BotContext {
|
|
|
163
167
|
thread,
|
|
164
168
|
'ostatus:conversation': conversation,
|
|
165
169
|
published: new Date().toISOString(),
|
|
166
|
-
attributedTo: this.#formatter.format({ username: this.#botId })
|
|
170
|
+
attributedTo: this.#formatter.format({ username: this.#botId }),
|
|
171
|
+
...optional
|
|
167
172
|
})
|
|
168
173
|
await this.#objectStorage.create(note)
|
|
169
174
|
await this.#doActivity({
|
|
@@ -183,7 +188,7 @@ export class BotContext {
|
|
|
183
188
|
return note
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
async sendReply (content, object) {
|
|
191
|
+
async sendReply (content, object, language = null) {
|
|
187
192
|
const r = this.#getRecipients(object)
|
|
188
193
|
const attributedTo = object.attributedTo?.first?.id
|
|
189
194
|
if (r.to) {
|
|
@@ -211,6 +216,9 @@ export class BotContext {
|
|
|
211
216
|
if (conversationProp) {
|
|
212
217
|
opt.conversation = Array.from(conversationProp)[0]
|
|
213
218
|
}
|
|
219
|
+
if (language) {
|
|
220
|
+
opt.language = language
|
|
221
|
+
}
|
|
214
222
|
return await this.sendNote(content, opt)
|
|
215
223
|
}
|
|
216
224
|
|
|
@@ -348,6 +356,12 @@ export class BotContext {
|
|
|
348
356
|
assert.equal(typeof content, 'string')
|
|
349
357
|
const exported = await note.export({ useOriginalContext: true })
|
|
350
358
|
exported.content = content
|
|
359
|
+
if ('contentMap' in exported) {
|
|
360
|
+
const keys = Object.keys(exported.contentMap)
|
|
361
|
+
if (keys.length === 1) {
|
|
362
|
+
exported.contentMap[keys[0]] = content
|
|
363
|
+
}
|
|
364
|
+
}
|
|
351
365
|
const updated = await as2.import(exported)
|
|
352
366
|
const { to, cc, bto, bcc, audience } = this.#getRecipients(note)
|
|
353
367
|
await this.#objectStorage.update(updated)
|
package/lib/bots/ok.js
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import Bot from '../bot.js'
|
|
2
2
|
|
|
3
3
|
export default class OKBot extends Bot {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
4
|
+
#content
|
|
5
|
+
#language
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
constructor (username, options = {}) {
|
|
8
|
+
const says = ('content' in options)
|
|
9
|
+
? Array.isArray(options.content)
|
|
10
|
+
? 'random things'
|
|
11
|
+
: `"${options.content}"`
|
|
12
|
+
: '"OK"'
|
|
13
|
+
options = {
|
|
14
|
+
fullname: `${username} bot`,
|
|
15
|
+
description: `A bot that says ${says} when mentioned.`,
|
|
16
|
+
...options
|
|
17
|
+
}
|
|
18
|
+
super(username, options)
|
|
19
|
+
this.#content = ('content' in options)
|
|
20
|
+
? (Array.isArray(options.content))
|
|
21
|
+
? options.content
|
|
22
|
+
: [options.content]
|
|
23
|
+
: ['OK']
|
|
24
|
+
this.#language = ('language' in options)
|
|
25
|
+
? options.language
|
|
26
|
+
: null
|
|
10
27
|
}
|
|
11
28
|
|
|
12
29
|
async onMention (object, activity) {
|
|
@@ -27,14 +44,16 @@ export default class OKBot extends Bot {
|
|
|
27
44
|
'attributed to'
|
|
28
45
|
)
|
|
29
46
|
const wf = await this._context.toWebfinger(attributedTo)
|
|
30
|
-
const
|
|
47
|
+
const response = this.#response()
|
|
48
|
+
const content = (wf) ? `@${wf} ${response}` : response
|
|
31
49
|
this._context.logger.info({
|
|
32
50
|
object: object.id,
|
|
33
51
|
attributedTo,
|
|
34
52
|
wf,
|
|
35
53
|
content
|
|
36
54
|
}, 'sending reply')
|
|
37
|
-
|
|
55
|
+
|
|
56
|
+
const reply = await this._context.sendReply(content, object, this.#language)
|
|
38
57
|
this._context.logger.info({
|
|
39
58
|
reply: reply.id,
|
|
40
59
|
content,
|
|
@@ -55,4 +74,9 @@ export default class OKBot extends Bot {
|
|
|
55
74
|
const key = `seen:${id}`
|
|
56
75
|
return this._context.setData(key, true)
|
|
57
76
|
}
|
|
77
|
+
|
|
78
|
+
#response () {
|
|
79
|
+
const idx = Math.floor(Math.random() * this.#content.length)
|
|
80
|
+
return this.#content[idx]
|
|
81
|
+
}
|
|
58
82
|
}
|