@fedify/fedify 0.11.0-dev.240 → 0.11.0-dev.242
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGES.md +51 -0
- package/esm/federation/handler.js +2 -2
- package/esm/federation/middleware.js +78 -0
- package/esm/vocab/activity.yaml +47 -0
- package/esm/vocab/application.yaml +14 -0
- package/esm/vocab/collection.yaml +0 -4
- package/esm/vocab/collectionpage.yaml +0 -3
- package/esm/vocab/group.yaml +14 -0
- package/esm/vocab/organization.yaml +14 -0
- package/esm/vocab/person.yaml +14 -0
- package/esm/vocab/service.yaml +14 -0
- package/esm/vocab/vocab.js +1350 -337
- package/package.json +1 -1
- package/types/federation/context.d.ts +16 -0
- package/types/federation/context.d.ts.map +1 -1
- package/types/federation/handler.d.ts +2 -2
- package/types/federation/handler.d.ts.map +1 -1
- package/types/federation/middleware.d.ts +13 -0
- package/types/federation/middleware.d.ts.map +1 -1
- package/types/testing/context.d.ts.map +1 -1
- package/types/vocab/vocab.d.ts +587 -51
- package/types/vocab/vocab.d.ts.map +1 -1
package/CHANGES.md
CHANGED
@@ -21,6 +21,10 @@ To be released.
|
|
21
21
|
- Added `{ type: "liked"; handle: string }` case to `ParseUriResult` type.
|
22
22
|
- Renamed `linked` property (which was a typo) to `liked` in
|
23
23
|
`Application`, `Group`, `Organization`, `Person`, and `Service` classes.
|
24
|
+
- Added `Federation.setFeaturedDispatcher()` method.
|
25
|
+
- Added `Context.getFeaturedUri()` method.
|
26
|
+
- Added `{ type: "featured"; handle: string }` case to `ParseUriResult`
|
27
|
+
type.
|
24
28
|
|
25
29
|
- Frequently used JSON-LD contexts are now preloaded. [[74]]
|
26
30
|
|
@@ -39,6 +43,53 @@ To be released.
|
|
39
43
|
- Added `Offer` class to Activity Vocabulary API.
|
40
44
|
[[#65], [#76] by Lee Dogeon]
|
41
45
|
|
46
|
+
- The below properties of `Collection` and `CollectionPage` in Activity
|
47
|
+
Vocabulary API now do not accept `Link` objects:
|
48
|
+
|
49
|
+
- `Collection.current`
|
50
|
+
- `Collection.first`
|
51
|
+
- `Collection.last`
|
52
|
+
- `Collection.items`
|
53
|
+
- `CollectionPage.partOf`
|
54
|
+
- `CollectionPage.next`
|
55
|
+
- `CollectionPage.prev`
|
56
|
+
|
57
|
+
- Added `target` property to `Activity` class in Activity Vocabulary API.
|
58
|
+
|
59
|
+
- Added `Activity.getTarget()` method.
|
60
|
+
- Added `Activity.getTargets()` method.
|
61
|
+
- `new Activity()` constructor now accepts `target` option.
|
62
|
+
- `new Activity()` constructor now accepts `targets` option.
|
63
|
+
- `Activity.clone()` method now accepts `target` option.
|
64
|
+
- `Activity.clone()` method now accepts `targets` option.
|
65
|
+
|
66
|
+
- Added `result` property to `Activity` class in Activity Vocabulary API.
|
67
|
+
|
68
|
+
- Added `Activity.getResult()` method.
|
69
|
+
- Added `Activity.getResults()` method.
|
70
|
+
- `new Activity()` constructor now accepts `result` option.
|
71
|
+
- `new Activity()` constructor now accepts `results` option.
|
72
|
+
- `Activity.clone()` method now accepts `result` option.
|
73
|
+
- `Activity.clone()` method now accepts `results` option.
|
74
|
+
|
75
|
+
- Added `origin` property to `Activity` class in Activity Vocabulary API.
|
76
|
+
|
77
|
+
- Added `Activity.getOrigin()` method.
|
78
|
+
- Added `Activity.getOrigins()` method.
|
79
|
+
- `new Activity()` constructor now accepts `origin` option.
|
80
|
+
- `new Activity()` constructor now accepts `origins` option.
|
81
|
+
- `Activity.clone()` method now accepts `origin` option.
|
82
|
+
- `Activity.clone()` method now accepts `origins` option.
|
83
|
+
|
84
|
+
- Added `instrument` property to `Activity` class in Activity Vocabulary API.
|
85
|
+
|
86
|
+
- Added `Activity.getInstrument()` method.
|
87
|
+
- Added `Activity.getInstruments()` method.
|
88
|
+
- `new Activity()` constructor now accepts `instrument` option.
|
89
|
+
- `new Activity()` constructor now accepts `instruments` option.
|
90
|
+
- `Activity.clone()` method now accepts `instrument` option.
|
91
|
+
- `Activity.clone()` method now accepts `instruments` option.
|
92
|
+
|
42
93
|
- The key pair or the key pair for signing outgoing HTTP requests made from
|
43
94
|
the shared inbox now can be configured. This improves the compatibility
|
44
95
|
with other ActivityPub implementations that require authorized fetches
|
@@ -4,7 +4,7 @@ import { accepts } from "../deps/jsr.io/@std/http/0.224.5/negotiation.js";
|
|
4
4
|
import { verifyRequest } from "../sig/http.js";
|
5
5
|
import { doesActorOwnKey } from "../sig/owner.js";
|
6
6
|
import { verifyObject } from "../sig/proof.js";
|
7
|
-
import { Activity,
|
7
|
+
import { Activity, Object, OrderedCollection, OrderedCollectionPage, } from "../vocab/vocab.js";
|
8
8
|
export function acceptsJsonLd(request) {
|
9
9
|
const types = accepts(request);
|
10
10
|
if (types == null)
|
@@ -146,7 +146,7 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
|
|
146
146
|
let logged = false;
|
147
147
|
for (const item of items) {
|
148
148
|
let mappedItem;
|
149
|
-
if (item instanceof Object || item instanceof
|
149
|
+
if (item instanceof Object || item instanceof URL) {
|
150
150
|
mappedItem = item;
|
151
151
|
}
|
152
152
|
else if (item.id == null)
|
@@ -48,6 +48,7 @@ export class Federation {
|
|
48
48
|
#followingCallbacks;
|
49
49
|
#followersCallbacks;
|
50
50
|
#likedCallbacks;
|
51
|
+
#featuredCallbacks;
|
51
52
|
#inboxListeners;
|
52
53
|
#inboxErrorHandler;
|
53
54
|
#sharedInboxKeyDispatcher;
|
@@ -334,6 +335,19 @@ export class Federation {
|
|
334
335
|
"URI. Set the property with Context.getLikedUri(handle).");
|
335
336
|
}
|
336
337
|
}
|
338
|
+
if (this.#featuredCallbacks != null &&
|
339
|
+
this.#featuredCallbacks.dispatcher != null) {
|
340
|
+
if (actor?.featuredId == null) {
|
341
|
+
logger.warn("You configured a featured collection dispatcher, but the " +
|
342
|
+
"actor does not have a featured property. Set the property " +
|
343
|
+
"with Context.getFeaturedUri(handle).");
|
344
|
+
}
|
345
|
+
else if (actor.featuredId.href != context.getFeaturedUri(handle).href) {
|
346
|
+
logger.warn("You configured a featured collection dispatcher, but the " +
|
347
|
+
"actor's featured property does not match the featured collection " +
|
348
|
+
"URI. Set the property with Context.getFeaturedUri(handle).");
|
349
|
+
}
|
350
|
+
}
|
337
351
|
if (this.#router.has("inbox")) {
|
338
352
|
if (actor.inboxId == null) {
|
339
353
|
logger.warn("You configured inbox listeners, but the actor does not " +
|
@@ -658,6 +672,50 @@ export class Federation {
|
|
658
672
|
};
|
659
673
|
return setters;
|
660
674
|
}
|
675
|
+
/**
|
676
|
+
* Registers a featured collection dispatcher.
|
677
|
+
* @param path The URI path pattern for the featured collection. The syntax
|
678
|
+
* is based on URI Template
|
679
|
+
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
|
680
|
+
* must have one variable: `{handle}`.
|
681
|
+
* @param dispatcher A featured collection callback to register.
|
682
|
+
* @returns An object with methods to set other featured collection
|
683
|
+
* callbacks.
|
684
|
+
* @throws {@link RouterError} Thrown if the path pattern is invalid.
|
685
|
+
* @since 0.11.0
|
686
|
+
*/
|
687
|
+
setFeaturedDispatcher(path, dispatcher) {
|
688
|
+
if (this.#router.has("featured")) {
|
689
|
+
throw new RouterError("Featured collection dispatcher already set.");
|
690
|
+
}
|
691
|
+
const variables = this.#router.add(path, "featured");
|
692
|
+
if (variables.size !== 1 || !variables.has("handle")) {
|
693
|
+
throw new RouterError("Path for featured collection dispatcher must have one variable: {handle}");
|
694
|
+
}
|
695
|
+
const callbacks = {
|
696
|
+
dispatcher,
|
697
|
+
};
|
698
|
+
this.#featuredCallbacks = callbacks;
|
699
|
+
const setters = {
|
700
|
+
setCounter(counter) {
|
701
|
+
callbacks.counter = counter;
|
702
|
+
return setters;
|
703
|
+
},
|
704
|
+
setFirstCursor(cursor) {
|
705
|
+
callbacks.firstCursor = cursor;
|
706
|
+
return setters;
|
707
|
+
},
|
708
|
+
setLastCursor(cursor) {
|
709
|
+
callbacks.lastCursor = cursor;
|
710
|
+
return setters;
|
711
|
+
},
|
712
|
+
authorize(predicate) {
|
713
|
+
callbacks.authorizePredicate = predicate;
|
714
|
+
return setters;
|
715
|
+
},
|
716
|
+
};
|
717
|
+
return setters;
|
718
|
+
}
|
661
719
|
/**
|
662
720
|
* Assigns the URL path for the inbox and starts setting inbox listeners.
|
663
721
|
*
|
@@ -994,6 +1052,16 @@ export class Federation {
|
|
994
1052
|
onNotFound,
|
995
1053
|
onNotAcceptable,
|
996
1054
|
});
|
1055
|
+
case "featured":
|
1056
|
+
return await handleCollection(request, {
|
1057
|
+
name: "featured",
|
1058
|
+
handle: route.values.handle,
|
1059
|
+
context,
|
1060
|
+
collectionCallbacks: this.#featuredCallbacks,
|
1061
|
+
onUnauthorized,
|
1062
|
+
onNotFound,
|
1063
|
+
onNotAcceptable,
|
1064
|
+
});
|
997
1065
|
default: {
|
998
1066
|
const response = onNotFound(request);
|
999
1067
|
return response instanceof Promise ? await response : response;
|
@@ -1099,6 +1167,13 @@ class ContextImpl {
|
|
1099
1167
|
}
|
1100
1168
|
return new URL(path, this.#url);
|
1101
1169
|
}
|
1170
|
+
getFeaturedUri(handle) {
|
1171
|
+
const path = this.#router.build("featured", { handle });
|
1172
|
+
if (path == null) {
|
1173
|
+
throw new RouterError("No featured collection path registered.");
|
1174
|
+
}
|
1175
|
+
return new URL(path, this.#url);
|
1176
|
+
}
|
1102
1177
|
parseUri(uri) {
|
1103
1178
|
if (uri.origin !== this.#url.origin)
|
1104
1179
|
return null;
|
@@ -1135,6 +1210,9 @@ class ContextImpl {
|
|
1135
1210
|
else if (route.name === "liked") {
|
1136
1211
|
return { type: "liked", handle: route.values.handle };
|
1137
1212
|
}
|
1213
|
+
else if (route.name === "featured") {
|
1214
|
+
return { type: "featured", handle: route.values.handle };
|
1215
|
+
}
|
1138
1216
|
return null;
|
1139
1217
|
}
|
1140
1218
|
getHandleFromActorUri(actorUri) {
|
package/esm/vocab/activity.yaml
CHANGED
@@ -41,3 +41,50 @@ properties:
|
|
41
41
|
wishlist", the object of the activity is the movie added.
|
42
42
|
range:
|
43
43
|
- "https://www.w3.org/ns/activitystreams#Object"
|
44
|
+
|
45
|
+
- pluralName: targets
|
46
|
+
singularName: target
|
47
|
+
singularAccessor: true
|
48
|
+
uri: "https://www.w3.org/ns/activitystreams#target"
|
49
|
+
description: |
|
50
|
+
Describes the indirect object, or target, of the activity. The precise
|
51
|
+
meaning of the target is largely dependent on the type of action being
|
52
|
+
described but will often be the object of the English preposition "to".
|
53
|
+
For instance, in the activity "John added a movie to his wishlist",
|
54
|
+
the target of the activity is John's wishlist. An activity can have more
|
55
|
+
than one target.
|
56
|
+
range:
|
57
|
+
- "https://www.w3.org/ns/activitystreams#Object"
|
58
|
+
|
59
|
+
- pluralName: results
|
60
|
+
singularName: result
|
61
|
+
singularAccessor: true
|
62
|
+
uri: "https://www.w3.org/ns/activitystreams#result"
|
63
|
+
description: |
|
64
|
+
Describes the result of the activity. For instance, if a particular action
|
65
|
+
results in the creation of a new resource, the result property can be used
|
66
|
+
to describe that new resource.
|
67
|
+
range:
|
68
|
+
- "https://www.w3.org/ns/activitystreams#Object"
|
69
|
+
|
70
|
+
- pluralName: origins
|
71
|
+
singularName: origin
|
72
|
+
singularAccessor: true
|
73
|
+
uri: "https://www.w3.org/ns/activitystreams#origin"
|
74
|
+
description: |
|
75
|
+
Describes an indirect object of the activity from which the activity is
|
76
|
+
directed. The precise meaning of the origin is the object of the English
|
77
|
+
preposition "from". For instance, in the activity "John moved an item to
|
78
|
+
List B from List A", the origin of the activity is "List A".
|
79
|
+
range:
|
80
|
+
- "https://www.w3.org/ns/activitystreams#Object"
|
81
|
+
|
82
|
+
- pluralName: instruments
|
83
|
+
singularName: instrument
|
84
|
+
singularAccessor: true
|
85
|
+
uri: "https://www.w3.org/ns/activitystreams#instrument"
|
86
|
+
description: |
|
87
|
+
Identifies one or more objects used (or to be used) in the completion of
|
88
|
+
an {@link Activity}.
|
89
|
+
range:
|
90
|
+
- "https://www.w3.org/ns/activitystreams#Object"
|
@@ -12,6 +12,9 @@ defaultContext:
|
|
12
12
|
- "https://w3id.org/security/multikey/v1"
|
13
13
|
- manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
|
14
14
|
toot: "http://joinmastodon.org/ns#"
|
15
|
+
featured:
|
16
|
+
"@id": "toot:featured"
|
17
|
+
"@type": "@id"
|
15
18
|
discoverable: "toot:discoverable"
|
16
19
|
suspended: "toot:suspended"
|
17
20
|
memorial: "toot:memorial"
|
@@ -143,6 +146,17 @@ properties:
|
|
143
146
|
range:
|
144
147
|
- "https://www.w3.org/ns/activitystreams#Collection"
|
145
148
|
|
149
|
+
- singularName: featured
|
150
|
+
functional: true
|
151
|
+
uri: "http://joinmastodon.org/ns#featured"
|
152
|
+
description: |
|
153
|
+
What is known in Mastodon as "pinned statuses", or statuses that are always
|
154
|
+
featured at the top of people's profiles, is implemented using an extra
|
155
|
+
property `featured` on the actor object that points to a {@link Collection}
|
156
|
+
of objects.
|
157
|
+
range:
|
158
|
+
- "https://www.w3.org/ns/activitystreams#Collection"
|
159
|
+
|
146
160
|
- pluralName: streams
|
147
161
|
singularName: stream
|
148
162
|
singularAccessor: false
|
@@ -30,7 +30,6 @@ properties:
|
|
30
30
|
the most recently updated member items.
|
31
31
|
range:
|
32
32
|
- "https://www.w3.org/ns/activitystreams#CollectionPage"
|
33
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
34
33
|
|
35
34
|
- singularName: first
|
36
35
|
functional: true
|
@@ -40,7 +39,6 @@ properties:
|
|
40
39
|
items in the collection.
|
41
40
|
range:
|
42
41
|
- "https://www.w3.org/ns/activitystreams#CollectionPage"
|
43
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
44
42
|
|
45
43
|
- singularName: last
|
46
44
|
functional: true
|
@@ -50,7 +48,6 @@ properties:
|
|
50
48
|
the collection.
|
51
49
|
range:
|
52
50
|
- "https://www.w3.org/ns/activitystreams#CollectionPage"
|
53
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
54
51
|
|
55
52
|
- pluralName: items
|
56
53
|
singularName: item
|
@@ -60,4 +57,3 @@ properties:
|
|
60
57
|
or unordered.
|
61
58
|
range:
|
62
59
|
- "https://www.w3.org/ns/activitystreams#Object"
|
63
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
@@ -17,7 +17,6 @@ properties:
|
|
17
17
|
Identifies the {@link Collection} to which a {@link CollectionPage} objects
|
18
18
|
items belong.
|
19
19
|
range:
|
20
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
21
20
|
- "https://www.w3.org/ns/activitystreams#Collection"
|
22
21
|
|
23
22
|
- singularName: next
|
@@ -26,7 +25,6 @@ properties:
|
|
26
25
|
description: In a paged {@link Collection}, indicates the next page of items.
|
27
26
|
range:
|
28
27
|
- "https://www.w3.org/ns/activitystreams#CollectionPage"
|
29
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
30
28
|
|
31
29
|
- singularName: prev
|
32
30
|
functional: true
|
@@ -35,4 +33,3 @@ properties:
|
|
35
33
|
In a paged {@link Collection}, identifies the previous page of items.
|
36
34
|
range:
|
37
35
|
- "https://www.w3.org/ns/activitystreams#CollectionPage"
|
38
|
-
- "https://www.w3.org/ns/activitystreams#Link"
|
package/esm/vocab/group.yaml
CHANGED
@@ -12,6 +12,9 @@ defaultContext:
|
|
12
12
|
- "https://w3id.org/security/multikey/v1"
|
13
13
|
- manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
|
14
14
|
toot: "http://joinmastodon.org/ns#"
|
15
|
+
featured:
|
16
|
+
"@id": "toot:featured"
|
17
|
+
"@type": "@id"
|
15
18
|
discoverable: "toot:discoverable"
|
16
19
|
suspended: "toot:suspended"
|
17
20
|
memorial: "toot:memorial"
|
@@ -143,6 +146,17 @@ properties:
|
|
143
146
|
range:
|
144
147
|
- "https://www.w3.org/ns/activitystreams#Collection"
|
145
148
|
|
149
|
+
- singularName: featured
|
150
|
+
functional: true
|
151
|
+
uri: "http://joinmastodon.org/ns#featured"
|
152
|
+
description: |
|
153
|
+
What is known in Mastodon as "pinned statuses", or statuses that are always
|
154
|
+
featured at the top of people's profiles, is implemented using an extra
|
155
|
+
property `featured` on the actor object that points to a {@link Collection}
|
156
|
+
of objects.
|
157
|
+
range:
|
158
|
+
- "https://www.w3.org/ns/activitystreams#Collection"
|
159
|
+
|
146
160
|
- pluralName: streams
|
147
161
|
singularName: stream
|
148
162
|
singularAccessor: false
|
@@ -12,6 +12,9 @@ defaultContext:
|
|
12
12
|
- "https://w3id.org/security/multikey/v1"
|
13
13
|
- manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
|
14
14
|
toot: "http://joinmastodon.org/ns#"
|
15
|
+
featured:
|
16
|
+
"@id": "toot:featured"
|
17
|
+
"@type": "@id"
|
15
18
|
discoverable: "toot:discoverable"
|
16
19
|
suspended: "toot:suspended"
|
17
20
|
memorial: "toot:memorial"
|
@@ -143,6 +146,17 @@ properties:
|
|
143
146
|
range:
|
144
147
|
- "https://www.w3.org/ns/activitystreams#Collection"
|
145
148
|
|
149
|
+
- singularName: featured
|
150
|
+
functional: true
|
151
|
+
uri: "http://joinmastodon.org/ns#featured"
|
152
|
+
description: |
|
153
|
+
What is known in Mastodon as "pinned statuses", or statuses that are always
|
154
|
+
featured at the top of people's profiles, is implemented using an extra
|
155
|
+
property `featured` on the actor object that points to a {@link Collection}
|
156
|
+
of objects.
|
157
|
+
range:
|
158
|
+
- "https://www.w3.org/ns/activitystreams#Collection"
|
159
|
+
|
146
160
|
- pluralName: streams
|
147
161
|
singularName: stream
|
148
162
|
singularAccessor: false
|
package/esm/vocab/person.yaml
CHANGED
@@ -12,6 +12,9 @@ defaultContext:
|
|
12
12
|
- "https://w3id.org/security/multikey/v1"
|
13
13
|
- manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
|
14
14
|
toot: "http://joinmastodon.org/ns#"
|
15
|
+
featured:
|
16
|
+
"@id": "toot:featured"
|
17
|
+
"@type": "@id"
|
15
18
|
discoverable: "toot:discoverable"
|
16
19
|
suspended: "toot:suspended"
|
17
20
|
memorial: "toot:memorial"
|
@@ -143,6 +146,17 @@ properties:
|
|
143
146
|
range:
|
144
147
|
- "https://www.w3.org/ns/activitystreams#Collection"
|
145
148
|
|
149
|
+
- singularName: featured
|
150
|
+
functional: true
|
151
|
+
uri: "http://joinmastodon.org/ns#featured"
|
152
|
+
description: |
|
153
|
+
What is known in Mastodon as "pinned statuses", or statuses that are always
|
154
|
+
featured at the top of people's profiles, is implemented using an extra
|
155
|
+
property `featured` on the actor object that points to a {@link Collection}
|
156
|
+
of objects.
|
157
|
+
range:
|
158
|
+
- "https://www.w3.org/ns/activitystreams#Collection"
|
159
|
+
|
146
160
|
- pluralName: streams
|
147
161
|
singularName: stream
|
148
162
|
singularAccessor: false
|
package/esm/vocab/service.yaml
CHANGED
@@ -12,6 +12,9 @@ defaultContext:
|
|
12
12
|
- "https://w3id.org/security/multikey/v1"
|
13
13
|
- manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
|
14
14
|
toot: "http://joinmastodon.org/ns#"
|
15
|
+
featured:
|
16
|
+
"@id": "toot:featured"
|
17
|
+
"@type": "@id"
|
15
18
|
discoverable: "toot:discoverable"
|
16
19
|
suspended: "toot:suspended"
|
17
20
|
memorial: "toot:memorial"
|
@@ -143,6 +146,17 @@ properties:
|
|
143
146
|
range:
|
144
147
|
- "https://www.w3.org/ns/activitystreams#Collection"
|
145
148
|
|
149
|
+
- singularName: featured
|
150
|
+
functional: true
|
151
|
+
uri: "http://joinmastodon.org/ns#featured"
|
152
|
+
description: |
|
153
|
+
What is known in Mastodon as "pinned statuses", or statuses that are always
|
154
|
+
featured at the top of people's profiles, is implemented using an extra
|
155
|
+
property `featured` on the actor object that points to a {@link Collection}
|
156
|
+
of objects.
|
157
|
+
range:
|
158
|
+
- "https://www.w3.org/ns/activitystreams#Collection"
|
159
|
+
|
146
160
|
- pluralName: streams
|
147
161
|
singularName: stream
|
148
162
|
singularAccessor: false
|