@fedify/vocab 2.4.0-dev.1528 → 2.4.0-dev.1564

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.
@@ -12,9 +12,13 @@ defaultContext:
12
12
  - "https://www.w3.org/ns/did/v1"
13
13
  - "https://w3id.org/security/multikey/v1"
14
14
  - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
15
16
  - alsoKnownAs:
16
17
  "@id": "as:alsoKnownAs"
17
18
  "@type": "@id"
19
+ featuredCollections:
20
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections"
21
+ "@type": "@id"
18
22
  manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
19
23
  movedTo:
20
24
  "@id": "as:movedTo"
@@ -196,6 +200,15 @@ properties:
196
200
  range:
197
201
  - "https://www.w3.org/ns/activitystreams#Collection"
198
202
 
203
+ - singularName: featuredCollections
204
+ functional: true
205
+ compactName: featuredCollections
206
+ uri: "https://w3id.org/fep/7aa9#featuredCollections"
207
+ description: |
208
+ A collection of {@link FeaturedCollection}s created by this actor.
209
+ range:
210
+ - "https://www.w3.org/ns/activitystreams#Collection"
211
+
199
212
  - pluralName: streams
200
213
  singularName: stream
201
214
  singularAccessor: false
@@ -0,0 +1,33 @@
1
+ $schema: ../../vocab-tools/schema.yaml
2
+ name: FeatureAuthorization
3
+ compactName: FeatureAuthorization
4
+ uri: "https://w3id.org/fep/7aa9#FeatureAuthorization"
5
+ extends: "https://www.w3.org/ns/activitystreams#Object"
6
+ entity: true
7
+ description: |
8
+ Proves that an actor consented to being included in a
9
+ {@link FeaturedCollection}.
10
+
11
+ See [FEP-7aa9](https://w3id.org/fep/7aa9) for details.
12
+ defaultContext:
13
+ - "https://www.w3.org/ns/activitystreams"
14
+ - "https://w3id.org/security/data-integrity/v1"
15
+ - "https://gotosocial.org/ns"
16
+ - "https://w3id.org/fep/7aa9"
17
+
18
+ properties:
19
+ - singularName: interactingObject
20
+ functional: true
21
+ compactName: interactingObject
22
+ uri: "https://gotosocial.org/ns#interactingObject"
23
+ description: The featured collection for which the authorization was granted.
24
+ range:
25
+ - "https://www.w3.org/ns/activitystreams#Object"
26
+
27
+ - singularName: interactionTarget
28
+ functional: true
29
+ compactName: interactionTarget
30
+ uri: "https://gotosocial.org/ns#interactionTarget"
31
+ description: The actor that was authorized to be featured.
32
+ range:
33
+ - "https://www.w3.org/ns/activitystreams#Object"
@@ -0,0 +1,41 @@
1
+ $schema: ../../vocab-tools/schema.yaml
2
+ name: FeaturedCollection
3
+ compactName: FeaturedCollection
4
+ uri: "https://w3id.org/fep/7aa9#FeaturedCollection"
5
+ extends: "https://www.w3.org/ns/activitystreams#OrderedCollection"
6
+ entity: true
7
+ description: |
8
+ A curated collection of recommended actors or other objects.
9
+
10
+ See [FEP-7aa9](https://w3id.org/fep/7aa9) for details.
11
+ defaultContext:
12
+ - "https://www.w3.org/ns/activitystreams"
13
+ - "https://w3id.org/security/data-integrity/v1"
14
+ - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
16
+ - toot: "http://joinmastodon.org/ns#"
17
+ sensitive: "as:sensitive"
18
+ discoverable: "toot:discoverable"
19
+ Hashtag: "as:Hashtag"
20
+
21
+ properties:
22
+ - singularName: topic
23
+ functional: true
24
+ compactName: topic
25
+ uri: "https://w3id.org/fep/7aa9#topic"
26
+ description: |
27
+ A single {@link Hashtag} object that represents the main topic or category
28
+ of this featured collection.
29
+ range:
30
+ - "https://www.w3.org/ns/activitystreams#Hashtag"
31
+
32
+ - singularName: discoverable
33
+ functional: true
34
+ compactName: discoverable
35
+ uri: "http://joinmastodon.org/ns#discoverable"
36
+ description: |
37
+ When present and set to `false`, signals that this featured collection is
38
+ not meant to be discovered by search, onboarding, or similar discovery
39
+ features.
40
+ range:
41
+ - "http://www.w3.org/2001/XMLSchema#boolean"
@@ -0,0 +1,34 @@
1
+ $schema: ../../vocab-tools/schema.yaml
2
+ name: FeaturedItem
3
+ compactName: FeaturedItem
4
+ uri: "https://w3id.org/fep/7aa9#FeaturedItem"
5
+ extends: "https://www.w3.org/ns/activitystreams#Object"
6
+ entity: true
7
+ description: |
8
+ A single entry in a {@link FeaturedCollection}.
9
+
10
+ See [FEP-7aa9](https://w3id.org/fep/7aa9) for details.
11
+ defaultContext:
12
+ - "https://www.w3.org/ns/activitystreams"
13
+ - "https://w3id.org/security/data-integrity/v1"
14
+ - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
16
+
17
+ properties:
18
+ - singularName: featuredObject
19
+ functional: true
20
+ compactName: featuredObject
21
+ uri: "https://w3id.org/fep/7aa9#featuredObject"
22
+ description: The object being featured.
23
+ range:
24
+ - "https://www.w3.org/ns/activitystreams#Object"
25
+
26
+ - singularName: featureAuthorization
27
+ functional: true
28
+ compactName: featureAuthorization
29
+ uri: "https://w3id.org/fep/7aa9#featureAuthorization"
30
+ description: |
31
+ The {@link FeatureAuthorization} proving that the featured actor consented
32
+ to inclusion in the featured collection.
33
+ range:
34
+ - "https://w3id.org/fep/7aa9#FeatureAuthorization"
@@ -0,0 +1,21 @@
1
+ $schema: ../../vocab-tools/schema.yaml
2
+ name: FeatureRequest
3
+ compactName: FeatureRequest
4
+ uri: "https://w3id.org/fep/7aa9#FeatureRequest"
5
+ extends: "https://www.w3.org/ns/activitystreams#Activity"
6
+ entity: true
7
+ description: |
8
+ A request for consent before featuring an actor in a
9
+ {@link FeaturedCollection}.
10
+
11
+ The `object` property references the actor to be included, and the
12
+ `instrument` property references the featured collection.
13
+
14
+ See [FEP-7aa9](https://w3id.org/fep/7aa9) for details.
15
+ defaultContext:
16
+ - "https://w3id.org/identity/v1"
17
+ - "https://www.w3.org/ns/activitystreams"
18
+ - "https://w3id.org/security/data-integrity/v1"
19
+ - "https://gotosocial.org/ns"
20
+ - "https://w3id.org/fep/7aa9"
21
+ properties: []
package/src/group.yaml CHANGED
@@ -12,9 +12,13 @@ defaultContext:
12
12
  - "https://www.w3.org/ns/did/v1"
13
13
  - "https://w3id.org/security/multikey/v1"
14
14
  - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
15
16
  - alsoKnownAs:
16
17
  "@id": "as:alsoKnownAs"
17
18
  "@type": "@id"
19
+ featuredCollections:
20
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections"
21
+ "@type": "@id"
18
22
  manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
19
23
  movedTo:
20
24
  "@id": "as:movedTo"
@@ -196,6 +200,15 @@ properties:
196
200
  range:
197
201
  - "https://www.w3.org/ns/activitystreams#Collection"
198
202
 
203
+ - singularName: featuredCollections
204
+ functional: true
205
+ compactName: featuredCollections
206
+ uri: "https://w3id.org/fep/7aa9#featuredCollections"
207
+ description: |
208
+ A collection of {@link FeaturedCollection}s created by this actor.
209
+ range:
210
+ - "https://www.w3.org/ns/activitystreams#Collection"
211
+
199
212
  - pluralName: streams
200
213
  singularName: stream
201
214
  singularAccessor: false
@@ -12,9 +12,24 @@ description: |
12
12
 
13
13
  See [GoToSocial interaction controls](https://docs.gotosocial.org/en/latest/federation/interaction_controls/)
14
14
  for details.
15
- defaultContext: "https://gotosocial.org/ns"
15
+ defaultContext:
16
+ - "https://gotosocial.org/ns"
17
+ - "https://w3id.org/fep/7aa9"
16
18
 
17
19
  properties:
20
+ - singularName: canFeature
21
+ functional: true
22
+ compactName: canFeature
23
+ uri: "https://w3id.org/fep/7aa9#canFeature"
24
+ untyped: true
25
+ description: |
26
+ The sub-policy specifying who can feature the actor in a
27
+ {@link FeaturedCollection}.
28
+
29
+ See [FEP-7aa9](https://w3id.org/fep/7aa9) for details.
30
+ range:
31
+ - "https://gotosocial.org/ns#InteractionRule"
32
+
18
33
  - singularName: canLike
19
34
  functional: true
20
35
  compactName: canLike
@@ -12,9 +12,13 @@ defaultContext:
12
12
  - "https://www.w3.org/ns/did/v1"
13
13
  - "https://w3id.org/security/multikey/v1"
14
14
  - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
15
16
  - alsoKnownAs:
16
17
  "@id": "as:alsoKnownAs"
17
18
  "@type": "@id"
19
+ featuredCollections:
20
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections"
21
+ "@type": "@id"
18
22
  manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
19
23
  movedTo:
20
24
  "@id": "as:movedTo"
@@ -196,6 +200,15 @@ properties:
196
200
  range:
197
201
  - "https://www.w3.org/ns/activitystreams#Collection"
198
202
 
203
+ - singularName: featuredCollections
204
+ functional: true
205
+ compactName: featuredCollections
206
+ uri: "https://w3id.org/fep/7aa9#featuredCollections"
207
+ description: |
208
+ A collection of {@link FeaturedCollection}s created by this actor.
209
+ range:
210
+ - "https://www.w3.org/ns/activitystreams#Collection"
211
+
199
212
  - pluralName: streams
200
213
  singularName: stream
201
214
  singularAccessor: false
package/src/person.yaml CHANGED
@@ -12,9 +12,13 @@ defaultContext:
12
12
  - "https://www.w3.org/ns/did/v1"
13
13
  - "https://w3id.org/security/multikey/v1"
14
14
  - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
15
16
  - alsoKnownAs:
16
17
  "@id": "as:alsoKnownAs"
17
18
  "@type": "@id"
19
+ featuredCollections:
20
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections"
21
+ "@type": "@id"
18
22
  manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
19
23
  movedTo:
20
24
  "@id": "as:movedTo"
@@ -196,6 +200,15 @@ properties:
196
200
  range:
197
201
  - "https://www.w3.org/ns/activitystreams#Collection"
198
202
 
203
+ - singularName: featuredCollections
204
+ functional: true
205
+ compactName: featuredCollections
206
+ uri: "https://w3id.org/fep/7aa9#featuredCollections"
207
+ description: |
208
+ A collection of {@link FeaturedCollection}s created by this actor.
209
+ range:
210
+ - "https://www.w3.org/ns/activitystreams#Collection"
211
+
199
212
  - pluralName: streams
200
213
  singularName: stream
201
214
  singularAccessor: false
package/src/service.yaml CHANGED
@@ -12,9 +12,13 @@ defaultContext:
12
12
  - "https://www.w3.org/ns/did/v1"
13
13
  - "https://w3id.org/security/multikey/v1"
14
14
  - "https://gotosocial.org/ns"
15
+ - "https://w3id.org/fep/7aa9"
15
16
  - alsoKnownAs:
16
17
  "@id": "as:alsoKnownAs"
17
18
  "@type": "@id"
19
+ featuredCollections:
20
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections"
21
+ "@type": "@id"
18
22
  manuallyApprovesFollowers: "as:manuallyApprovesFollowers"
19
23
  movedTo:
20
24
  "@id": "as:movedTo"
@@ -196,6 +200,15 @@ properties:
196
200
  range:
197
201
  - "https://www.w3.org/ns/activitystreams#Collection"
198
202
 
203
+ - singularName: featuredCollections
204
+ functional: true
205
+ compactName: featuredCollections
206
+ uri: "https://w3id.org/fep/7aa9#featuredCollections"
207
+ description: |
208
+ A collection of {@link FeaturedCollection}s created by this actor.
209
+ range:
210
+ - "https://www.w3.org/ns/activitystreams#Collection"
211
+
199
212
  - pluralName: streams
200
213
  singularName: stream
201
214
  singularAccessor: false
package/src/vocab.test.ts CHANGED
@@ -36,6 +36,10 @@ import {
36
36
  Delete,
37
37
  Document,
38
38
  Endpoints,
39
+ FeatureAuthorization,
40
+ FeaturedCollection,
41
+ FeaturedItem,
42
+ FeatureRequest,
39
43
  Follow,
40
44
  Hashtag,
41
45
  Intent,
@@ -104,6 +108,23 @@ const QUOTE_REQUEST_CONTEXT = [
104
108
  },
105
109
  ] as const;
106
110
 
111
+ const FEATURE_CONTEXT = [
112
+ "https://www.w3.org/ns/activitystreams",
113
+ "https://w3id.org/security/data-integrity/v1",
114
+ "https://gotosocial.org/ns",
115
+ "https://w3id.org/fep/7aa9",
116
+ ] as const;
117
+
118
+ const FEATURED_COLLECTION_CONTEXT = [
119
+ ...FEATURE_CONTEXT,
120
+ {
121
+ Hashtag: "as:Hashtag",
122
+ discoverable: "toot:discoverable",
123
+ sensitive: "as:sensitive",
124
+ toot: "http://joinmastodon.org/ns#",
125
+ },
126
+ ] as const;
127
+
107
128
  const DELETE_QUOTE_REQUEST_CONTEXT = [
108
129
  "https://w3id.org/identity/v1",
109
130
  "https://www.w3.org/ns/activitystreams",
@@ -1734,6 +1755,7 @@ test("Person.toJsonLd()", async () => {
1734
1755
  "https://www.w3.org/ns/did/v1",
1735
1756
  "https://w3id.org/security/multikey/v1",
1736
1757
  "https://gotosocial.org/ns",
1758
+ "https://w3id.org/fep/7aa9",
1737
1759
  {
1738
1760
  PropertyValue: "schema:PropertyValue",
1739
1761
  alsoKnownAs: {
@@ -1749,6 +1771,10 @@ test("Person.toJsonLd()", async () => {
1749
1771
  "@id": "toot:featured",
1750
1772
  "@type": "@id",
1751
1773
  },
1774
+ featuredCollections: {
1775
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections",
1776
+ "@type": "@id",
1777
+ },
1752
1778
  featuredTags: {
1753
1779
  "@id": "toot:featuredTags",
1754
1780
  "@type": "@id",
@@ -2452,6 +2478,266 @@ test("InteractionPolicy.canQuote", async () => {
2452
2478
  );
2453
2479
  });
2454
2480
 
2481
+ test("InteractionPolicy.canFeature", async () => {
2482
+ const person = new Person({
2483
+ id: new URL("https://example.com/users/alice"),
2484
+ featuredCollections: new URL(
2485
+ "https://example.com/users/alice/featured_collections",
2486
+ ),
2487
+ interactionPolicy: new InteractionPolicy({
2488
+ canFeature: new InteractionRule({
2489
+ automaticApproval: new URL(
2490
+ "https://www.w3.org/ns/activitystreams#Public",
2491
+ ),
2492
+ }),
2493
+ }),
2494
+ });
2495
+ const expected = {
2496
+ "@context": [
2497
+ "https://www.w3.org/ns/activitystreams",
2498
+ "https://w3id.org/security/v1",
2499
+ "https://w3id.org/security/data-integrity/v1",
2500
+ "https://www.w3.org/ns/did/v1",
2501
+ "https://w3id.org/security/multikey/v1",
2502
+ "https://gotosocial.org/ns",
2503
+ "https://w3id.org/fep/7aa9",
2504
+ {
2505
+ Emoji: "toot:Emoji",
2506
+ PropertyValue: "schema:PropertyValue",
2507
+ _misskey_followedMessage: "misskey:_misskey_followedMessage",
2508
+ alsoKnownAs: {
2509
+ "@id": "as:alsoKnownAs",
2510
+ "@type": "@id",
2511
+ },
2512
+ discoverable: "toot:discoverable",
2513
+ featured: {
2514
+ "@id": "toot:featured",
2515
+ "@type": "@id",
2516
+ },
2517
+ featuredCollections: {
2518
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections",
2519
+ "@type": "@id",
2520
+ },
2521
+ featuredTags: {
2522
+ "@id": "toot:featuredTags",
2523
+ "@type": "@id",
2524
+ },
2525
+ indexable: "toot:indexable",
2526
+ isCat: "misskey:isCat",
2527
+ manuallyApprovesFollowers: "as:manuallyApprovesFollowers",
2528
+ memorial: "toot:memorial",
2529
+ misskey: "https://misskey-hub.net/ns#",
2530
+ movedTo: {
2531
+ "@id": "as:movedTo",
2532
+ "@type": "@id",
2533
+ },
2534
+ schema: "http://schema.org#",
2535
+ suspended: "toot:suspended",
2536
+ toot: "http://joinmastodon.org/ns#",
2537
+ value: "schema:value",
2538
+ },
2539
+ ],
2540
+ type: "Person",
2541
+ id: "https://example.com/users/alice",
2542
+ featuredCollections: "https://example.com/users/alice/featured_collections",
2543
+ interactionPolicy: {
2544
+ canFeature: {
2545
+ automaticApproval: "as:Public",
2546
+ },
2547
+ },
2548
+ };
2549
+ deepStrictEqual(
2550
+ await person.toJsonLd({ contextLoader: mockDocumentLoader }),
2551
+ expected,
2552
+ );
2553
+
2554
+ const loaded = await Person.fromJsonLd(expected, {
2555
+ documentLoader: mockDocumentLoader,
2556
+ contextLoader: mockDocumentLoader,
2557
+ });
2558
+ deepStrictEqual(
2559
+ loaded.featuredCollectionsId,
2560
+ new URL("https://example.com/users/alice/featured_collections"),
2561
+ );
2562
+ assertInstanceOf(loaded.interactionPolicy, InteractionPolicy);
2563
+ assertInstanceOf(loaded.interactionPolicy.canFeature, InteractionRule);
2564
+ deepStrictEqual(
2565
+ loaded.interactionPolicy.canFeature.automaticApproval,
2566
+ new URL("https://www.w3.org/ns/activitystreams#Public"),
2567
+ );
2568
+ deepStrictEqual(
2569
+ await loaded.toJsonLd({ contextLoader: mockDocumentLoader }),
2570
+ expected,
2571
+ );
2572
+
2573
+ const loadedFromFepContext = await Person.fromJsonLd({
2574
+ "@context": [
2575
+ "https://www.w3.org/ns/activitystreams",
2576
+ "https://gotosocial.org/ns",
2577
+ "https://w3id.org/fep/7aa9",
2578
+ {
2579
+ featuredCollections: {
2580
+ "@id": "https://w3id.org/fep/7aa9#featuredCollections",
2581
+ "@type": "@id",
2582
+ },
2583
+ },
2584
+ ],
2585
+ type: "Person",
2586
+ id: "https://example.com/users/alice",
2587
+ featuredCollections: "https://example.com/users/alice/featured_collections",
2588
+ }, {
2589
+ documentLoader: mockDocumentLoader,
2590
+ contextLoader: mockDocumentLoader,
2591
+ });
2592
+ deepStrictEqual(
2593
+ loadedFromFepContext.featuredCollectionsId,
2594
+ new URL("https://example.com/users/alice/featured_collections"),
2595
+ );
2596
+ });
2597
+
2598
+ test("FeaturedCollection.toJsonLd()", async () => {
2599
+ const collection = new FeaturedCollection({
2600
+ id: new URL("https://example.com/users/alice/featured/1"),
2601
+ name: "Cute cats",
2602
+ attribution: new URL("https://example.com/users/alice"),
2603
+ topic: new Hashtag({ name: "#cats" }),
2604
+ discoverable: false,
2605
+ totalItems: 1,
2606
+ });
2607
+ const expected = {
2608
+ "@context": FEATURED_COLLECTION_CONTEXT,
2609
+ type: "FeaturedCollection",
2610
+ id: "https://example.com/users/alice/featured/1",
2611
+ attributedTo: "https://example.com/users/alice",
2612
+ name: "Cute cats",
2613
+ totalItems: 1,
2614
+ topic: {
2615
+ type: "Hashtag",
2616
+ name: "#cats",
2617
+ },
2618
+ discoverable: false,
2619
+ };
2620
+ deepStrictEqual(
2621
+ await collection.toJsonLd({ contextLoader: mockDocumentLoader }),
2622
+ expected,
2623
+ );
2624
+
2625
+ const loaded = await FeaturedCollection.fromJsonLd(expected, {
2626
+ documentLoader: mockDocumentLoader,
2627
+ contextLoader: mockDocumentLoader,
2628
+ });
2629
+ assertInstanceOf(loaded, FeaturedCollection);
2630
+ deepStrictEqual(loaded.name, "Cute cats");
2631
+ deepStrictEqual(
2632
+ loaded.attributionId,
2633
+ new URL("https://example.com/users/alice"),
2634
+ );
2635
+ assertInstanceOf(loaded.topic, Hashtag);
2636
+ deepStrictEqual(loaded.topic.name, "#cats");
2637
+ deepStrictEqual(loaded.discoverable, false);
2638
+ deepStrictEqual(loaded.totalItems, 1);
2639
+ deepStrictEqual(
2640
+ await loaded.toJsonLd({ contextLoader: mockDocumentLoader }),
2641
+ expected,
2642
+ );
2643
+ });
2644
+
2645
+ test("FeaturedItem.toJsonLd()", async () => {
2646
+ const item = new FeaturedItem({
2647
+ id: new URL("https://example.com/users/alice/featured/1/items/1"),
2648
+ featuredObject: new URL("https://example.com/users/bob"),
2649
+ featureAuthorization: new URL("https://example.com/users/bob/stamps/1"),
2650
+ });
2651
+ const expected = {
2652
+ "@context": FEATURE_CONTEXT,
2653
+ type: "FeaturedItem",
2654
+ id: "https://example.com/users/alice/featured/1/items/1",
2655
+ featuredObject: "https://example.com/users/bob",
2656
+ featureAuthorization: "https://example.com/users/bob/stamps/1",
2657
+ };
2658
+ deepStrictEqual(
2659
+ await item.toJsonLd({ contextLoader: mockDocumentLoader }),
2660
+ expected,
2661
+ );
2662
+
2663
+ const loaded = await FeaturedItem.fromJsonLd(expected, {
2664
+ documentLoader: mockDocumentLoader,
2665
+ contextLoader: mockDocumentLoader,
2666
+ });
2667
+ assertInstanceOf(loaded, FeaturedItem);
2668
+ deepStrictEqual(
2669
+ loaded.featuredObjectId,
2670
+ new URL("https://example.com/users/bob"),
2671
+ );
2672
+ deepStrictEqual(
2673
+ loaded.featureAuthorizationId,
2674
+ new URL("https://example.com/users/bob/stamps/1"),
2675
+ );
2676
+ });
2677
+
2678
+ test("FeatureAuthorization.fromJsonLd()", async () => {
2679
+ const jsonLd = {
2680
+ "@context": FEATURE_CONTEXT,
2681
+ type: "FeatureAuthorization",
2682
+ id: "https://example.com/users/bob/stamps/1",
2683
+ interactingObject: "https://example.com/users/alice/featured/1",
2684
+ interactionTarget: "https://example.com/users/bob",
2685
+ };
2686
+ const authorization = await FeatureAuthorization.fromJsonLd(jsonLd, {
2687
+ documentLoader: mockDocumentLoader,
2688
+ contextLoader: mockDocumentLoader,
2689
+ });
2690
+ assertInstanceOf(authorization, FeatureAuthorization);
2691
+ deepStrictEqual(
2692
+ authorization.interactingObjectId,
2693
+ new URL("https://example.com/users/alice/featured/1"),
2694
+ );
2695
+ deepStrictEqual(
2696
+ authorization.interactionTargetId,
2697
+ new URL("https://example.com/users/bob"),
2698
+ );
2699
+ deepStrictEqual(
2700
+ await authorization.toJsonLd({ contextLoader: mockDocumentLoader }),
2701
+ jsonLd,
2702
+ );
2703
+ });
2704
+
2705
+ test("FeatureRequest.toJsonLd()", async () => {
2706
+ const request = new FeatureRequest({
2707
+ id: new URL("https://example.com/users/alice/featured/1/requests/1"),
2708
+ object: new URL("https://example.com/users/bob"),
2709
+ instrument: new URL("https://example.com/users/alice/featured/1"),
2710
+ });
2711
+ const expected = {
2712
+ "@context": [
2713
+ "https://w3id.org/identity/v1",
2714
+ ...FEATURE_CONTEXT,
2715
+ ],
2716
+ type: "FeatureRequest",
2717
+ id: "https://example.com/users/alice/featured/1/requests/1",
2718
+ object: "https://example.com/users/bob",
2719
+ instrument: "https://example.com/users/alice/featured/1",
2720
+ };
2721
+ deepStrictEqual(
2722
+ await request.toJsonLd({ contextLoader: mockDocumentLoader }),
2723
+ expected,
2724
+ );
2725
+
2726
+ const loaded = await FeatureRequest.fromJsonLd(expected, {
2727
+ documentLoader: mockDocumentLoader,
2728
+ contextLoader: mockDocumentLoader,
2729
+ });
2730
+ assertInstanceOf(loaded, FeatureRequest);
2731
+ deepStrictEqual(
2732
+ loaded.objectId,
2733
+ new URL("https://example.com/users/bob"),
2734
+ );
2735
+ deepStrictEqual(
2736
+ loaded.instrumentId,
2737
+ new URL("https://example.com/users/alice/featured/1"),
2738
+ );
2739
+ });
2740
+
2455
2741
  test("QuoteAuthorization.fromJsonLd()", async () => {
2456
2742
  const jsonLd = {
2457
2743
  "@context": [