@fedify/relay 2.0.0-pr.490.2 → 2.0.0-pr.559.4
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/LICENSE +1 -1
- package/README.md +159 -53
- package/dist/litepub.test.d.ts +3 -0
- package/dist/litepub.test.js +701 -0
- package/dist/mastodon.test.d.ts +3 -0
- package/dist/mastodon.test.js +664 -0
- package/dist/mod.cjs +345 -287
- package/dist/mod.d.cts +117 -35
- package/dist/mod.d.ts +117 -35
- package/dist/mod.js +346 -286
- package/dist/types-DAQwEF8j.js +28333 -0
- package/package.json +15 -13
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- deno-fmt-ignore-file -->
|
|
2
2
|
|
|
3
3
|
@fedify/relay: ActivityPub relay for Fedify
|
|
4
|
-
|
|
4
|
+
===========================================
|
|
5
5
|
|
|
6
6
|
[![JSR][JSR badge]][JSR]
|
|
7
7
|
[![npm][npm badge]][npm]
|
|
@@ -13,9 +13,21 @@ This package provides ActivityPub relay functionality for the [Fedify]
|
|
|
13
13
|
ecosystem, enabling the creation and management of relay servers that can
|
|
14
14
|
forward activities between federated instances.
|
|
15
15
|
|
|
16
|
+
For comprehensive documentation on building and operating relay servers,
|
|
17
|
+
see the [*Relay server* section in the Fedify manual][manual].
|
|
18
|
+
|
|
19
|
+
[JSR badge]: https://jsr.io/badges/@fedify/relay
|
|
20
|
+
[JSR]: https://jsr.io/@fedify/relay
|
|
21
|
+
[npm badge]: https://img.shields.io/npm/v/@fedify/relay?logo=npm
|
|
22
|
+
[npm]: https://www.npmjs.com/package/@fedify/relay
|
|
23
|
+
[@fedify@hollo.social badge]: https://fedi-badge.deno.dev/@fedify@hollo.social/followers.svg
|
|
24
|
+
[@fedify@hollo.social]: https://hollo.social/@fedify
|
|
25
|
+
[Fedify]: https://fedify.dev/
|
|
26
|
+
[manual]: https://fedify.dev/manual/relay
|
|
27
|
+
|
|
16
28
|
|
|
17
29
|
What is an ActivityPub relay?
|
|
18
|
-
|
|
30
|
+
-----------------------------
|
|
19
31
|
|
|
20
32
|
ActivityPub relays are infrastructure components that help small instances
|
|
21
33
|
participate effectively in the federated social network by acting as
|
|
@@ -33,7 +45,7 @@ This package supports two popular relay protocols used in the fediverse:
|
|
|
33
45
|
### Mastodon-style relay
|
|
34
46
|
|
|
35
47
|
The Mastodon-style relay protocol uses LD signatures for activity
|
|
36
|
-
verification and follows the Public collection.
|
|
48
|
+
verification and follows the Public collection. This protocol is widely
|
|
37
49
|
supported by Mastodon and many other ActivityPub implementations.
|
|
38
50
|
|
|
39
51
|
Key features:
|
|
@@ -46,11 +58,16 @@ Key features:
|
|
|
46
58
|
|
|
47
59
|
### LitePub-style relay
|
|
48
60
|
|
|
49
|
-
*LitePub relay support is planned for a future release.*
|
|
50
|
-
|
|
51
61
|
The LitePub-style relay protocol uses bidirectional following relationships
|
|
52
62
|
and wraps activities in `Announce` activities for distribution.
|
|
53
63
|
|
|
64
|
+
Key features:
|
|
65
|
+
|
|
66
|
+
- Reciprocal following between relay and subscribers
|
|
67
|
+
- Activities wrapped in `Announce` for distribution
|
|
68
|
+
- Two-phase subscription (pending → accepted)
|
|
69
|
+
- Enhanced federation capabilities
|
|
70
|
+
|
|
54
71
|
|
|
55
72
|
Installation
|
|
56
73
|
------------
|
|
@@ -83,46 +100,101 @@ bun add @fedify/relay
|
|
|
83
100
|
Usage
|
|
84
101
|
-----
|
|
85
102
|
|
|
86
|
-
### Creating a
|
|
103
|
+
### Creating a relay
|
|
87
104
|
|
|
88
|
-
Here's a simple example of creating a
|
|
105
|
+
Here's a simple example of creating a relay server using the factory function:
|
|
89
106
|
|
|
90
107
|
~~~~ typescript
|
|
91
|
-
import {
|
|
108
|
+
import { createRelay } from "@fedify/relay";
|
|
92
109
|
import { MemoryKvStore } from "@fedify/fedify";
|
|
93
110
|
|
|
94
|
-
|
|
111
|
+
// Create a Mastodon-style relay
|
|
112
|
+
const relay = createRelay("mastodon", {
|
|
95
113
|
kv: new MemoryKvStore(),
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
origin: "https://relay.example.com",
|
|
115
|
+
// Required: Set a subscription handler to approve/reject subscriptions
|
|
116
|
+
subscriptionHandler: async (ctx, actor) => {
|
|
117
|
+
// For an open relay, simply return true
|
|
118
|
+
// return true;
|
|
119
|
+
|
|
120
|
+
// Or implement custom approval logic:
|
|
121
|
+
const domain = new URL(actor.id!).hostname;
|
|
122
|
+
const blockedDomains = ["spam.example", "blocked.example"];
|
|
123
|
+
return !blockedDomains.includes(domain);
|
|
124
|
+
},
|
|
106
125
|
});
|
|
107
126
|
|
|
108
127
|
// Serve the relay
|
|
109
128
|
Deno.serve((request) => relay.fetch(request));
|
|
110
129
|
~~~~
|
|
111
130
|
|
|
131
|
+
You can also create a LitePub-style relay by changing the type:
|
|
132
|
+
|
|
133
|
+
~~~~ typescript
|
|
134
|
+
const relay = createRelay("litepub", {
|
|
135
|
+
kv: new MemoryKvStore(),
|
|
136
|
+
origin: "https://relay.example.com",
|
|
137
|
+
subscriptionHandler: async (ctx, actor) => true,
|
|
138
|
+
});
|
|
139
|
+
~~~~
|
|
140
|
+
|
|
112
141
|
### Subscription handling
|
|
113
142
|
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
The `subscriptionHandler` is required and determines whether to approve or
|
|
144
|
+
reject subscription requests. For an open relay that accepts all subscriptions:
|
|
116
145
|
|
|
117
146
|
~~~~ typescript
|
|
118
|
-
relay
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return allowedDomains.includes(domain);
|
|
147
|
+
const relay = createRelay("mastodon", {
|
|
148
|
+
kv: new MemoryKvStore(),
|
|
149
|
+
origin: "https://relay.example.com",
|
|
150
|
+
subscriptionHandler: async (ctx, actor) => true, // Accept all
|
|
123
151
|
});
|
|
124
152
|
~~~~
|
|
125
153
|
|
|
154
|
+
You can also implement custom approval logic:
|
|
155
|
+
|
|
156
|
+
~~~~ typescript
|
|
157
|
+
const relay = createRelay("mastodon", {
|
|
158
|
+
kv: new MemoryKvStore(),
|
|
159
|
+
origin: "https://relay.example.com",
|
|
160
|
+
subscriptionHandler: async (ctx, actor) => {
|
|
161
|
+
// Example: Only allow subscriptions from specific domains
|
|
162
|
+
const domain = new URL(actor.id!).hostname;
|
|
163
|
+
const allowedDomains = ["mastodon.social", "fosstodon.org"];
|
|
164
|
+
return allowedDomains.includes(domain);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
~~~~
|
|
168
|
+
|
|
169
|
+
### Managing followers
|
|
170
|
+
|
|
171
|
+
The relay provides methods to query and manage followers without exposing
|
|
172
|
+
internal storage details.
|
|
173
|
+
|
|
174
|
+
#### Listing all followers
|
|
175
|
+
|
|
176
|
+
~~~~ typescript
|
|
177
|
+
for await (const follower of relay.listFollowers()) {
|
|
178
|
+
console.log(`Follower: ${follower.actorId}`);
|
|
179
|
+
console.log(`State: ${follower.state}`);
|
|
180
|
+
console.log(`Actor name: ${follower.actor.name}`);
|
|
181
|
+
console.log(`Actor type: ${follower.actor.constructor.name}`);
|
|
182
|
+
}
|
|
183
|
+
~~~~
|
|
184
|
+
|
|
185
|
+
#### Getting a specific follower
|
|
186
|
+
|
|
187
|
+
~~~~ typescript
|
|
188
|
+
const follower = await relay.getFollower("https://mastodon.example.com/users/alice");
|
|
189
|
+
if (follower) {
|
|
190
|
+
console.log(`Found follower in state: ${follower.state}`);
|
|
191
|
+
console.log(`Actor username: ${follower.actor.preferredUsername}`);
|
|
192
|
+
console.log(`Inbox: ${follower.actor.inboxId?.href}`);
|
|
193
|
+
} else {
|
|
194
|
+
console.log("Follower not found");
|
|
195
|
+
}
|
|
196
|
+
~~~~
|
|
197
|
+
|
|
126
198
|
### Integration with web frameworks
|
|
127
199
|
|
|
128
200
|
The relay's `fetch()` method returns a standard `Response` object, making it
|
|
@@ -131,13 +203,14 @@ example with Hono:
|
|
|
131
203
|
|
|
132
204
|
~~~~ typescript
|
|
133
205
|
import { Hono } from "hono";
|
|
134
|
-
import {
|
|
206
|
+
import { createRelay } from "@fedify/relay";
|
|
135
207
|
import { MemoryKvStore } from "@fedify/fedify";
|
|
136
208
|
|
|
137
209
|
const app = new Hono();
|
|
138
|
-
const relay =
|
|
210
|
+
const relay = createRelay("mastodon", {
|
|
139
211
|
kv: new MemoryKvStore(),
|
|
140
|
-
|
|
212
|
+
origin: "https://relay.example.com",
|
|
213
|
+
subscriptionHandler: async (ctx, actor) => true,
|
|
141
214
|
});
|
|
142
215
|
|
|
143
216
|
app.use("*", async (c) => {
|
|
@@ -187,42 +260,67 @@ For production use, choose a persistent storage backend like Redis or
|
|
|
187
260
|
PostgreSQL. See the [Fedify documentation on key–value stores] for more
|
|
188
261
|
details.
|
|
189
262
|
|
|
263
|
+
[Fedify documentation on key–value stores]: https://fedify.dev/manual/kv
|
|
264
|
+
|
|
190
265
|
|
|
191
266
|
API reference
|
|
192
267
|
-------------
|
|
193
268
|
|
|
194
|
-
### `
|
|
269
|
+
### `createRelay()`
|
|
195
270
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
#### Constructor
|
|
271
|
+
Factory function to create a relay instance.
|
|
199
272
|
|
|
200
273
|
~~~~ typescript
|
|
201
|
-
|
|
274
|
+
function createRelay(
|
|
275
|
+
type: "mastodon" | "litepub",
|
|
276
|
+
options: RelayOptions
|
|
277
|
+
): Relay
|
|
202
278
|
~~~~
|
|
203
279
|
|
|
204
|
-
|
|
280
|
+
**Parameters:**
|
|
281
|
+
|
|
282
|
+
- `type`: The type of relay to create (`"mastodon"` or `"litepub"`)
|
|
283
|
+
- `options`: Configuration options for the relay
|
|
205
284
|
|
|
206
|
-
|
|
285
|
+
**Returns:** A `Relay` instance
|
|
286
|
+
|
|
287
|
+
### `Relay`
|
|
288
|
+
|
|
289
|
+
Public interface for ActivityPub relay implementations.
|
|
207
290
|
|
|
208
291
|
#### Methods
|
|
209
292
|
|
|
210
293
|
- `fetch(request: Request): Promise<Response>`: Handle incoming HTTP requests
|
|
211
|
-
- `
|
|
212
|
-
|
|
294
|
+
- `listFollowers(): AsyncIterableIterator<RelayFollower>`: Lists all
|
|
295
|
+
followers of the relay
|
|
296
|
+
- `getFollower(actorId: string): Promise<RelayFollower | null>`: Gets
|
|
297
|
+
a specific follower by actor ID
|
|
298
|
+
- `getActorUri(): Promise<URL>`: Gets the URI of the relay actor
|
|
299
|
+
- `getSharedInboxUri(): Promise<URL>`: Gets the shared inbox URI of the relay
|
|
300
|
+
|
|
301
|
+
#### Relay types
|
|
302
|
+
|
|
303
|
+
The relay type is specified when calling `createRelay()`:
|
|
304
|
+
|
|
305
|
+
- `"mastodon"`: Mastodon-compatible relay using direct activity forwarding,
|
|
306
|
+
immediate subscription approval, and LD signatures
|
|
307
|
+
- `"litepub"`: LitePub-compatible relay using bidirectional following,
|
|
308
|
+
activities wrapped in `Announce`, and two-phase subscription
|
|
213
309
|
|
|
214
310
|
### `RelayOptions`
|
|
215
311
|
|
|
216
312
|
Configuration options for the relay:
|
|
217
313
|
|
|
218
314
|
- `kv: KvStore` (required): Key–value store for persisting relay data
|
|
219
|
-
- `
|
|
315
|
+
- `origin: string` (required): Relay's origin URL (e.g.,
|
|
316
|
+
`"https://relay.example.com"`)
|
|
317
|
+
- `name?: string`: Relay's display name (defaults to `"ActivityPub Relay"`)
|
|
318
|
+
- `subscriptionHandler: SubscriptionRequestHandler` (required): Handler for
|
|
319
|
+
subscription approval/rejection
|
|
220
320
|
- `documentLoaderFactory?: DocumentLoaderFactory`: Custom document loader
|
|
221
321
|
factory
|
|
222
322
|
- `authenticatedDocumentLoaderFactory?: AuthenticatedDocumentLoaderFactory`:
|
|
223
323
|
Custom authenticated document loader factory
|
|
224
|
-
- `federation?: Federation<void>`: Custom Federation instance (for advanced
|
|
225
|
-
use cases)
|
|
226
324
|
- `queue?: MessageQueue`: Message queue for background activity processing
|
|
227
325
|
|
|
228
326
|
### `SubscriptionRequestHandler`
|
|
@@ -231,27 +329,35 @@ A function that determines whether to approve a subscription request:
|
|
|
231
329
|
|
|
232
330
|
~~~~ typescript
|
|
233
331
|
type SubscriptionRequestHandler = (
|
|
234
|
-
ctx: Context<
|
|
332
|
+
ctx: Context<RelayOptions>,
|
|
235
333
|
clientActor: Actor,
|
|
236
334
|
) => Promise<boolean>
|
|
237
335
|
~~~~
|
|
238
336
|
|
|
239
|
-
Parameters
|
|
337
|
+
**Parameters:**
|
|
240
338
|
|
|
241
|
-
- `ctx`: The Fedify context object
|
|
339
|
+
- `ctx`: The Fedify context object with relay options
|
|
242
340
|
- `clientActor`: The actor requesting to subscribe
|
|
243
341
|
|
|
244
|
-
Returns
|
|
342
|
+
**Returns:**
|
|
245
343
|
|
|
246
344
|
- `true` to approve the subscription
|
|
247
345
|
- `false` to reject the subscription
|
|
248
346
|
|
|
347
|
+
### `RelayFollower`
|
|
249
348
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
349
|
+
A follower of the relay with validated Actor instance:
|
|
350
|
+
|
|
351
|
+
~~~~ typescript
|
|
352
|
+
interface RelayFollower {
|
|
353
|
+
readonly actorId: string;
|
|
354
|
+
readonly actor: Actor;
|
|
355
|
+
readonly state: "pending" | "accepted";
|
|
356
|
+
}
|
|
357
|
+
~~~~
|
|
358
|
+
|
|
359
|
+
**Properties:**
|
|
360
|
+
|
|
361
|
+
- `actorId`: The actor ID (URL) of the follower
|
|
362
|
+
- `actor`: The validated Actor object
|
|
363
|
+
- `state`: The follower's state (`"pending"` or `"accepted"`)
|