@evanp/activitypub-bot 0.8.0 → 0.9.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.
- package/README.md +189 -13
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
An ActivityPub server-side bot framework
|
|
4
4
|
|
|
5
|
-
activitypub.bot is [social bot](https://en.wikipedia.org/wiki/Social_bot) server
|
|
5
|
+
activitypub.bot is a [social bot](https://en.wikipedia.org/wiki/Social_bot) server
|
|
6
6
|
which helps developers create and deploy semi-autonomous actors on the
|
|
7
7
|
[ActivityPub](https://activitypub.rocks/) network. Unlike general-purpose social
|
|
8
8
|
networking servers, the bot software does not use a remote API like the
|
|
@@ -23,7 +23,7 @@ activitypub.bot was originally developed as sample code for [ActivityPub: Progra
|
|
|
23
23
|
|
|
24
24
|
## Security
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Please use the form at [https://github.com/evanp/activitypub-bot/security](https://github.com/evanp/activitypub-bot/security) to report a vulnerability privately.
|
|
27
27
|
|
|
28
28
|
## Background
|
|
29
29
|
|
|
@@ -37,36 +37,212 @@ The easiest way to install this server is using [Helm](https://helm.sh). See the
|
|
|
37
37
|
|
|
38
38
|
There is also a Docker image at [ghcr.io/evanp/activitypub-bot](https://ghcr.io/evanp/activitypub-bot).
|
|
39
39
|
|
|
40
|
-
It's also an [npm](https://npmjs.org/) package.
|
|
40
|
+
It's also an [npm](https://npmjs.org/) package, [@evanp/activitypub-bot](https://www.npmjs.com/package/@evanp/activitypub-bot).
|
|
41
41
|
|
|
42
42
|
## Usage
|
|
43
43
|
|
|
44
|
+
The server works as an ActivityPub server; bots appear as ActivityPub "actors".
|
|
45
|
+
|
|
46
|
+
### Environment variables
|
|
47
|
+
|
|
48
|
+
The package can be configured with the following environment variables.
|
|
49
|
+
|
|
50
|
+
#### DATABASE_URL
|
|
51
|
+
|
|
52
|
+
A [sequelize](https://sequelize.org) database URI for storing the server data. The default is 'sqlite::memory', which will store data in memory and lose the data when the process shuts down; you probably don't want that. The server comes with Postgres, MySQL, and SQLite libraries; you might need to install libraries if you're using some other dialect.
|
|
53
|
+
|
|
54
|
+
The URI format varies by database backend; see [Postgres](https://www.postgresql.org/docs/current/libpq-connect.html), [MySQL](https://dev.mysql.com/doc/refman/8.0/en/connecting-using-uri-or-key-value-pairs.html), or [SQLite](https://sqlite.org/uri.html).
|
|
55
|
+
|
|
56
|
+
The server creates and alters tables at runtime; whatever user you use to connect should have rights to do those things.
|
|
57
|
+
|
|
58
|
+
#### ORIGIN
|
|
59
|
+
|
|
60
|
+
The [origin](https://developer.mozilla.org/en-US/docs/Web/API/URL/origin) (protocol + hostname) for the server. This will only be used for formatting IDs, not for running the server. Use this if you're running the server
|
|
61
|
+
behind a load balancer or inside a Kubernetes cluster.
|
|
62
|
+
|
|
63
|
+
The default is 'https://activitypubbot.test', which doesn't work and probably isn't what you want.
|
|
64
|
+
|
|
65
|
+
#### PORT
|
|
66
|
+
|
|
67
|
+
The [port](https://en.wikipedia.org/wiki/Port_(computer_networking)) number to listen on. This is only used for connection; URLs are created using [ORIGIN](#origin). Must be an integer number between 1 and 65535; the default is 9000.
|
|
68
|
+
|
|
69
|
+
#### LOG_LEVEL
|
|
70
|
+
|
|
71
|
+
The minimum [pino](https://getpino.io) [log level](https://getpino.io/#/docs/api?id=logger-level) to output. This can be `trace`, `debug`, `info`, `warn`, `error`, `fatal`, or `silent`. Whatever the log level is, messages with
|
|
72
|
+
lower log levels won't appear in the logs. For example, if the log level is `info`, debug and trace log messages will be silently dropped. `silent` turns off logging altogether.
|
|
73
|
+
|
|
74
|
+
The default is `info` (or `silent` when running unit tests).
|
|
75
|
+
|
|
76
|
+
#### BOTS_CONFIG_FILE
|
|
77
|
+
|
|
78
|
+
The path to the [config file](#config_file) for this server, which defines the usernames and code for the bots for this server. The default is to use the shipped default bot config file, which defines an [OKBot](#okbot) named `ok` and a [DoNothingBot](#donothingbot) named `null`.
|
|
79
|
+
|
|
80
|
+
### Config file
|
|
81
|
+
|
|
82
|
+
The config file defines the bots provided by this server.
|
|
83
|
+
|
|
84
|
+
The config file is implemented as a JavaScript module. It should export a single object mapping a string name for the bot to an instance of a classes that implements the [Bot](#bot) interface.
|
|
85
|
+
|
|
86
|
+
For example, the default config file declares two bot accounts: an [OKBot](#okbot) named `ok` and a [DoNothingBot](#donothingbot) named `null`.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
import DoNothingBot from '../lib/bots/donothing.js'
|
|
90
|
+
import OKBot from '../lib/bots/ok.js'
|
|
91
|
+
|
|
92
|
+
export default {
|
|
93
|
+
ok: new OKBot('ok'),
|
|
94
|
+
null: new DoNothingBot('null')
|
|
95
|
+
}
|
|
44
96
|
```
|
|
45
|
-
```
|
|
46
97
|
|
|
47
|
-
|
|
98
|
+
### Pre-installed bot classes
|
|
99
|
+
|
|
100
|
+
The following bot classes are pre-installed with the server.
|
|
101
|
+
|
|
102
|
+
#### OKBot
|
|
48
103
|
|
|
49
|
-
|
|
104
|
+
An *OKBot* instance will reply to any message that it's mentioned in with the constant string 'OK'.
|
|
105
|
+
|
|
106
|
+
#### DoNothingBot
|
|
107
|
+
|
|
108
|
+
A *DoNothingBot* instance will only do default stuff, like accepting follows.
|
|
50
109
|
|
|
51
110
|
## API
|
|
52
111
|
|
|
53
|
-
|
|
112
|
+
New bot classes must implement the [Bot](#bot) interface, which is easiest if you inherit from the `Bot` class. Bots will receive a [BotContext](#botcontext) object at initialization. The BotContext is the main way to access data or execute activities.
|
|
54
113
|
|
|
55
|
-
|
|
114
|
+
### Bot
|
|
56
115
|
|
|
57
|
-
|
|
116
|
+
The Bot interface has the following methods.
|
|
117
|
+
|
|
118
|
+
#### constructor (username)
|
|
119
|
+
|
|
120
|
+
The constructor; receives the `username` by default. Initialization should probably be deferred to the initialize() method. The default implementation stores the username.
|
|
121
|
+
|
|
122
|
+
#### async initialize (context)
|
|
123
|
+
|
|
124
|
+
Initializes the bot with the given [BotContext](#botcontext). The default implementation stores the context for later use.
|
|
125
|
+
|
|
126
|
+
#### get fullname ()
|
|
127
|
+
|
|
128
|
+
A [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) for the full name of the bot.
|
|
129
|
+
|
|
130
|
+
#### get description ()
|
|
131
|
+
|
|
132
|
+
A [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) for the bio of the bot.
|
|
133
|
+
|
|
134
|
+
#### get username ()
|
|
135
|
+
|
|
136
|
+
A [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) for the username of the bot. Should match the constructor argument.
|
|
137
|
+
|
|
138
|
+
#### get _context ()
|
|
139
|
+
|
|
140
|
+
A protected [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) for the context of the bot. (The default implementation stashes the context in a private variable, so this protected
|
|
141
|
+
getter is needed to retrieve it.)
|
|
142
|
+
|
|
143
|
+
#### async onMention (object, activity)
|
|
144
|
+
|
|
145
|
+
Called when the bot is mentioned in an incoming object. Can be used to implement conversational interfaces. `object` is the object of a `Create` activity, like a `Note`, that mentions the bot; it's represented in [activitystrea.ms](#activitystreams) format. `activity` is the activity itself.
|
|
146
|
+
|
|
147
|
+
### BotContext
|
|
58
148
|
|
|
59
|
-
|
|
149
|
+
This is the bot's control panel for working with the rest of the server.
|
|
150
|
+
|
|
151
|
+
#### get botID ()
|
|
152
|
+
|
|
153
|
+
Returns the username of the bot this context was created for.
|
|
154
|
+
|
|
155
|
+
#### get logger ()
|
|
156
|
+
|
|
157
|
+
A [pino](https://getpino.io/) [Logger](https://getpino.io/#/docs/api?id=logger) instance to use for logging messages.
|
|
158
|
+
|
|
159
|
+
#### async setData (key, value)
|
|
160
|
+
|
|
161
|
+
There's a simple key-value data store for bots to keep private data. `key` must be a string (max 512 characters); `value` is any JavaScript value that can be serialized as JSON using [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
|
|
162
|
+
|
|
163
|
+
#### async getData (key)
|
|
164
|
+
|
|
165
|
+
Returns the data previously stored for this key. If it doesn't exist, throws a `NoSuchValueError`. Use `hasData(key)` to check for existence.
|
|
166
|
+
|
|
167
|
+
#### async deleteData (key)
|
|
168
|
+
|
|
169
|
+
Deletes the data stored for this key. There's no backup; it's just gone.
|
|
170
|
+
|
|
171
|
+
#### async hasData (key)
|
|
172
|
+
|
|
173
|
+
Checks to see if any data has been previously stored with this key; returns a boolean.
|
|
174
|
+
|
|
175
|
+
#### async getObject (id)
|
|
176
|
+
|
|
177
|
+
Given an [ActivityPub object identifier](https://www.w3.org/TR/activitypub/#obj-id), returns an [activitystrea.ms](#activitystreams) object.
|
|
178
|
+
|
|
179
|
+
#### async sendNote (content, { to, cc, bto, bcc, audience, inReplyTo, thread, context, conversation })
|
|
180
|
+
|
|
181
|
+
Sends an Activity Streams `Note` with the given `content`. The content will be converted to HTML safely, and transformed according to social microtext rules:
|
|
182
|
+
|
|
183
|
+
- `@username@server.example`: transformed into a link to a user, and a `Mention`
|
|
184
|
+
- `#hashtag`: transformed into a hashtag link, and a `Hashtag` is added to the Note object
|
|
185
|
+
- `https://example.com/` : transformed into a link
|
|
186
|
+
|
|
187
|
+
The optional additional parameters are strings used for ActivityPub properties of the object:
|
|
188
|
+
|
|
189
|
+
- `to`, `cc`, `bto`, `bcc`, `audience`: addressing properties
|
|
190
|
+
- `inReplyTo`: the object the note is in reply to
|
|
191
|
+
- `thread`, `context`, `conversation`: the thread the object is in
|
|
192
|
+
|
|
193
|
+
#### async sendReply (content, object)
|
|
194
|
+
|
|
195
|
+
A shortcut for sending a reply with `content` to the `object`. Extracts and configures the right addressing properties and threading properties from `object`, and passes them to `sendNote()`.
|
|
196
|
+
|
|
197
|
+
#### async likeObject (obj)
|
|
198
|
+
|
|
199
|
+
Sends a `Like` activity for the passed-in object in [activitystrea.ms](#activitystreams) form.
|
|
200
|
+
|
|
201
|
+
#### async unlikeObject (obj)
|
|
202
|
+
|
|
203
|
+
Sends an `Undo`/`Like` activity for the passed-in object in [activitystrea.ms](#activitystreams) form which was previously liked.
|
|
204
|
+
|
|
205
|
+
#### async followActor (actor)
|
|
206
|
+
|
|
207
|
+
Sends a `Follow` activity for the passed-in actor in [activitystrea.ms](#activitystreams) form.
|
|
208
|
+
|
|
209
|
+
#### async unfollowActor (actor)
|
|
210
|
+
|
|
211
|
+
Sends an `Undo`/`Follow` activity for the passed-in actor in [activitystrea.ms](#activitystreams) form.
|
|
212
|
+
|
|
213
|
+
#### async blockActor (actor)
|
|
214
|
+
|
|
215
|
+
Sends a `Block` activity for the passed-in actor in [activitystrea.ms](#activitystreams) form.
|
|
216
|
+
|
|
217
|
+
#### async unblockActor (actor)
|
|
218
|
+
|
|
219
|
+
Sends an `Undo`/`Block` activity for the passed-in actor in [activitystrea.ms](#activitystreams) form.
|
|
220
|
+
|
|
221
|
+
#### async toActorId (webfinger)
|
|
222
|
+
|
|
223
|
+
Gets the `id` of the [ActivityPub Actor](https://www.w3.org/TR/activitypub/#actors) with the given [WebFinger](https://en.wikipedia.org/wiki/WebFinger) identity.
|
|
224
|
+
|
|
225
|
+
#### async toWebfinger (actorId)
|
|
226
|
+
|
|
227
|
+
Gets the [WebFinger](https://en.wikipedia.org/wiki/WebFinger) identity of the [ActivityPub Actor](https://www.w3.org/TR/activitypub/#actors) with the given `id`.
|
|
228
|
+
|
|
229
|
+
### activitystrea.ms
|
|
230
|
+
|
|
231
|
+
Activity Streams 2.0 objects are represented internally as [activitystrea.ms](https://www.npmjs.com/package/activitystrea.ms) library objects.
|
|
232
|
+
|
|
233
|
+
## Contributing
|
|
60
234
|
|
|
61
235
|
PRs accepted.
|
|
62
236
|
|
|
63
|
-
|
|
237
|
+
JavaScript code should use [JavaScript Standard Style](https://standardjs.com).
|
|
238
|
+
|
|
239
|
+
There is a test suite using the Node [test runner](https://nodejs.org/api/test.html#test-runner). If you add a new feature, add tests for it. If you find a bug and fix it, add a test to make sure it stays fixed.
|
|
64
240
|
|
|
65
|
-
|
|
241
|
+
If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
|
|
66
242
|
|
|
67
243
|
## License
|
|
68
244
|
|
|
69
|
-
Copyright (C) 2023-
|
|
245
|
+
Copyright (C) 2023-2026 Evan Prodromou <evan@prodromou.name>
|
|
70
246
|
|
|
71
247
|
This program is free software: you can redistribute it and/or modify
|
|
72
248
|
it under the terms of the GNU Affero General Public License as published
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evanp/activitypub-bot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "server-side ActivityPub bot framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@isaacs/ttlcache": "^1.4.1",
|
|
29
29
|
"activitystrea.ms": "3.2",
|
|
30
|
-
"express": "^4.
|
|
30
|
+
"express": "^4.22.1",
|
|
31
31
|
"http-errors": "^2.0.0",
|
|
32
32
|
"humanhash": "^1.0.4",
|
|
33
33
|
"lru-cache": "^11.1.0",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"node-fetch": "^3.3.2",
|
|
36
36
|
"p-queue": "^8.1.0",
|
|
37
37
|
"pino": "^9.7.0",
|
|
38
|
-
"pino-http": "^
|
|
38
|
+
"pino-http": "^11.0.0",
|
|
39
39
|
"sequelize": "^6.37.7"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"nock": "^14.0.5",
|
|
43
43
|
"standard": "^17.1.2",
|
|
44
|
-
"supertest": "^7.1.
|
|
44
|
+
"supertest": "^7.1.4"
|
|
45
45
|
},
|
|
46
46
|
"optionalDependencies": {
|
|
47
47
|
"mysql2": "^3.9.1",
|
|
48
|
-
"pg": "^8.16.
|
|
48
|
+
"pg": "^8.16.3",
|
|
49
49
|
"sqlite3": "^5.1.7"
|
|
50
50
|
}
|
|
51
51
|
}
|