@fedify/fedify 0.11.0-dev.239 → 0.11.0-dev.241

Sign up to get free protection for your applications and to get access to all the features.
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
 
@@ -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;
@@ -321,6 +322,32 @@ export class Federation {
321
322
  "URI. Set the property with Context.getOutboxUri(handle).");
322
323
  }
323
324
  }
325
+ if (this.#likedCallbacks != null &&
326
+ this.#likedCallbacks.dispatcher != null) {
327
+ if (actor?.likedId == null) {
328
+ logger.warn("You configured a liked collection dispatcher, but the " +
329
+ "actor does not have a liked property. Set the property " +
330
+ "with Context.getLikedUri(handle).");
331
+ }
332
+ else if (actor.likedId.href != context.getLikedUri(handle).href) {
333
+ logger.warn("You configured a liked collection dispatcher, but the " +
334
+ "actor's liked property does not match the liked collection " +
335
+ "URI. Set the property with Context.getLikedUri(handle).");
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
+ }
324
351
  if (this.#router.has("inbox")) {
325
352
  if (actor.inboxId == null) {
326
353
  logger.warn("You configured inbox listeners, but the actor does not " +
@@ -645,6 +672,50 @@ export class Federation {
645
672
  };
646
673
  return setters;
647
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
+ }
648
719
  /**
649
720
  * Assigns the URL path for the inbox and starts setting inbox listeners.
650
721
  *
@@ -981,6 +1052,16 @@ export class Federation {
981
1052
  onNotFound,
982
1053
  onNotAcceptable,
983
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
+ });
984
1065
  default: {
985
1066
  const response = onNotFound(request);
986
1067
  return response instanceof Promise ? await response : response;
@@ -1086,6 +1167,13 @@ class ContextImpl {
1086
1167
  }
1087
1168
  return new URL(path, this.#url);
1088
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
+ }
1089
1177
  parseUri(uri) {
1090
1178
  if (uri.origin !== this.#url.origin)
1091
1179
  return null;
@@ -1122,6 +1210,9 @@ class ContextImpl {
1122
1210
  else if (route.name === "liked") {
1123
1211
  return { type: "liked", handle: route.values.handle };
1124
1212
  }
1213
+ else if (route.name === "featured") {
1214
+ return { type: "featured", handle: route.values.handle };
1215
+ }
1125
1216
  return null;
1126
1217
  }
1127
1218
  getHandleFromActorUri(actorUri) {
@@ -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
@@ -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
@@ -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