@fedify/fedify 0.9.0-dev.171 → 0.9.0-dev.173

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of @fedify/fedify might be problematic. Click here for more details.

package/CHANGES.md CHANGED
@@ -8,10 +8,28 @@ Version 0.9.0
8
8
 
9
9
  To be released.
10
10
 
11
+ - Added `Hashtag` class to Activity Vocabulary API. [[#48]]
12
+
13
+ - Added `Emoji` class to Activity Vocabulary API. [[#48]]
14
+
15
+ - Added an actor handle normalization function.
16
+
17
+ - Added `normalizeActorHandle()` function.
18
+ - Added `NormalizeActorHandleOptions` interface.
19
+ - The `getActorHandle()` function now guarantees that the returned
20
+ actor handle is normalized.
21
+ - Added the second optional parameter to `getActorHandle()` function.
22
+ - The return type of `getActorHandle()` function became
23
+ ``Promise<`@${string}@${string}` | `${string}@${string}`>``
24
+ (was ``Promise<`@${string}@${string}`>``).
25
+
11
26
  - Added more log messages using the [LogTape] library. Currently the below
12
27
  logger categories are used:
13
28
 
14
29
  - `["fedify", "federation", "actor"]`
30
+ - `["fedify", "federation", "http"]`
31
+
32
+ [#48]: https://github.com/dahlia/fedify/issues/48
15
33
 
16
34
 
17
35
  Version 0.8.0
@@ -22,7 +40,7 @@ Released on May 6, 2024.
22
40
  - The CLI toolchain for testing and debugging is now available on JSR:
23
41
  [@fedify/cli]. You can install it with
24
42
  `deno install -A --unstable-fs --unstable-kv --unstable-temporal -n fedify
25
- jsr:@fedify/cli`, or download a standalone exectuable from the [releases]
43
+ jsr:@fedify/cli`, or download a standalone executable from the [releases]
26
44
  page.
27
45
 
28
46
  - Added `fedify` command.
@@ -843,7 +843,26 @@ export class Federation {
843
843
  * @returns The response to the request.
844
844
  * @since 0.6.0
845
845
  */
846
- async fetch(request, { onNotFound, onNotAcceptable, onUnauthorized, contextData, }) {
846
+ async fetch(request, options) {
847
+ const response = await this.#fetch(request, options);
848
+ const logger = getLogger(["fedify", "federation", "http"]);
849
+ const url = new URL(request.url);
850
+ const logTpl = "{method} {path}: {status}";
851
+ const values = {
852
+ method: request.method,
853
+ path: `${url.pathname}${url.search}`,
854
+ url: request.url,
855
+ status: response.status,
856
+ };
857
+ if (response.status >= 500)
858
+ logger.error(logTpl, values);
859
+ else if (response.status >= 400)
860
+ logger.warn(logTpl, values);
861
+ else
862
+ logger.info(logTpl, values);
863
+ return response;
864
+ }
865
+ async #fetch(request, { onNotFound, onNotAcceptable, onUnauthorized, contextData, }) {
847
866
  onNotFound ??= notFound;
848
867
  onNotAcceptable ??= notAcceptable;
849
868
  onUnauthorized ??= unauthorized;
@@ -1,3 +1,4 @@
1
+ import { toASCII, toUnicode } from "node:punycode";
1
2
  import { lookupWebFinger } from "../webfinger/lookup.js";
2
3
  import { Application, Group, Organization, Person, Service } from "./vocab.js";
3
4
  /**
@@ -66,13 +67,15 @@ export function getActorClassByTypeName(typeName) {
66
67
  * ```
67
68
  *
68
69
  * @param actor The actor or actor URI to get the handle from.
70
+ * @param options The options for normalizing the actor handle.
69
71
  * @returns The actor handle. It starts with `@` and is followed by the
70
- * username and domain, separated by `@`.
72
+ * username and domain, separated by `@` by default (it can be
73
+ * customized with the options).
71
74
  * @throws {TypeError} If the actor does not have enough information to get the
72
75
  * handle.
73
76
  * @since 0.4.0
74
77
  */
75
- export async function getActorHandle(actor) {
78
+ export async function getActorHandle(actor, options = {}) {
76
79
  const actorId = actor instanceof URL ? actor : actor.id;
77
80
  if (actorId != null) {
78
81
  const result = await lookupWebFinger(actorId);
@@ -82,14 +85,37 @@ export async function getActorHandle(actor) {
82
85
  aliases.unshift(result.subject);
83
86
  for (const alias of aliases) {
84
87
  const match = alias.match(/^acct:([^@]+)@([^@]+)$/);
85
- if (match != null)
86
- return `@${match[1]}@${match[2]}`;
88
+ if (match != null) {
89
+ return normalizeActorHandle(`@${match[1]}@${match[2]}`, options);
90
+ }
87
91
  }
88
92
  }
89
93
  }
90
94
  if (!(actor instanceof URL) && actor.preferredUsername != null &&
91
95
  actor.id != null) {
92
- return `@${actor.preferredUsername}@${actor.id.host}`;
96
+ return normalizeActorHandle(`@${actor.preferredUsername}@${actor.id.host}`, options);
93
97
  }
94
98
  throw new TypeError("Actor does not have enough information to get the handle.");
95
99
  }
100
+ /**
101
+ * Normalizes the given actor handle.
102
+ * @param handle The full handle of the actor to normalize.
103
+ * @param options The options for normalizing the actor handle.
104
+ * @returns The normalized actor handle.
105
+ * @throws {TypeError} If the actor handle is invalid.
106
+ */
107
+ export function normalizeActorHandle(handle, options = {}) {
108
+ handle = handle.replace(/^@/, "");
109
+ const atPos = handle.indexOf("@");
110
+ if (atPos < 1)
111
+ throw new TypeError("Invalid actor handle.");
112
+ let domain = handle.substring(atPos + 1);
113
+ if (domain.length < 1 || domain.includes("@")) {
114
+ throw new TypeError("Invalid actor handle.");
115
+ }
116
+ domain = domain.toLowerCase();
117
+ domain = options.punycode ? toASCII(domain) : toUnicode(domain);
118
+ domain = domain.toLowerCase();
119
+ const user = handle.substring(0, atPos);
120
+ return options.trimLeadingAt ? `${user}@${domain}` : `@${user}@${domain}`;
121
+ }
@@ -7,5 +7,10 @@ description: |
7
7
  Indicates that the `actor` is calling the `target`'s attention the `object`.
8
8
 
9
9
  The `origin` typically has no defined meaning.
10
- defaultContext: "https://www.w3.org/ns/activitystreams"
10
+ defaultContext:
11
+ - "https://www.w3.org/ns/activitystreams"
12
+ - toot: "http://joinmastodon.org/ns#"
13
+ sensitive: "as:sensitive"
14
+ Emoji: "toot:Emoji"
15
+ Hashtag: "as:Hashtag"
11
16
  properties: []
@@ -4,5 +4,10 @@ uri: "https://www.w3.org/ns/activitystreams#Article"
4
4
  extends: "https://www.w3.org/ns/activitystreams#Object"
5
5
  entity: true
6
6
  description: Represents any kind of multi-paragraph written work.
7
- defaultContext: "https://www.w3.org/ns/activitystreams"
7
+ defaultContext:
8
+ - "https://www.w3.org/ns/activitystreams"
9
+ - toot: "http://joinmastodon.org/ns#"
10
+ sensitive: "as:sensitive"
11
+ Emoji: "toot:Emoji"
12
+ Hashtag: "as:Hashtag"
8
13
  properties: []
@@ -4,5 +4,10 @@ uri: "https://www.w3.org/ns/activitystreams#Create"
4
4
  extends: "https://www.w3.org/ns/activitystreams#Activity"
5
5
  entity: true
6
6
  description: Indicates that the `actor` has created the `object`.
7
- defaultContext: "https://www.w3.org/ns/activitystreams"
7
+ defaultContext:
8
+ - "https://www.w3.org/ns/activitystreams"
9
+ - toot: "http://joinmastodon.org/ns#"
10
+ sensitive: "as:sensitive"
11
+ Emoji: "toot:Emoji"
12
+ Hashtag: "as:Hashtag"
8
13
  properties: []
@@ -0,0 +1,11 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: Emoji
3
+ uri: "http://joinmastodon.org/ns#Emoji"
4
+ extends: "https://www.w3.org/ns/activitystreams#Object"
5
+ entity: true
6
+ description: Represents a custom emoji.
7
+ defaultContext:
8
+ - "https://www.w3.org/ns/activitystreams"
9
+ - toot: "http://joinmastodon.org/ns#"
10
+ Emoji: "toot:Emoji"
11
+ properties: []
@@ -0,0 +1,13 @@
1
+ $schema: ../codegen/schema.yaml
2
+ name: Hashtag
3
+ uri: "https://www.w3.org/ns/activitystreams#Hashtag"
4
+ extends: "https://www.w3.org/ns/activitystreams#Link"
5
+ entity: false
6
+ description: |
7
+ A specialized {@link Link} that represents an #hashtag.
8
+
9
+ See also <https://swicg.github.io/miscellany/#Hashtag>.
10
+ defaultContext:
11
+ - "https://www.w3.org/ns/activitystreams"
12
+ - Hashtag: "as:Hashtag"
13
+ properties: []
@@ -6,5 +6,10 @@ entity: true
6
6
  description: |
7
7
  Represents a short written work typically less than a single paragraph in
8
8
  length.
9
- defaultContext: "https://www.w3.org/ns/activitystreams"
9
+ defaultContext:
10
+ - "https://www.w3.org/ns/activitystreams"
11
+ - toot: "http://joinmastodon.org/ns#"
12
+ sensitive: "as:sensitive"
13
+ Emoji: "toot:Emoji"
14
+ Hashtag: "as:Hashtag"
10
15
  properties: []
@@ -9,5 +9,10 @@ description: |
9
9
  set of modifications made to `object`.
10
10
 
11
11
  The `target` and `origin` typically have no defined meaning.
12
- defaultContext: "https://www.w3.org/ns/activitystreams"
12
+ defaultContext:
13
+ - "https://www.w3.org/ns/activitystreams"
14
+ - toot: "http://joinmastodon.org/ns#"
15
+ sensitive: "as:sensitive"
16
+ Emoji: "toot:Emoji"
17
+ Hashtag: "as:Hashtag"
13
18
  properties: []