@fedify/vocab 2.4.0-dev.1564 → 2.4.0-dev.1570
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/deno.json +1 -1
- package/dist/mod.cjs +9909 -13825
- package/dist/mod.d.cts +676 -1629
- package/dist/mod.d.ts +676 -1629
- package/dist/mod.js +9911 -13823
- package/dist-tests/{actor-B6FsWrG4.mjs → actor-BTMC-aMT.mjs} +2 -2
- package/dist-tests/actor.test.mjs +2 -2
- package/dist-tests/application.yaml +0 -13
- package/dist-tests/group.yaml +0 -13
- package/dist-tests/interactionpolicy.yaml +1 -16
- package/dist-tests/lookup.test.mjs +5 -7
- package/dist-tests/organization.yaml +0 -13
- package/dist-tests/person.yaml +0 -13
- package/dist-tests/service.yaml +0 -13
- package/dist-tests/type.test.mjs +1 -1
- package/dist-tests/{vocab-DOHLQ4UQ.mjs → vocab-XnSGFOqq.mjs} +9908 -13822
- package/dist-tests/vocab.test.mjs +1 -986
- package/package.json +4 -4
- package/src/__snapshots__/vocab.test.ts.snap +0 -609
- package/src/application.yaml +0 -13
- package/src/group.yaml +0 -13
- package/src/interactionpolicy.yaml +1 -16
- package/src/lookup.ts +2 -6
- package/src/organization.yaml +0 -13
- package/src/person.yaml +0 -13
- package/src/service.yaml +0 -13
- package/src/vocab.test.ts +121 -1539
- package/dist-tests/featureauthorization.yaml +0 -33
- package/dist-tests/featuredcollection.yaml +0 -41
- package/dist-tests/featureditem.yaml +0 -34
- package/dist-tests/featurerequest.yaml +0 -21
- package/src/featureauthorization.yaml +0 -33
- package/src/featuredcollection.yaml +0 -41
- package/src/featureditem.yaml +0 -34
- package/src/featurerequest.yaml +0 -21
package/src/vocab.test.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
2
2
|
import {
|
|
3
3
|
decodeMultibase,
|
|
4
|
-
type DocumentLoader,
|
|
5
4
|
LanguageString,
|
|
6
5
|
parseDecimal,
|
|
7
|
-
type RemoteDocument,
|
|
8
6
|
} from "@fedify/vocab-runtime";
|
|
9
7
|
import {
|
|
10
8
|
areAllScalarTypes,
|
|
@@ -36,10 +34,6 @@ import {
|
|
|
36
34
|
Delete,
|
|
37
35
|
Document,
|
|
38
36
|
Endpoints,
|
|
39
|
-
FeatureAuthorization,
|
|
40
|
-
FeaturedCollection,
|
|
41
|
-
FeaturedItem,
|
|
42
|
-
FeatureRequest,
|
|
43
37
|
Follow,
|
|
44
38
|
Hashtag,
|
|
45
39
|
Intent,
|
|
@@ -108,23 +102,6 @@ const QUOTE_REQUEST_CONTEXT = [
|
|
|
108
102
|
},
|
|
109
103
|
] as const;
|
|
110
104
|
|
|
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
|
-
|
|
128
105
|
const DELETE_QUOTE_REQUEST_CONTEXT = [
|
|
129
106
|
"https://w3id.org/identity/v1",
|
|
130
107
|
"https://www.w3.org/ns/activitystreams",
|
|
@@ -492,974 +469,14 @@ test("Activity.fromJsonLd()", async () => {
|
|
|
492
469
|
proofs[0].proofValue,
|
|
493
470
|
decodeMultibase(
|
|
494
471
|
// cSpell: disable
|
|
495
|
-
"z3sXaxjKs4M3BRicwWA9peyNPJvJqxtGsDmpt1jjoHCjgeUf71TRFz56osPSfDErszyLp5Ks1EhYSgpDaNM977Rg2",
|
|
496
|
-
// cSpell: enable
|
|
497
|
-
),
|
|
498
|
-
);
|
|
499
|
-
deepStrictEqual(
|
|
500
|
-
proofs[0].created,
|
|
501
|
-
Temporal.Instant.from("2023-02-24T23:36:38Z"),
|
|
502
|
-
);
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
test("fromJsonLd() handles portable ActivityPub IRIs", async () => {
|
|
506
|
-
const did = "did:key:z6Mkabc";
|
|
507
|
-
const portableActor =
|
|
508
|
-
`ap://${did}/actor?gateways=https%3A%2F%2Fserver.example`;
|
|
509
|
-
const portableObject =
|
|
510
|
-
`ap://${did}/objects/1?gateways=https%3A%2F%2Fserver.example`;
|
|
511
|
-
const uppercasePortableObject =
|
|
512
|
-
`AP://${did}/objects/1?gateways=https%3A%2F%2Fserver.example`;
|
|
513
|
-
const portablePage = `ap://${did}/actor/outbox?page=2`;
|
|
514
|
-
|
|
515
|
-
const note = await Note.fromJsonLd({
|
|
516
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
517
|
-
type: "Note",
|
|
518
|
-
id: uppercasePortableObject,
|
|
519
|
-
attributedTo: `ap+ef61://${
|
|
520
|
-
encodeURIComponent(did)
|
|
521
|
-
}/actor?gateways=https%3A%2F%2Fserver.example`,
|
|
522
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
523
|
-
deepStrictEqual(
|
|
524
|
-
note.id,
|
|
525
|
-
new URL(
|
|
526
|
-
"ap+ef61://did%3Akey%3Az6Mkabc/objects/1?gateways=https%3A%2F%2Fserver.example",
|
|
527
|
-
),
|
|
528
|
-
);
|
|
529
|
-
deepStrictEqual(
|
|
530
|
-
note.attributionId,
|
|
531
|
-
new URL(
|
|
532
|
-
"ap+ef61://did%3Akey%3Az6Mkabc/actor?gateways=https%3A%2F%2Fserver.example",
|
|
533
|
-
),
|
|
534
|
-
);
|
|
535
|
-
const noteJson = await note.toJsonLd({
|
|
536
|
-
contextLoader: mockDocumentLoader,
|
|
537
|
-
}) as Record<string, unknown>;
|
|
538
|
-
deepStrictEqual(noteJson.type, "Note");
|
|
539
|
-
deepStrictEqual(
|
|
540
|
-
noteJson.id,
|
|
541
|
-
"ap+ef61://did:key:z6Mkabc/objects/1?gateways=https%3A%2F%2Fserver.example",
|
|
542
|
-
);
|
|
543
|
-
deepStrictEqual(
|
|
544
|
-
noteJson.attributedTo,
|
|
545
|
-
"ap+ef61://did:key:z6Mkabc/actor?gateways=https%3A%2F%2Fserver.example",
|
|
546
|
-
);
|
|
547
|
-
|
|
548
|
-
const activity = await Activity.fromJsonLd({
|
|
549
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
550
|
-
type: "Create",
|
|
551
|
-
actor: portableActor,
|
|
552
|
-
object: portableObject,
|
|
553
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
554
|
-
deepStrictEqual(
|
|
555
|
-
activity.actorId,
|
|
556
|
-
new URL(
|
|
557
|
-
"ap+ef61://did%3Akey%3Az6Mkabc/actor?gateways=https%3A%2F%2Fserver.example",
|
|
558
|
-
),
|
|
559
|
-
);
|
|
560
|
-
const activityJson = await activity.toJsonLd({
|
|
561
|
-
contextLoader: mockDocumentLoader,
|
|
562
|
-
}) as Record<string, unknown>;
|
|
563
|
-
deepStrictEqual(activityJson.type, "Create");
|
|
564
|
-
deepStrictEqual(
|
|
565
|
-
activityJson.actor,
|
|
566
|
-
"ap+ef61://did:key:z6Mkabc/actor?gateways=https%3A%2F%2Fserver.example",
|
|
567
|
-
);
|
|
568
|
-
deepStrictEqual(
|
|
569
|
-
activityJson.object,
|
|
570
|
-
"ap+ef61://did:key:z6Mkabc/objects/1?gateways=https%3A%2F%2Fserver.example",
|
|
571
|
-
);
|
|
572
|
-
|
|
573
|
-
const person = await Person.fromJsonLd({
|
|
574
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
575
|
-
type: "Person",
|
|
576
|
-
inbox: `ap+ef61://${did}/actor/inbox`,
|
|
577
|
-
outbox: `ap+ef61://${did}/actor/outbox`,
|
|
578
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
579
|
-
deepStrictEqual(
|
|
580
|
-
person.inboxId,
|
|
581
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor/inbox"),
|
|
582
|
-
);
|
|
583
|
-
deepStrictEqual(
|
|
584
|
-
person.outboxId,
|
|
585
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor/outbox"),
|
|
586
|
-
);
|
|
587
|
-
const personJson = await person.toJsonLd({
|
|
588
|
-
contextLoader: mockDocumentLoader,
|
|
589
|
-
}) as Record<string, unknown>;
|
|
590
|
-
deepStrictEqual(personJson.type, "Person");
|
|
591
|
-
deepStrictEqual(personJson.inbox, "ap+ef61://did:key:z6Mkabc/actor/inbox");
|
|
592
|
-
deepStrictEqual(
|
|
593
|
-
personJson.outbox,
|
|
594
|
-
"ap+ef61://did:key:z6Mkabc/actor/outbox",
|
|
595
|
-
);
|
|
596
|
-
|
|
597
|
-
const page = await OrderedCollectionPage.fromJsonLd({
|
|
598
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
599
|
-
type: "OrderedCollectionPage",
|
|
600
|
-
next: portablePage,
|
|
601
|
-
prev: `ap+ef61://${encodeURIComponent(did)}/actor/outbox?page=1`,
|
|
602
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
603
|
-
deepStrictEqual(
|
|
604
|
-
page.nextId,
|
|
605
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor/outbox?page=2"),
|
|
606
|
-
);
|
|
607
|
-
deepStrictEqual(
|
|
608
|
-
page.prevId,
|
|
609
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor/outbox?page=1"),
|
|
610
|
-
);
|
|
611
|
-
const pageJson = await page.toJsonLd({
|
|
612
|
-
contextLoader: mockDocumentLoader,
|
|
613
|
-
}) as Record<string, unknown>;
|
|
614
|
-
deepStrictEqual(pageJson.type, "OrderedCollectionPage");
|
|
615
|
-
deepStrictEqual(
|
|
616
|
-
pageJson.next,
|
|
617
|
-
"ap+ef61://did:key:z6Mkabc/actor/outbox?page=2",
|
|
618
|
-
);
|
|
619
|
-
deepStrictEqual(
|
|
620
|
-
pageJson.prev,
|
|
621
|
-
"ap+ef61://did:key:z6Mkabc/actor/outbox?page=1",
|
|
622
|
-
);
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
test("fromJsonLd() caches text that mentions portable ActivityPub IRIs", async () => {
|
|
626
|
-
const noteJson = {
|
|
627
|
-
"@context": [
|
|
628
|
-
"https://www.w3.org/ns/activitystreams",
|
|
629
|
-
{ extra: "https://example.com/ns#extra" },
|
|
630
|
-
],
|
|
631
|
-
type: "Note",
|
|
632
|
-
id: "https://example.com/notes/1",
|
|
633
|
-
content: "This is text about ap://did:key:z6Mkabc/actor.",
|
|
634
|
-
extra: "This extension property should stay cached.",
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
const note = await Note.fromJsonLd(noteJson, {
|
|
638
|
-
documentLoader: mockDocumentLoader,
|
|
639
|
-
contextLoader: mockDocumentLoader,
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
deepStrictEqual(await note.toJsonLd(), noteJson);
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
test("fromJsonLd() preserves extensions with portable ActivityPub IRIs", async () => {
|
|
646
|
-
const note = await Note.fromJsonLd({
|
|
647
|
-
"@context": [
|
|
648
|
-
"https://www.w3.org/ns/activitystreams",
|
|
649
|
-
{ extra: "https://example.com/ns#extra" },
|
|
650
|
-
],
|
|
651
|
-
type: "Note",
|
|
652
|
-
id: "ap://did:key:z6Mkabc/objects/1",
|
|
653
|
-
extra: "This extension property should stay cached.",
|
|
654
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
655
|
-
|
|
656
|
-
const jsonLd = await note.toJsonLd() as Record<string, unknown>;
|
|
657
|
-
deepStrictEqual(jsonLd.extra, "This extension property should stay cached.");
|
|
658
|
-
deepStrictEqual(jsonLd.id, "ap+ef61://did:key:z6Mkabc/objects/1");
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
test("fromJsonLd() preserves unmapped terms with portable IRIs", async () => {
|
|
662
|
-
const note = await Note.fromJsonLd({
|
|
663
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
664
|
-
type: "Note",
|
|
665
|
-
id: "ap://did:key:z6Mkabc/objects/1",
|
|
666
|
-
extra: "This unmapped property should stay cached.",
|
|
667
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
668
|
-
|
|
669
|
-
const jsonLd = await note.toJsonLd() as Record<string, unknown>;
|
|
670
|
-
deepStrictEqual(
|
|
671
|
-
jsonLd.extra,
|
|
672
|
-
"This unmapped property should stay cached.",
|
|
673
|
-
);
|
|
674
|
-
deepStrictEqual(jsonLd.id, "ap+ef61://did:key:z6Mkabc/objects/1");
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
test("fromJsonLd() preserves expanded arrays with portable IRIs", async () => {
|
|
678
|
-
const expanded = [
|
|
679
|
-
{
|
|
680
|
-
"@id": "https://example.com/activities/1",
|
|
681
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Create"],
|
|
682
|
-
"https://www.w3.org/ns/activitystreams#actor": [
|
|
683
|
-
{ "@id": "ap://did:key:z6Mkabc/actor" },
|
|
684
|
-
],
|
|
685
|
-
"https://www.w3.org/ns/activitystreams#object": [
|
|
686
|
-
{ "@id": "https://example.com/objects/1" },
|
|
687
|
-
],
|
|
688
|
-
},
|
|
689
|
-
{
|
|
690
|
-
"@id": "https://example.com/objects/1",
|
|
691
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
692
|
-
"https://www.w3.org/ns/activitystreams#content": [
|
|
693
|
-
{ "@value": "Sibling node should stay cached." },
|
|
694
|
-
],
|
|
695
|
-
},
|
|
696
|
-
];
|
|
697
|
-
|
|
698
|
-
const activity = await Activity.fromJsonLd(expanded, {
|
|
699
|
-
documentLoader: mockDocumentLoader,
|
|
700
|
-
contextLoader: mockDocumentLoader,
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
deepStrictEqual(
|
|
704
|
-
activity.actorId,
|
|
705
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"),
|
|
706
|
-
);
|
|
707
|
-
deepStrictEqual(await activity.toJsonLd(), [
|
|
708
|
-
{
|
|
709
|
-
"@id": "https://example.com/activities/1",
|
|
710
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Create"],
|
|
711
|
-
"https://www.w3.org/ns/activitystreams#actor": [
|
|
712
|
-
{ "@id": "ap+ef61://did:key:z6Mkabc/actor" },
|
|
713
|
-
],
|
|
714
|
-
"https://www.w3.org/ns/activitystreams#object": [
|
|
715
|
-
{ "@id": "https://example.com/objects/1" },
|
|
716
|
-
],
|
|
717
|
-
},
|
|
718
|
-
{
|
|
719
|
-
"@id": "https://example.com/objects/1",
|
|
720
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
721
|
-
"https://www.w3.org/ns/activitystreams#content": [
|
|
722
|
-
{ "@value": "Sibling node should stay cached." },
|
|
723
|
-
],
|
|
724
|
-
},
|
|
725
|
-
]);
|
|
726
|
-
deepStrictEqual(expanded[0]["https://www.w3.org/ns/activitystreams#actor"], [
|
|
727
|
-
{ "@id": "ap://did:key:z6Mkabc/actor" },
|
|
728
|
-
]);
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
test("fromJsonLd() preserves single-node expanded arrays with portable IRIs", async () => {
|
|
732
|
-
const expanded = [
|
|
733
|
-
{
|
|
734
|
-
"@id": "ap://did:key:z6Mkabc/objects/1",
|
|
735
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
736
|
-
"https://www.w3.org/ns/activitystreams#attributedTo": [
|
|
737
|
-
{ "@id": "ap://did:key:z6Mkabc/actor" },
|
|
738
|
-
],
|
|
739
|
-
"https://www.w3.org/ns/activitystreams#content": [
|
|
740
|
-
{ "@value": "Single expanded node should stay cached as an array." },
|
|
741
|
-
],
|
|
742
|
-
},
|
|
743
|
-
];
|
|
744
|
-
|
|
745
|
-
const note = await Note.fromJsonLd(expanded, {
|
|
746
|
-
documentLoader: mockDocumentLoader,
|
|
747
|
-
contextLoader: mockDocumentLoader,
|
|
748
|
-
});
|
|
749
|
-
|
|
750
|
-
deepStrictEqual(await note.toJsonLd(), [
|
|
751
|
-
{
|
|
752
|
-
"@id": "ap+ef61://did:key:z6Mkabc/objects/1",
|
|
753
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
754
|
-
"https://www.w3.org/ns/activitystreams#attributedTo": [
|
|
755
|
-
{ "@id": "ap+ef61://did:key:z6Mkabc/actor" },
|
|
756
|
-
],
|
|
757
|
-
"https://www.w3.org/ns/activitystreams#content": [
|
|
758
|
-
{ "@value": "Single expanded node should stay cached as an array." },
|
|
759
|
-
],
|
|
760
|
-
},
|
|
761
|
-
]);
|
|
762
|
-
deepStrictEqual(expanded[0]["@id"], "ap://did:key:z6Mkabc/objects/1");
|
|
763
|
-
});
|
|
764
|
-
|
|
765
|
-
test("fromJsonLd() preserves no-context object shape with portable IRIs", async () => {
|
|
766
|
-
const expanded = {
|
|
767
|
-
"@id": "ap://did:key:z6Mkabc/objects/1",
|
|
768
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
769
|
-
"https://www.w3.org/ns/activitystreams#attributedTo": [
|
|
770
|
-
{ "@id": "ap://did:key:z6Mkabc/actor" },
|
|
771
|
-
],
|
|
772
|
-
"https://www.w3.org/ns/activitystreams#content": [
|
|
773
|
-
{ "@value": "No-context object shape should stay cached." },
|
|
774
|
-
],
|
|
775
|
-
};
|
|
776
|
-
|
|
777
|
-
const note = await Note.fromJsonLd(expanded, {
|
|
778
|
-
documentLoader: mockDocumentLoader,
|
|
779
|
-
contextLoader: mockDocumentLoader,
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
deepStrictEqual(await note.toJsonLd(), {
|
|
783
|
-
"@id": "ap+ef61://did:key:z6Mkabc/objects/1",
|
|
784
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
785
|
-
"https://www.w3.org/ns/activitystreams#attributedTo": [
|
|
786
|
-
{ "@id": "ap+ef61://did:key:z6Mkabc/actor" },
|
|
787
|
-
],
|
|
788
|
-
"https://www.w3.org/ns/activitystreams#content": [
|
|
789
|
-
{ "@value": "No-context object shape should stay cached." },
|
|
790
|
-
],
|
|
791
|
-
});
|
|
792
|
-
deepStrictEqual(expanded["@id"], "ap://did:key:z6Mkabc/objects/1");
|
|
793
|
-
});
|
|
794
|
-
|
|
795
|
-
test("fromJsonLd() preserves expanded subtype cache types", async () => {
|
|
796
|
-
const expanded = [
|
|
797
|
-
{
|
|
798
|
-
"@id": "https://example.com/activities/1",
|
|
799
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Create"],
|
|
800
|
-
"https://www.w3.org/ns/activitystreams#actor": [
|
|
801
|
-
{ "@id": "https://example.com/actors/alice" },
|
|
802
|
-
],
|
|
803
|
-
"https://www.w3.org/ns/activitystreams#object": [
|
|
804
|
-
{ "@id": "https://example.com/objects/1" },
|
|
805
|
-
],
|
|
806
|
-
},
|
|
807
|
-
{
|
|
808
|
-
"@id": "https://example.com/objects/1",
|
|
809
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
810
|
-
"https://www.w3.org/ns/activitystreams#attributedTo": [
|
|
811
|
-
{ "@id": "ap://did:key:z6Mkabc/actor" },
|
|
812
|
-
],
|
|
813
|
-
},
|
|
814
|
-
];
|
|
815
|
-
|
|
816
|
-
const activity = await Activity.fromJsonLd(expanded, {
|
|
817
|
-
documentLoader: mockDocumentLoader,
|
|
818
|
-
contextLoader: mockDocumentLoader,
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
deepStrictEqual(await activity.toJsonLd(), [
|
|
822
|
-
{
|
|
823
|
-
"@id": "https://example.com/activities/1",
|
|
824
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Create"],
|
|
825
|
-
"https://www.w3.org/ns/activitystreams#actor": [
|
|
826
|
-
{ "@id": "https://example.com/actors/alice" },
|
|
827
|
-
],
|
|
828
|
-
"https://www.w3.org/ns/activitystreams#object": [
|
|
829
|
-
{ "@id": "https://example.com/objects/1" },
|
|
830
|
-
],
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
"@id": "https://example.com/objects/1",
|
|
834
|
-
"@type": ["https://www.w3.org/ns/activitystreams#Note"],
|
|
835
|
-
"https://www.w3.org/ns/activitystreams#attributedTo": [
|
|
836
|
-
{ "@id": "ap+ef61://did:key:z6Mkabc/actor" },
|
|
837
|
-
],
|
|
838
|
-
},
|
|
839
|
-
]);
|
|
840
|
-
deepStrictEqual(expanded[0]["@type"], [
|
|
841
|
-
"https://www.w3.org/ns/activitystreams#Create",
|
|
842
|
-
]);
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
test("fromJsonLd() preserves compact array contexts with portable IRIs", async () => {
|
|
846
|
-
const note = await Note.fromJsonLd([{
|
|
847
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
848
|
-
type: "Note",
|
|
849
|
-
id: "ap://did:key:z6Mkabc/objects/1",
|
|
850
|
-
}], {
|
|
851
|
-
documentLoader: mockDocumentLoader,
|
|
852
|
-
contextLoader: mockDocumentLoader,
|
|
853
|
-
});
|
|
854
|
-
|
|
855
|
-
deepStrictEqual(await note.toJsonLd(), [{
|
|
856
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
857
|
-
type: "Note",
|
|
858
|
-
id: "ap+ef61://did:key:z6Mkabc/objects/1",
|
|
859
|
-
}]);
|
|
860
|
-
});
|
|
861
|
-
|
|
862
|
-
test("fromJsonLd() preserves compact single-item arrays with portable IRIs", async () => {
|
|
863
|
-
const createJson = {
|
|
864
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
865
|
-
type: "Create",
|
|
866
|
-
actor: ["ap://did:key:z6Mkabc/actor"],
|
|
867
|
-
object: "https://example.com/objects/1",
|
|
868
|
-
};
|
|
869
|
-
|
|
870
|
-
const create = await Create.fromJsonLd(createJson, {
|
|
871
|
-
documentLoader: mockDocumentLoader,
|
|
872
|
-
contextLoader: mockDocumentLoader,
|
|
873
|
-
});
|
|
874
|
-
|
|
875
|
-
deepStrictEqual(await create.toJsonLd(), {
|
|
876
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
877
|
-
type: "Create",
|
|
878
|
-
actor: ["ap+ef61://did:key:z6Mkabc/actor"],
|
|
879
|
-
object: "https://example.com/objects/1",
|
|
880
|
-
});
|
|
881
|
-
deepStrictEqual(createJson.actor, ["ap://did:key:z6Mkabc/actor"]);
|
|
882
|
-
});
|
|
883
|
-
|
|
884
|
-
test("fromJsonLd() preserves compact multi-node arrays with portable IRIs", async () => {
|
|
885
|
-
const activityJson = [
|
|
886
|
-
{
|
|
887
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
888
|
-
type: "Create",
|
|
889
|
-
id: "https://example.com/activities/1",
|
|
890
|
-
actor: "https://example.com/actors/alice",
|
|
891
|
-
object: "https://example.com/objects/1",
|
|
892
|
-
},
|
|
893
|
-
{
|
|
894
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
895
|
-
type: "Note",
|
|
896
|
-
id: "https://example.com/objects/1",
|
|
897
|
-
attributedTo: "ap://did:key:z6Mkabc/actor",
|
|
898
|
-
},
|
|
899
|
-
];
|
|
900
|
-
|
|
901
|
-
const activity = await Activity.fromJsonLd(activityJson, {
|
|
902
|
-
documentLoader: mockDocumentLoader,
|
|
903
|
-
contextLoader: mockDocumentLoader,
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
deepStrictEqual(await activity.toJsonLd(), [
|
|
907
|
-
{
|
|
908
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
909
|
-
type: "Create",
|
|
910
|
-
id: "https://example.com/activities/1",
|
|
911
|
-
actor: "https://example.com/actors/alice",
|
|
912
|
-
object: "https://example.com/objects/1",
|
|
913
|
-
},
|
|
914
|
-
{
|
|
915
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
916
|
-
type: "Note",
|
|
917
|
-
id: "https://example.com/objects/1",
|
|
918
|
-
attributedTo: "ap+ef61://did:key:z6Mkabc/actor",
|
|
919
|
-
},
|
|
920
|
-
]);
|
|
921
|
-
});
|
|
922
|
-
|
|
923
|
-
test("fromJsonLd() preserves nested unmapped terms with portable IRIs", async () => {
|
|
924
|
-
const noteJson = {
|
|
925
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
926
|
-
type: "Note",
|
|
927
|
-
id: "ap://did:key:z6Mkabc/objects/1",
|
|
928
|
-
attachment: {
|
|
929
|
-
type: "Object",
|
|
930
|
-
name: "Attachment with an unmapped extension.",
|
|
931
|
-
extra: "This nested unmapped property should stay cached.",
|
|
932
|
-
},
|
|
933
|
-
};
|
|
934
|
-
|
|
935
|
-
const note = await Note.fromJsonLd(noteJson, {
|
|
936
|
-
documentLoader: mockDocumentLoader,
|
|
937
|
-
contextLoader: mockDocumentLoader,
|
|
938
|
-
});
|
|
939
|
-
|
|
940
|
-
deepStrictEqual(await note.toJsonLd(), {
|
|
941
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
942
|
-
type: "Note",
|
|
943
|
-
id: "ap+ef61://did:key:z6Mkabc/objects/1",
|
|
944
|
-
attachment: {
|
|
945
|
-
type: "Object",
|
|
946
|
-
name: "Attachment with an unmapped extension.",
|
|
947
|
-
extra: "This nested unmapped property should stay cached.",
|
|
948
|
-
},
|
|
949
|
-
});
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
test("fromJsonLd() preserves compact array item extension contexts with portable IRIs", async () => {
|
|
953
|
-
const activityJson = [
|
|
954
|
-
{
|
|
955
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
956
|
-
type: "Create",
|
|
957
|
-
id: "https://example.com/activities/1",
|
|
958
|
-
actor: "https://example.com/actors/alice",
|
|
959
|
-
object: "https://example.com/objects/1",
|
|
960
|
-
},
|
|
961
|
-
{
|
|
962
|
-
"@context": [
|
|
963
|
-
"https://www.w3.org/ns/activitystreams",
|
|
964
|
-
{
|
|
965
|
-
extraRef: {
|
|
966
|
-
"@id": "https://example.com/ns#extraRef",
|
|
967
|
-
"@type": "@id",
|
|
968
|
-
},
|
|
969
|
-
},
|
|
970
|
-
],
|
|
971
|
-
type: "Note",
|
|
972
|
-
id: "https://example.com/objects/1",
|
|
973
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
974
|
-
},
|
|
975
|
-
];
|
|
976
|
-
|
|
977
|
-
const activity = await Activity.fromJsonLd(activityJson, {
|
|
978
|
-
documentLoader: mockDocumentLoader,
|
|
979
|
-
contextLoader: mockDocumentLoader,
|
|
980
|
-
});
|
|
981
|
-
|
|
982
|
-
deepStrictEqual(await activity.toJsonLd(), [
|
|
983
|
-
{
|
|
984
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
985
|
-
type: "Create",
|
|
986
|
-
id: "https://example.com/activities/1",
|
|
987
|
-
actor: "https://example.com/actors/alice",
|
|
988
|
-
object: "https://example.com/objects/1",
|
|
989
|
-
},
|
|
990
|
-
{
|
|
991
|
-
"@context": [
|
|
992
|
-
"https://www.w3.org/ns/activitystreams",
|
|
993
|
-
{
|
|
994
|
-
extraRef: {
|
|
995
|
-
"@id": "https://example.com/ns#extraRef",
|
|
996
|
-
"@type": "@id",
|
|
997
|
-
},
|
|
998
|
-
},
|
|
999
|
-
],
|
|
1000
|
-
type: "Note",
|
|
1001
|
-
id: "https://example.com/objects/1",
|
|
1002
|
-
extraRef: "ap+ef61://did:key:z6Mkabc/extra",
|
|
1003
|
-
},
|
|
1004
|
-
]);
|
|
1005
|
-
});
|
|
1006
|
-
|
|
1007
|
-
test("fromJsonLd() formats portable IRIs in JSON-LD containers", async () => {
|
|
1008
|
-
const note = await Note.fromJsonLd({
|
|
1009
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1010
|
-
type: "Note",
|
|
1011
|
-
id: "https://example.com/notes/1",
|
|
1012
|
-
attributedTo: {
|
|
1013
|
-
"@list": ["ap://did:key:z6Mkabc/actor"],
|
|
1014
|
-
},
|
|
1015
|
-
to: {
|
|
1016
|
-
"@set": ["ap://did:key:z6Mkabc/followers"],
|
|
1017
|
-
},
|
|
1018
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
1019
|
-
|
|
1020
|
-
const jsonLd = await note.toJsonLd() as Record<string, unknown>;
|
|
1021
|
-
deepStrictEqual(jsonLd.attributedTo, {
|
|
1022
|
-
"@list": ["ap+ef61://did:key:z6Mkabc/actor"],
|
|
1023
|
-
});
|
|
1024
|
-
deepStrictEqual(jsonLd.to, "ap+ef61://did:key:z6Mkabc/followers");
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
|
-
test("fromJsonLd() formats portable IRIs hidden behind JSON-LD aliases", async () => {
|
|
1028
|
-
const activity = await Activity.fromJsonLd({
|
|
1029
|
-
"@context": [
|
|
1030
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1031
|
-
{
|
|
1032
|
-
as: {
|
|
1033
|
-
"@id": "https://www.w3.org/ns/activitystreams#",
|
|
1034
|
-
"@prefix": true,
|
|
1035
|
-
},
|
|
1036
|
-
extra: "https://example.com/ns#extra",
|
|
1037
|
-
extraRef: {
|
|
1038
|
-
"@id": "https://example.com/ns#extraRef",
|
|
1039
|
-
"@type": "@id",
|
|
1040
|
-
},
|
|
1041
|
-
actorRef: {
|
|
1042
|
-
"@id": "as:actor",
|
|
1043
|
-
"@type": "@id",
|
|
1044
|
-
},
|
|
1045
|
-
targetRef: {
|
|
1046
|
-
"@id": "as:target",
|
|
1047
|
-
"@type": "@id",
|
|
1048
|
-
},
|
|
1049
|
-
},
|
|
1050
|
-
],
|
|
1051
|
-
type: "Create",
|
|
1052
|
-
actorRef: "ap://did:key:z6Mkabc/actor",
|
|
1053
|
-
object: "https://example.com/objects/1",
|
|
1054
|
-
targetRef: "ap://did:key:z6Mkabc/target",
|
|
1055
|
-
extra: "This extension property should stay cached.",
|
|
1056
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
1057
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
1058
|
-
|
|
1059
|
-
deepStrictEqual(
|
|
1060
|
-
activity.actorId,
|
|
1061
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"),
|
|
1062
|
-
);
|
|
1063
|
-
deepStrictEqual(
|
|
1064
|
-
activity.targetId,
|
|
1065
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/target"),
|
|
1066
|
-
);
|
|
1067
|
-
const jsonLd = await activity.toJsonLd({
|
|
1068
|
-
contextLoader: mockDocumentLoader,
|
|
1069
|
-
}) as Record<string, unknown>;
|
|
1070
|
-
deepStrictEqual(jsonLd.actor, "ap+ef61://did:key:z6Mkabc/actor");
|
|
1071
|
-
deepStrictEqual("actorRef" in jsonLd, false);
|
|
1072
|
-
deepStrictEqual(jsonLd.target, "ap+ef61://did:key:z6Mkabc/target");
|
|
1073
|
-
deepStrictEqual("targetRef" in jsonLd, false);
|
|
1074
|
-
deepStrictEqual(jsonLd.extra, "This extension property should stay cached.");
|
|
1075
|
-
deepStrictEqual(jsonLd.extraRef, "ap+ef61://did:key:z6Mkabc/extra");
|
|
1076
|
-
});
|
|
1077
|
-
|
|
1078
|
-
test("fromJsonLd() preserves portable IRIs in @id extension terms", async () => {
|
|
1079
|
-
const note = await Note.fromJsonLd({
|
|
1080
|
-
"@context": [
|
|
1081
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1082
|
-
{
|
|
1083
|
-
extraRef: {
|
|
1084
|
-
"@id": "https://example.com/ns#extraRef",
|
|
1085
|
-
"@type": "@id",
|
|
1086
|
-
},
|
|
1087
|
-
},
|
|
1088
|
-
],
|
|
1089
|
-
type: "Note",
|
|
1090
|
-
id: "https://example.com/notes/1",
|
|
1091
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
1092
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
1093
|
-
|
|
1094
|
-
const jsonLd = await note.toJsonLd({
|
|
1095
|
-
contextLoader: mockDocumentLoader,
|
|
1096
|
-
}) as Record<string, unknown>;
|
|
1097
|
-
deepStrictEqual(jsonLd.extraRef, "ap+ef61://did:key:z6Mkabc/extra");
|
|
1098
|
-
});
|
|
1099
|
-
|
|
1100
|
-
test("fromJsonLd() ignores malformed portable IRIs in extension cache terms", async () => {
|
|
1101
|
-
const noteJson = {
|
|
1102
|
-
"@context": [
|
|
1103
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1104
|
-
{
|
|
1105
|
-
extraRef: {
|
|
1106
|
-
"@id": "https://example.com/ns#extraRef",
|
|
1107
|
-
"@type": "@id",
|
|
1108
|
-
},
|
|
1109
|
-
},
|
|
1110
|
-
],
|
|
1111
|
-
type: "Note",
|
|
1112
|
-
id: "https://example.com/notes/1",
|
|
1113
|
-
extraRef: "ap://example.com/not-portable",
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
|
-
const note = await Note.fromJsonLd(noteJson, {
|
|
1117
|
-
documentLoader: mockDocumentLoader,
|
|
1118
|
-
contextLoader: mockDocumentLoader,
|
|
1119
|
-
});
|
|
1120
|
-
|
|
1121
|
-
deepStrictEqual(await note.toJsonLd(), noteJson);
|
|
1122
|
-
});
|
|
1123
|
-
|
|
1124
|
-
test("fromJsonLd() preserves portable IRIs in @id typed terms", async () => {
|
|
1125
|
-
const note = await Note.fromJsonLd({
|
|
1126
|
-
"@context": [
|
|
1127
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1128
|
-
{
|
|
1129
|
-
"@vocab": "https://example.com/ns#",
|
|
1130
|
-
extraRef: { "@type": "@id" },
|
|
1131
|
-
},
|
|
1132
|
-
],
|
|
1133
|
-
type: "Note",
|
|
1134
|
-
id: "https://example.com/notes/1",
|
|
1135
|
-
content: "This text mentions ap://did:key:z6Mkabc/text.",
|
|
1136
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
1137
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
1138
|
-
|
|
1139
|
-
const jsonLd = await note.toJsonLd({
|
|
1140
|
-
contextLoader: mockDocumentLoader,
|
|
1141
|
-
}) as Record<string, unknown>;
|
|
1142
|
-
deepStrictEqual(
|
|
1143
|
-
jsonLd.content,
|
|
1144
|
-
"This text mentions ap://did:key:z6Mkabc/text.",
|
|
1145
|
-
);
|
|
1146
|
-
deepStrictEqual(jsonLd.extraRef, "ap+ef61://did:key:z6Mkabc/extra");
|
|
1147
|
-
});
|
|
1148
|
-
|
|
1149
|
-
test("fromJsonLd() preserves portable IRIs hidden behind remote contexts", async () => {
|
|
1150
|
-
const contextUrl = "https://example.com/contexts/portable-iris";
|
|
1151
|
-
const contextLoader: DocumentLoader = async (
|
|
1152
|
-
resource: string,
|
|
1153
|
-
options,
|
|
1154
|
-
): Promise<RemoteDocument> => {
|
|
1155
|
-
if (resource === contextUrl) {
|
|
1156
|
-
return {
|
|
1157
|
-
contextUrl: null,
|
|
1158
|
-
documentUrl: resource,
|
|
1159
|
-
document: {
|
|
1160
|
-
"@context": [
|
|
1161
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1162
|
-
{
|
|
1163
|
-
"@vocab": "https://example.com/ns#",
|
|
1164
|
-
extra: "https://example.com/ns#extra",
|
|
1165
|
-
extraRef: { "@type": "@id" },
|
|
1166
|
-
},
|
|
1167
|
-
],
|
|
1168
|
-
},
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
return await mockDocumentLoader(resource, options);
|
|
1172
|
-
};
|
|
1173
|
-
const note = await Note.fromJsonLd({
|
|
1174
|
-
"@context": contextUrl,
|
|
1175
|
-
type: "Note",
|
|
1176
|
-
id: "https://example.com/notes/1",
|
|
1177
|
-
content: "This text mentions ap://did:key:z6Mkabc/text.",
|
|
1178
|
-
extra: "This extension property should stay cached.",
|
|
1179
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
1180
|
-
}, { documentLoader: mockDocumentLoader, contextLoader });
|
|
1181
|
-
|
|
1182
|
-
const jsonLd = await note.toJsonLd({ contextLoader }) as Record<
|
|
1183
|
-
string,
|
|
1184
|
-
unknown
|
|
1185
|
-
>;
|
|
1186
|
-
deepStrictEqual(
|
|
1187
|
-
jsonLd.content,
|
|
1188
|
-
"This text mentions ap://did:key:z6Mkabc/text.",
|
|
1189
|
-
);
|
|
1190
|
-
deepStrictEqual(jsonLd.extra, "This extension property should stay cached.");
|
|
1191
|
-
deepStrictEqual(jsonLd.extraRef, "ap+ef61://did:key:z6Mkabc/extra");
|
|
1192
|
-
});
|
|
1193
|
-
|
|
1194
|
-
test("fromJsonLd() formats portable IRIs hidden behind nested remote contexts", async () => {
|
|
1195
|
-
const rootContextUrl = "https://example.com/contexts/nested-portable-iris";
|
|
1196
|
-
const nestedContextUrl = "https://example.com/contexts/nested-portable-ref";
|
|
1197
|
-
const contextLoader: DocumentLoader = async (
|
|
1198
|
-
resource: string,
|
|
1199
|
-
options,
|
|
1200
|
-
): Promise<RemoteDocument> => {
|
|
1201
|
-
if (resource === rootContextUrl) {
|
|
1202
|
-
return {
|
|
1203
|
-
contextUrl: null,
|
|
1204
|
-
documentUrl: resource,
|
|
1205
|
-
document: {
|
|
1206
|
-
"@context": [
|
|
1207
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1208
|
-
{
|
|
1209
|
-
"@vocab": "https://example.com/ns#",
|
|
1210
|
-
extraContainer: "https://example.com/ns#extraContainer",
|
|
1211
|
-
},
|
|
1212
|
-
],
|
|
1213
|
-
},
|
|
1214
|
-
};
|
|
1215
|
-
}
|
|
1216
|
-
if (resource === nestedContextUrl) {
|
|
1217
|
-
return {
|
|
1218
|
-
contextUrl: null,
|
|
1219
|
-
documentUrl: resource,
|
|
1220
|
-
document: {
|
|
1221
|
-
"@context": {
|
|
1222
|
-
"@vocab": "https://example.com/ns#",
|
|
1223
|
-
extra: "https://example.com/ns#extra",
|
|
1224
|
-
extraRef: { "@type": "@id" },
|
|
1225
|
-
},
|
|
1226
|
-
},
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
return await mockDocumentLoader(resource, options);
|
|
1230
|
-
};
|
|
1231
|
-
const note = await Note.fromJsonLd({
|
|
1232
|
-
"@context": rootContextUrl,
|
|
1233
|
-
type: "Note",
|
|
1234
|
-
id: "https://example.com/notes/1",
|
|
1235
|
-
extraContainer: {
|
|
1236
|
-
"@context": nestedContextUrl,
|
|
1237
|
-
content: "This text mentions ap://did:key:z6Mkabc/text.",
|
|
1238
|
-
extra: "This nested extension object should stay cached.",
|
|
1239
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
1240
|
-
},
|
|
1241
|
-
}, { documentLoader: mockDocumentLoader, contextLoader });
|
|
1242
|
-
|
|
1243
|
-
const jsonLd = await note.toJsonLd({ contextLoader }) as Record<
|
|
1244
|
-
string,
|
|
1245
|
-
unknown
|
|
1246
|
-
>;
|
|
1247
|
-
deepStrictEqual(jsonLd.extraContainer, {
|
|
1248
|
-
"@context": nestedContextUrl,
|
|
1249
|
-
content: "This text mentions ap://did:key:z6Mkabc/text.",
|
|
1250
|
-
extra: "This nested extension object should stay cached.",
|
|
1251
|
-
extraRef: { id: "ap+ef61://did:key:z6Mkabc/extra" },
|
|
1252
|
-
});
|
|
1253
|
-
});
|
|
1254
|
-
|
|
1255
|
-
test("fromJsonLd() formats portable IRIs in sibling remote-context objects", async () => {
|
|
1256
|
-
const rootContextUrl = "https://example.com/contexts/sibling-containers";
|
|
1257
|
-
const nestedContextUrl = "https://example.com/contexts/sibling-extra-ref";
|
|
1258
|
-
const contextLoader: DocumentLoader = async (
|
|
1259
|
-
resource: string,
|
|
1260
|
-
options,
|
|
1261
|
-
): Promise<RemoteDocument> => {
|
|
1262
|
-
if (resource === rootContextUrl) {
|
|
1263
|
-
return {
|
|
1264
|
-
contextUrl: null,
|
|
1265
|
-
documentUrl: resource,
|
|
1266
|
-
document: {
|
|
1267
|
-
"@context": [
|
|
1268
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1269
|
-
{
|
|
1270
|
-
"@vocab": "https://example.com/ns#",
|
|
1271
|
-
firstExtraContainer: "https://example.com/ns#firstExtraContainer",
|
|
1272
|
-
secondExtraContainer:
|
|
1273
|
-
"https://example.com/ns#secondExtraContainer",
|
|
1274
|
-
},
|
|
1275
|
-
],
|
|
1276
|
-
},
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
|
-
if (resource === nestedContextUrl) {
|
|
1280
|
-
return {
|
|
1281
|
-
contextUrl: null,
|
|
1282
|
-
documentUrl: resource,
|
|
1283
|
-
document: {
|
|
1284
|
-
"@context": {
|
|
1285
|
-
"@vocab": "https://example.com/ns#",
|
|
1286
|
-
extraRef: { "@type": "@id" },
|
|
1287
|
-
},
|
|
1288
|
-
},
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
return await mockDocumentLoader(resource, options);
|
|
1292
|
-
};
|
|
1293
|
-
const note = await Note.fromJsonLd({
|
|
1294
|
-
"@context": rootContextUrl,
|
|
1295
|
-
type: "Note",
|
|
1296
|
-
id: "https://example.com/notes/1",
|
|
1297
|
-
firstExtraContainer: {
|
|
1298
|
-
"@context": nestedContextUrl,
|
|
1299
|
-
content: "No portable IRI here.",
|
|
1300
|
-
},
|
|
1301
|
-
secondExtraContainer: {
|
|
1302
|
-
"@context": nestedContextUrl,
|
|
1303
|
-
extraRef: "ap://did:key:z6Mkabc/second",
|
|
1304
|
-
},
|
|
1305
|
-
}, { documentLoader: mockDocumentLoader, contextLoader });
|
|
1306
|
-
|
|
1307
|
-
const jsonLd = await note.toJsonLd({ contextLoader }) as Record<
|
|
1308
|
-
string,
|
|
1309
|
-
unknown
|
|
1310
|
-
>;
|
|
1311
|
-
deepStrictEqual(jsonLd.firstExtraContainer, {
|
|
1312
|
-
"@context": nestedContextUrl,
|
|
1313
|
-
content: "No portable IRI here.",
|
|
1314
|
-
});
|
|
1315
|
-
deepStrictEqual(jsonLd.secondExtraContainer, {
|
|
1316
|
-
"@context": nestedContextUrl,
|
|
1317
|
-
extraRef: { id: "ap+ef61://did:key:z6Mkabc/second" },
|
|
1318
|
-
});
|
|
1319
|
-
});
|
|
1320
|
-
|
|
1321
|
-
test("fromJsonLd() batches unmapped portable IRI term checks", async () => {
|
|
1322
|
-
const contextUrl = "https://example.com/contexts/batched-portable-aliases";
|
|
1323
|
-
let contextLoads = 0;
|
|
1324
|
-
const contextLoader: DocumentLoader = async (
|
|
1325
|
-
resource: string,
|
|
1326
|
-
options,
|
|
1327
|
-
): Promise<RemoteDocument> => {
|
|
1328
|
-
if (resource === contextUrl) {
|
|
1329
|
-
contextLoads++;
|
|
1330
|
-
return {
|
|
1331
|
-
contextUrl: null,
|
|
1332
|
-
documentUrl: resource,
|
|
1333
|
-
document: {
|
|
1334
|
-
"@context": [
|
|
1335
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1336
|
-
{
|
|
1337
|
-
as: {
|
|
1338
|
-
"@id": "https://www.w3.org/ns/activitystreams#",
|
|
1339
|
-
"@prefix": true,
|
|
1340
|
-
},
|
|
1341
|
-
actorRef0: { "@id": "as:actor", "@type": "@id" },
|
|
1342
|
-
actorRef1: { "@id": "as:actor", "@type": "@id" },
|
|
1343
|
-
targetRef0: { "@id": "as:target", "@type": "@id" },
|
|
1344
|
-
targetRef1: { "@id": "as:target", "@type": "@id" },
|
|
1345
|
-
objectRef0: { "@id": "as:object", "@type": "@id" },
|
|
1346
|
-
objectRef1: { "@id": "as:object", "@type": "@id" },
|
|
1347
|
-
},
|
|
1348
|
-
],
|
|
1349
|
-
},
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
return await mockDocumentLoader(resource, options);
|
|
1353
|
-
};
|
|
1354
|
-
|
|
1355
|
-
const activity = await Activity.fromJsonLd({
|
|
1356
|
-
"@context": contextUrl,
|
|
1357
|
-
type: "Create",
|
|
1358
|
-
actorRef0: "ap://did:key:z6Mkabc/actor0",
|
|
1359
|
-
actorRef1: "ap://did:key:z6Mkabc/actor1",
|
|
1360
|
-
targetRef0: "ap://did:key:z6Mkabc/target0",
|
|
1361
|
-
targetRef1: "ap://did:key:z6Mkabc/target1",
|
|
1362
|
-
objectRef0: "https://example.com/objects/0",
|
|
1363
|
-
objectRef1: "https://example.com/objects/1",
|
|
1364
|
-
}, { documentLoader: mockDocumentLoader, contextLoader });
|
|
1365
|
-
|
|
1366
|
-
await activity.toJsonLd({ contextLoader });
|
|
1367
|
-
|
|
1368
|
-
ok(contextLoads <= 5);
|
|
1369
|
-
});
|
|
1370
|
-
|
|
1371
|
-
test("fromJsonLd() falls back when portable IRI cache merge fails", async () => {
|
|
1372
|
-
const contextUrl = "https://example.com/contexts/failing-cache-merge";
|
|
1373
|
-
let contextLoads = 0;
|
|
1374
|
-
const contextLoader: DocumentLoader = async (
|
|
1375
|
-
resource: string,
|
|
1376
|
-
options,
|
|
1377
|
-
): Promise<RemoteDocument> => {
|
|
1378
|
-
if (resource === contextUrl) {
|
|
1379
|
-
contextLoads++;
|
|
1380
|
-
if (contextLoads > 1) throw new Error("merge context unavailable");
|
|
1381
|
-
return {
|
|
1382
|
-
contextUrl: null,
|
|
1383
|
-
documentUrl: resource,
|
|
1384
|
-
document: {
|
|
1385
|
-
"@context": [
|
|
1386
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1387
|
-
{
|
|
1388
|
-
"@vocab": "https://example.com/ns#",
|
|
1389
|
-
extraRef: { "@type": "@id" },
|
|
1390
|
-
},
|
|
1391
|
-
],
|
|
1392
|
-
},
|
|
1393
|
-
};
|
|
1394
|
-
}
|
|
1395
|
-
return await mockDocumentLoader(resource, options);
|
|
1396
|
-
};
|
|
1397
|
-
|
|
1398
|
-
const note = await Note.fromJsonLd({
|
|
1399
|
-
"@context": contextUrl,
|
|
1400
|
-
type: "Note",
|
|
1401
|
-
id: "ap://did:key:z6Mkabc/objects/1",
|
|
1402
|
-
extraRef: "ap://did:key:z6Mkabc/extra",
|
|
1403
|
-
}, { documentLoader: mockDocumentLoader, contextLoader });
|
|
1404
|
-
|
|
1405
|
-
const jsonLd = await note.toJsonLd({
|
|
1406
|
-
contextLoader: mockDocumentLoader,
|
|
1407
|
-
}) as Record<string, unknown>;
|
|
1408
|
-
|
|
1409
|
-
deepStrictEqual(jsonLd.type, "Note");
|
|
1410
|
-
deepStrictEqual(jsonLd.id, "ap+ef61://did:key:z6Mkabc/objects/1");
|
|
1411
|
-
});
|
|
1412
|
-
|
|
1413
|
-
test("fromJsonLd() formats portable IRIs in scalar URL values", async () => {
|
|
1414
|
-
const note = await Note.fromJsonLd({
|
|
1415
|
-
"@context": [
|
|
1416
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1417
|
-
"https://gotosocial.org/ns",
|
|
1418
|
-
{ quoteUrl: "as:quoteUrl" },
|
|
1419
|
-
],
|
|
1420
|
-
type: "Note",
|
|
1421
|
-
id: "https://example.com/notes/1",
|
|
1422
|
-
quoteUrl: "ap://did:key:z6Mkabc/objects/1",
|
|
1423
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
1424
|
-
|
|
1425
|
-
deepStrictEqual(
|
|
1426
|
-
note.quoteUrl,
|
|
1427
|
-
new URL("ap+ef61://did%3Akey%3Az6Mkabc/objects/1"),
|
|
1428
|
-
);
|
|
1429
|
-
const jsonLd = await note.toJsonLd({
|
|
1430
|
-
contextLoader: mockDocumentLoader,
|
|
1431
|
-
}) as Record<string, unknown>;
|
|
1432
|
-
deepStrictEqual(jsonLd.quoteUrl, "ap+ef61://did:key:z6Mkabc/objects/1");
|
|
1433
|
-
});
|
|
1434
|
-
|
|
1435
|
-
test("fromJsonLd() formats portable IRIs in URL value lists", async () => {
|
|
1436
|
-
const note = await Note.fromJsonLd({
|
|
1437
|
-
"@context": [
|
|
1438
|
-
"https://www.w3.org/ns/activitystreams",
|
|
1439
|
-
"https://gotosocial.org/ns",
|
|
1440
|
-
{ quoteUrl: "as:quoteUrl" },
|
|
1441
|
-
],
|
|
1442
|
-
type: "Note",
|
|
1443
|
-
id: "https://example.com/notes/1",
|
|
1444
|
-
quoteUrl: {
|
|
1445
|
-
"@list": [
|
|
1446
|
-
{ "@value": "ap://did:key:z6Mkabc/objects/1" },
|
|
1447
|
-
],
|
|
1448
|
-
},
|
|
1449
|
-
}, { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader });
|
|
1450
|
-
|
|
472
|
+
"z3sXaxjKs4M3BRicwWA9peyNPJvJqxtGsDmpt1jjoHCjgeUf71TRFz56osPSfDErszyLp5Ks1EhYSgpDaNM977Rg2",
|
|
473
|
+
// cSpell: enable
|
|
474
|
+
),
|
|
475
|
+
);
|
|
1451
476
|
deepStrictEqual(
|
|
1452
|
-
|
|
1453
|
-
|
|
477
|
+
proofs[0].created,
|
|
478
|
+
Temporal.Instant.from("2023-02-24T23:36:38Z"),
|
|
1454
479
|
);
|
|
1455
|
-
const jsonLd = await note.toJsonLd({
|
|
1456
|
-
contextLoader: mockDocumentLoader,
|
|
1457
|
-
}) as Record<string, unknown>;
|
|
1458
|
-
deepStrictEqual(jsonLd.quoteUrl, {
|
|
1459
|
-
"@list": [
|
|
1460
|
-
"ap+ef61://did:key:z6Mkabc/objects/1",
|
|
1461
|
-
],
|
|
1462
|
-
});
|
|
1463
480
|
});
|
|
1464
481
|
|
|
1465
482
|
test({
|
|
@@ -1527,37 +544,6 @@ test({
|
|
|
1527
544
|
},
|
|
1528
545
|
});
|
|
1529
546
|
|
|
1530
|
-
test("Activity.getObject() fetches canonical portable IRIs", async () => {
|
|
1531
|
-
const fetchedUrls: string[] = [];
|
|
1532
|
-
// deno-lint-ignore require-await
|
|
1533
|
-
const documentLoader: DocumentLoader = async (url) => {
|
|
1534
|
-
fetchedUrls.push(url);
|
|
1535
|
-
return {
|
|
1536
|
-
contextUrl: null,
|
|
1537
|
-
documentUrl: url,
|
|
1538
|
-
document: {
|
|
1539
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1540
|
-
id: url,
|
|
1541
|
-
type: "Note",
|
|
1542
|
-
content: "Fetched portable object",
|
|
1543
|
-
},
|
|
1544
|
-
};
|
|
1545
|
-
};
|
|
1546
|
-
const activity = await Activity.fromJsonLd({
|
|
1547
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1548
|
-
type: "Create",
|
|
1549
|
-
object: "ap://did:key:z6Mkabc/objects/1",
|
|
1550
|
-
}, { documentLoader, contextLoader: mockDocumentLoader });
|
|
1551
|
-
|
|
1552
|
-
const object = await activity.getObject({
|
|
1553
|
-
documentLoader,
|
|
1554
|
-
contextLoader: mockDocumentLoader,
|
|
1555
|
-
});
|
|
1556
|
-
|
|
1557
|
-
assertInstanceOf(object, Note);
|
|
1558
|
-
deepStrictEqual(fetchedUrls, ["ap+ef61://did:key:z6Mkabc/objects/1"]);
|
|
1559
|
-
});
|
|
1560
|
-
|
|
1561
547
|
test({
|
|
1562
548
|
name: "Activity.getObjects()",
|
|
1563
549
|
permissions: { env: true, read: true },
|
|
@@ -1755,7 +741,6 @@ test("Person.toJsonLd()", async () => {
|
|
|
1755
741
|
"https://www.w3.org/ns/did/v1",
|
|
1756
742
|
"https://w3id.org/security/multikey/v1",
|
|
1757
743
|
"https://gotosocial.org/ns",
|
|
1758
|
-
"https://w3id.org/fep/7aa9",
|
|
1759
744
|
{
|
|
1760
745
|
PropertyValue: "schema:PropertyValue",
|
|
1761
746
|
alsoKnownAs: {
|
|
@@ -1771,10 +756,6 @@ test("Person.toJsonLd()", async () => {
|
|
|
1771
756
|
"@id": "toot:featured",
|
|
1772
757
|
"@type": "@id",
|
|
1773
758
|
},
|
|
1774
|
-
featuredCollections: {
|
|
1775
|
-
"@id": "https://w3id.org/fep/7aa9#featuredCollections",
|
|
1776
|
-
"@type": "@id",
|
|
1777
|
-
},
|
|
1778
759
|
featuredTags: {
|
|
1779
760
|
"@id": "toot:featuredTags",
|
|
1780
761
|
"@type": "@id",
|
|
@@ -2315,426 +1296,166 @@ test("Collection.fromJsonLd()", async () => {
|
|
|
2315
1296
|
"type": "Collection",
|
|
2316
1297
|
"id": "https://example.com/collection/jzc50wc28l",
|
|
2317
1298
|
"inboxOf": "https://example.com/person/bup9a8eqm",
|
|
2318
|
-
});
|
|
2319
|
-
deepStrictEqual(
|
|
2320
|
-
collection.id,
|
|
2321
|
-
new URL("https://example.com/collection/jzc50wc28l"),
|
|
2322
|
-
);
|
|
2323
|
-
deepStrictEqual(
|
|
2324
|
-
collection.inboxOfId,
|
|
2325
|
-
new URL("https://example.com/person/bup9a8eqm"),
|
|
2326
|
-
);
|
|
2327
|
-
});
|
|
2328
|
-
|
|
2329
|
-
test("Note.quoteUrl", async () => {
|
|
2330
|
-
const note = new Note({
|
|
2331
|
-
quoteUrl: new URL("https://example.com/object"),
|
|
2332
|
-
});
|
|
2333
|
-
const expected = {
|
|
2334
|
-
"@context": NOTE_QUOTE_CONTEXT,
|
|
2335
|
-
_misskey_quote: "https://example.com/object",
|
|
2336
|
-
quoteUri: "https://example.com/object",
|
|
2337
|
-
quoteUrl: "https://example.com/object",
|
|
2338
|
-
type: "Note",
|
|
2339
|
-
};
|
|
2340
|
-
deepStrictEqual(await note.toJsonLd(), expected);
|
|
2341
|
-
deepStrictEqual(await note.toJsonLd({ format: "compact" }), expected);
|
|
2342
|
-
|
|
2343
|
-
const jsonLd: Record<string, unknown> = {
|
|
2344
|
-
"@context": [
|
|
2345
|
-
"https://www.w3.org/ns/activitystreams",
|
|
2346
|
-
{
|
|
2347
|
-
_misskey_quote: "misskey:_misskey_quote",
|
|
2348
|
-
fedibird: "http://fedibird.com/ns#",
|
|
2349
|
-
misskey: "https://misskey-hub.net/ns#",
|
|
2350
|
-
quoteUri: "fedibird:quoteUri",
|
|
2351
|
-
quoteUrl: "as:quoteUrl",
|
|
2352
|
-
},
|
|
2353
|
-
],
|
|
2354
|
-
type: "Note",
|
|
2355
|
-
quoteUrl: "https://example.com/object",
|
|
2356
|
-
_misskey_quote: "https://example.com/object2",
|
|
2357
|
-
quoteUri: "https://example.com/object3",
|
|
2358
|
-
};
|
|
2359
|
-
const loaded = await Note.fromJsonLd(jsonLd);
|
|
2360
|
-
deepStrictEqual(loaded.quoteUrl, new URL("https://example.com/object"));
|
|
2361
|
-
|
|
2362
|
-
delete jsonLd.quoteUrl;
|
|
2363
|
-
const loaded2 = await Note.fromJsonLd(jsonLd);
|
|
2364
|
-
deepStrictEqual(loaded2.quoteUrl, new URL("https://example.com/object2"));
|
|
2365
|
-
|
|
2366
|
-
delete jsonLd._misskey_quote;
|
|
2367
|
-
const loaded3 = await Note.fromJsonLd(jsonLd);
|
|
2368
|
-
deepStrictEqual(loaded3.quoteUrl, new URL("https://example.com/object3"));
|
|
2369
|
-
});
|
|
2370
|
-
|
|
2371
|
-
test("Note.quote", async () => {
|
|
2372
|
-
const note = new Note({
|
|
2373
|
-
quote: new URL("https://example.com/object"),
|
|
2374
|
-
});
|
|
2375
|
-
const expected = {
|
|
2376
|
-
"@context": NOTE_QUOTE_CONTEXT,
|
|
2377
|
-
quote: "https://example.com/object",
|
|
2378
|
-
type: "Note",
|
|
2379
|
-
};
|
|
2380
|
-
deepStrictEqual(await note.toJsonLd(), expected);
|
|
2381
|
-
deepStrictEqual(await note.toJsonLd({ format: "compact" }), expected);
|
|
2382
|
-
|
|
2383
|
-
const loaded = await Note.fromJsonLd({
|
|
2384
|
-
"@context": [
|
|
2385
|
-
"https://www.w3.org/ns/activitystreams",
|
|
2386
|
-
{
|
|
2387
|
-
quote: {
|
|
2388
|
-
"@id": "https://w3id.org/fep/044f#quote",
|
|
2389
|
-
"@type": "@id",
|
|
2390
|
-
},
|
|
2391
|
-
},
|
|
2392
|
-
],
|
|
2393
|
-
type: "Note",
|
|
2394
|
-
quote: "https://example.com/object",
|
|
2395
|
-
});
|
|
2396
|
-
deepStrictEqual(loaded.quoteId, new URL("https://example.com/object"));
|
|
2397
|
-
});
|
|
2398
|
-
|
|
2399
|
-
test("Note.quoteAuthorization", async () => {
|
|
2400
|
-
const note = new Note({
|
|
2401
|
-
quoteAuthorization: new URL("https://example.com/authorizations/1"),
|
|
2402
|
-
});
|
|
2403
|
-
const expected = {
|
|
2404
|
-
"@context": NOTE_QUOTE_CONTEXT,
|
|
2405
|
-
quoteAuthorization: "https://example.com/authorizations/1",
|
|
2406
|
-
type: "Note",
|
|
2407
|
-
};
|
|
2408
|
-
deepStrictEqual(await note.toJsonLd(), expected);
|
|
2409
|
-
deepStrictEqual(await note.toJsonLd({ format: "compact" }), expected);
|
|
2410
|
-
|
|
2411
|
-
const loaded = await Note.fromJsonLd({
|
|
2412
|
-
"@context": [
|
|
2413
|
-
"https://www.w3.org/ns/activitystreams",
|
|
2414
|
-
{
|
|
2415
|
-
QuoteAuthorization: "https://w3id.org/fep/044f#QuoteAuthorization",
|
|
2416
|
-
quoteAuthorization: {
|
|
2417
|
-
"@id": "https://w3id.org/fep/044f#quoteAuthorization",
|
|
2418
|
-
"@type": "@id",
|
|
2419
|
-
},
|
|
2420
|
-
},
|
|
2421
|
-
],
|
|
2422
|
-
type: "Note",
|
|
2423
|
-
quoteAuthorization: "https://example.com/authorizations/1",
|
|
2424
|
-
});
|
|
2425
|
-
deepStrictEqual(
|
|
2426
|
-
loaded.quoteAuthorizationId,
|
|
2427
|
-
new URL("https://example.com/authorizations/1"),
|
|
2428
|
-
);
|
|
2429
|
-
|
|
2430
|
-
const loadedFromGoToSocialContext = await Note.fromJsonLd({
|
|
2431
|
-
"@context": [
|
|
2432
|
-
"https://www.w3.org/ns/activitystreams",
|
|
2433
|
-
"https://gotosocial.org/ns",
|
|
2434
|
-
],
|
|
2435
|
-
type: "Note",
|
|
2436
|
-
quoteAuthorization: "https://example.com/authorizations/2",
|
|
2437
|
-
}, {
|
|
2438
|
-
documentLoader: mockDocumentLoader,
|
|
2439
|
-
contextLoader: mockDocumentLoader,
|
|
2440
|
-
});
|
|
2441
|
-
deepStrictEqual(
|
|
2442
|
-
loadedFromGoToSocialContext.quoteAuthorizationId,
|
|
2443
|
-
new URL("https://example.com/authorizations/2"),
|
|
2444
|
-
);
|
|
2445
|
-
});
|
|
2446
|
-
|
|
2447
|
-
test("InteractionPolicy.canQuote", async () => {
|
|
2448
|
-
const note = new Note({
|
|
2449
|
-
interactionPolicy: new InteractionPolicy({
|
|
2450
|
-
canQuote: new InteractionRule({
|
|
2451
|
-
automaticApproval: new URL(
|
|
2452
|
-
"https://www.w3.org/ns/activitystreams#Public",
|
|
2453
|
-
),
|
|
2454
|
-
}),
|
|
2455
|
-
}),
|
|
2456
|
-
});
|
|
2457
|
-
const expected = {
|
|
2458
|
-
"@context": NOTE_QUOTE_CONTEXT,
|
|
2459
|
-
interactionPolicy: {
|
|
2460
|
-
canQuote: {
|
|
2461
|
-
automaticApproval: "as:Public",
|
|
2462
|
-
},
|
|
2463
|
-
},
|
|
2464
|
-
type: "Note",
|
|
2465
|
-
};
|
|
2466
|
-
deepStrictEqual(
|
|
2467
|
-
await note.toJsonLd({ contextLoader: mockDocumentLoader }),
|
|
2468
|
-
expected,
|
|
2469
|
-
);
|
|
2470
|
-
|
|
2471
|
-
const loaded = await Note.fromJsonLd(expected, {
|
|
2472
|
-
documentLoader: mockDocumentLoader,
|
|
2473
|
-
contextLoader: mockDocumentLoader,
|
|
2474
|
-
});
|
|
2475
|
-
deepStrictEqual(
|
|
2476
|
-
await loaded.toJsonLd({ contextLoader: mockDocumentLoader }),
|
|
2477
|
-
expected,
|
|
2478
|
-
);
|
|
2479
|
-
});
|
|
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);
|
|
1299
|
+
});
|
|
2564
1300
|
deepStrictEqual(
|
|
2565
|
-
|
|
2566
|
-
new URL("https://
|
|
1301
|
+
collection.id,
|
|
1302
|
+
new URL("https://example.com/collection/jzc50wc28l"),
|
|
2567
1303
|
);
|
|
2568
1304
|
deepStrictEqual(
|
|
2569
|
-
|
|
2570
|
-
|
|
1305
|
+
collection.inboxOfId,
|
|
1306
|
+
new URL("https://example.com/person/bup9a8eqm"),
|
|
2571
1307
|
);
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
test("Note.quoteUrl", async () => {
|
|
1311
|
+
const note = new Note({
|
|
1312
|
+
quoteUrl: new URL("https://example.com/object"),
|
|
1313
|
+
});
|
|
1314
|
+
const expected = {
|
|
1315
|
+
"@context": NOTE_QUOTE_CONTEXT,
|
|
1316
|
+
_misskey_quote: "https://example.com/object",
|
|
1317
|
+
quoteUri: "https://example.com/object",
|
|
1318
|
+
quoteUrl: "https://example.com/object",
|
|
1319
|
+
type: "Note",
|
|
1320
|
+
};
|
|
1321
|
+
deepStrictEqual(await note.toJsonLd(), expected);
|
|
1322
|
+
deepStrictEqual(await note.toJsonLd({ format: "compact" }), expected);
|
|
2572
1323
|
|
|
2573
|
-
const
|
|
1324
|
+
const jsonLd: Record<string, unknown> = {
|
|
2574
1325
|
"@context": [
|
|
2575
1326
|
"https://www.w3.org/ns/activitystreams",
|
|
2576
|
-
"https://gotosocial.org/ns",
|
|
2577
|
-
"https://w3id.org/fep/7aa9",
|
|
2578
1327
|
{
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
1328
|
+
_misskey_quote: "misskey:_misskey_quote",
|
|
1329
|
+
fedibird: "http://fedibird.com/ns#",
|
|
1330
|
+
misskey: "https://misskey-hub.net/ns#",
|
|
1331
|
+
quoteUri: "fedibird:quoteUri",
|
|
1332
|
+
quoteUrl: "as:quoteUrl",
|
|
2583
1333
|
},
|
|
2584
1334
|
],
|
|
2585
|
-
type: "
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
);
|
|
1335
|
+
type: "Note",
|
|
1336
|
+
quoteUrl: "https://example.com/object",
|
|
1337
|
+
_misskey_quote: "https://example.com/object2",
|
|
1338
|
+
quoteUri: "https://example.com/object3",
|
|
1339
|
+
};
|
|
1340
|
+
const loaded = await Note.fromJsonLd(jsonLd);
|
|
1341
|
+
deepStrictEqual(loaded.quoteUrl, new URL("https://example.com/object"));
|
|
1342
|
+
|
|
1343
|
+
delete jsonLd.quoteUrl;
|
|
1344
|
+
const loaded2 = await Note.fromJsonLd(jsonLd);
|
|
1345
|
+
deepStrictEqual(loaded2.quoteUrl, new URL("https://example.com/object2"));
|
|
1346
|
+
|
|
1347
|
+
delete jsonLd._misskey_quote;
|
|
1348
|
+
const loaded3 = await Note.fromJsonLd(jsonLd);
|
|
1349
|
+
deepStrictEqual(loaded3.quoteUrl, new URL("https://example.com/object3"));
|
|
2596
1350
|
});
|
|
2597
1351
|
|
|
2598
|
-
test("
|
|
2599
|
-
const
|
|
2600
|
-
|
|
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,
|
|
1352
|
+
test("Note.quote", async () => {
|
|
1353
|
+
const note = new Note({
|
|
1354
|
+
quote: new URL("https://example.com/object"),
|
|
2606
1355
|
});
|
|
2607
1356
|
const expected = {
|
|
2608
|
-
"@context":
|
|
2609
|
-
|
|
2610
|
-
|
|
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,
|
|
1357
|
+
"@context": NOTE_QUOTE_CONTEXT,
|
|
1358
|
+
quote: "https://example.com/object",
|
|
1359
|
+
type: "Note",
|
|
2619
1360
|
};
|
|
2620
|
-
deepStrictEqual(
|
|
2621
|
-
|
|
2622
|
-
expected,
|
|
2623
|
-
);
|
|
1361
|
+
deepStrictEqual(await note.toJsonLd(), expected);
|
|
1362
|
+
deepStrictEqual(await note.toJsonLd({ format: "compact" }), expected);
|
|
2624
1363
|
|
|
2625
|
-
const loaded = await
|
|
2626
|
-
|
|
2627
|
-
|
|
1364
|
+
const loaded = await Note.fromJsonLd({
|
|
1365
|
+
"@context": [
|
|
1366
|
+
"https://www.w3.org/ns/activitystreams",
|
|
1367
|
+
{
|
|
1368
|
+
quote: {
|
|
1369
|
+
"@id": "https://w3id.org/fep/044f#quote",
|
|
1370
|
+
"@type": "@id",
|
|
1371
|
+
},
|
|
1372
|
+
},
|
|
1373
|
+
],
|
|
1374
|
+
type: "Note",
|
|
1375
|
+
quote: "https://example.com/object",
|
|
2628
1376
|
});
|
|
2629
|
-
|
|
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
|
-
);
|
|
1377
|
+
deepStrictEqual(loaded.quoteId, new URL("https://example.com/object"));
|
|
2643
1378
|
});
|
|
2644
1379
|
|
|
2645
|
-
test("
|
|
2646
|
-
const
|
|
2647
|
-
|
|
2648
|
-
featuredObject: new URL("https://example.com/users/bob"),
|
|
2649
|
-
featureAuthorization: new URL("https://example.com/users/bob/stamps/1"),
|
|
1380
|
+
test("Note.quoteAuthorization", async () => {
|
|
1381
|
+
const note = new Note({
|
|
1382
|
+
quoteAuthorization: new URL("https://example.com/authorizations/1"),
|
|
2650
1383
|
});
|
|
2651
1384
|
const expected = {
|
|
2652
|
-
"@context":
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
featuredObject: "https://example.com/users/bob",
|
|
2656
|
-
featureAuthorization: "https://example.com/users/bob/stamps/1",
|
|
1385
|
+
"@context": NOTE_QUOTE_CONTEXT,
|
|
1386
|
+
quoteAuthorization: "https://example.com/authorizations/1",
|
|
1387
|
+
type: "Note",
|
|
2657
1388
|
};
|
|
2658
|
-
deepStrictEqual(
|
|
2659
|
-
|
|
2660
|
-
expected,
|
|
2661
|
-
);
|
|
1389
|
+
deepStrictEqual(await note.toJsonLd(), expected);
|
|
1390
|
+
deepStrictEqual(await note.toJsonLd({ format: "compact" }), expected);
|
|
2662
1391
|
|
|
2663
|
-
const loaded = await
|
|
2664
|
-
|
|
2665
|
-
|
|
1392
|
+
const loaded = await Note.fromJsonLd({
|
|
1393
|
+
"@context": [
|
|
1394
|
+
"https://www.w3.org/ns/activitystreams",
|
|
1395
|
+
{
|
|
1396
|
+
QuoteAuthorization: "https://w3id.org/fep/044f#QuoteAuthorization",
|
|
1397
|
+
quoteAuthorization: {
|
|
1398
|
+
"@id": "https://w3id.org/fep/044f#quoteAuthorization",
|
|
1399
|
+
"@type": "@id",
|
|
1400
|
+
},
|
|
1401
|
+
},
|
|
1402
|
+
],
|
|
1403
|
+
type: "Note",
|
|
1404
|
+
quoteAuthorization: "https://example.com/authorizations/1",
|
|
2666
1405
|
});
|
|
2667
|
-
assertInstanceOf(loaded, FeaturedItem);
|
|
2668
1406
|
deepStrictEqual(
|
|
2669
|
-
loaded.
|
|
2670
|
-
new URL("https://example.com/
|
|
2671
|
-
);
|
|
2672
|
-
deepStrictEqual(
|
|
2673
|
-
loaded.featureAuthorizationId,
|
|
2674
|
-
new URL("https://example.com/users/bob/stamps/1"),
|
|
1407
|
+
loaded.quoteAuthorizationId,
|
|
1408
|
+
new URL("https://example.com/authorizations/1"),
|
|
2675
1409
|
);
|
|
2676
|
-
});
|
|
2677
1410
|
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
}
|
|
2686
|
-
const authorization = await FeatureAuthorization.fromJsonLd(jsonLd, {
|
|
1411
|
+
const loadedFromGoToSocialContext = await Note.fromJsonLd({
|
|
1412
|
+
"@context": [
|
|
1413
|
+
"https://www.w3.org/ns/activitystreams",
|
|
1414
|
+
"https://gotosocial.org/ns",
|
|
1415
|
+
],
|
|
1416
|
+
type: "Note",
|
|
1417
|
+
quoteAuthorization: "https://example.com/authorizations/2",
|
|
1418
|
+
}, {
|
|
2687
1419
|
documentLoader: mockDocumentLoader,
|
|
2688
1420
|
contextLoader: mockDocumentLoader,
|
|
2689
1421
|
});
|
|
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
1422
|
deepStrictEqual(
|
|
2700
|
-
|
|
2701
|
-
|
|
1423
|
+
loadedFromGoToSocialContext.quoteAuthorizationId,
|
|
1424
|
+
new URL("https://example.com/authorizations/2"),
|
|
2702
1425
|
);
|
|
2703
1426
|
});
|
|
2704
1427
|
|
|
2705
|
-
test("
|
|
2706
|
-
const
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
1428
|
+
test("InteractionPolicy.canQuote", async () => {
|
|
1429
|
+
const note = new Note({
|
|
1430
|
+
interactionPolicy: new InteractionPolicy({
|
|
1431
|
+
canQuote: new InteractionRule({
|
|
1432
|
+
automaticApproval: new URL(
|
|
1433
|
+
"https://www.w3.org/ns/activitystreams#Public",
|
|
1434
|
+
),
|
|
1435
|
+
}),
|
|
1436
|
+
}),
|
|
2710
1437
|
});
|
|
2711
1438
|
const expected = {
|
|
2712
|
-
"@context":
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
instrument: "https://example.com/users/alice/featured/1",
|
|
1439
|
+
"@context": NOTE_QUOTE_CONTEXT,
|
|
1440
|
+
interactionPolicy: {
|
|
1441
|
+
canQuote: {
|
|
1442
|
+
automaticApproval: "as:Public",
|
|
1443
|
+
},
|
|
1444
|
+
},
|
|
1445
|
+
type: "Note",
|
|
2720
1446
|
};
|
|
2721
1447
|
deepStrictEqual(
|
|
2722
|
-
await
|
|
1448
|
+
await note.toJsonLd({ contextLoader: mockDocumentLoader }),
|
|
2723
1449
|
expected,
|
|
2724
1450
|
);
|
|
2725
1451
|
|
|
2726
|
-
const loaded = await
|
|
1452
|
+
const loaded = await Note.fromJsonLd(expected, {
|
|
2727
1453
|
documentLoader: mockDocumentLoader,
|
|
2728
1454
|
contextLoader: mockDocumentLoader,
|
|
2729
1455
|
});
|
|
2730
|
-
assertInstanceOf(loaded, FeatureRequest);
|
|
2731
1456
|
deepStrictEqual(
|
|
2732
|
-
loaded.
|
|
2733
|
-
|
|
2734
|
-
);
|
|
2735
|
-
deepStrictEqual(
|
|
2736
|
-
loaded.instrumentId,
|
|
2737
|
-
new URL("https://example.com/users/alice/featured/1"),
|
|
1457
|
+
await loaded.toJsonLd({ contextLoader: mockDocumentLoader }),
|
|
1458
|
+
expected,
|
|
2738
1459
|
);
|
|
2739
1460
|
});
|
|
2740
1461
|
|
|
@@ -3741,31 +2462,6 @@ test("FEP-fe34: crossOrigin trust behavior", async () => {
|
|
|
3741
2462
|
deepStrictEqual(result?.content, "This is a spoofed note");
|
|
3742
2463
|
});
|
|
3743
2464
|
|
|
3744
|
-
test("FEP-fe34: id-less owners honor crossOrigin trust", async () => {
|
|
3745
|
-
const create = await Create.fromJsonLd({
|
|
3746
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3747
|
-
"@type": "Create",
|
|
3748
|
-
"actor": "https://example.com/actor",
|
|
3749
|
-
"object": {
|
|
3750
|
-
"@type": "Note",
|
|
3751
|
-
"@id": "https://different-origin.com/note",
|
|
3752
|
-
"content": "Embedded note",
|
|
3753
|
-
},
|
|
3754
|
-
});
|
|
3755
|
-
|
|
3756
|
-
const result = await create.getObject({
|
|
3757
|
-
crossOrigin: "trust",
|
|
3758
|
-
// deno-lint-ignore require-await
|
|
3759
|
-
documentLoader: async (url) => {
|
|
3760
|
-
throw new Error(`Unexpected fetch: ${url}`);
|
|
3761
|
-
},
|
|
3762
|
-
});
|
|
3763
|
-
|
|
3764
|
-
assertInstanceOf(result, Note);
|
|
3765
|
-
deepStrictEqual(result.id, new URL("https://different-origin.com/note"));
|
|
3766
|
-
deepStrictEqual(result.content, "Embedded note");
|
|
3767
|
-
});
|
|
3768
|
-
|
|
3769
2465
|
test("FEP-fe34: Same origin objects are trusted", async () => {
|
|
3770
2466
|
// deno-lint-ignore require-await
|
|
3771
2467
|
const sameOriginDocumentLoader = async (url: string) => {
|
|
@@ -3913,44 +2609,6 @@ test("FEP-fe34: Constructor vs JSON-LD parsing trust difference", async () => {
|
|
|
3913
2609
|
deepStrictEqual(jsonLdResult?.content, "Fetched from origin");
|
|
3914
2610
|
});
|
|
3915
2611
|
|
|
3916
|
-
test(
|
|
3917
|
-
"FEP-fe34: Portable DID authorities are cross-origin boundaries",
|
|
3918
|
-
async () => {
|
|
3919
|
-
const create = await Create.fromJsonLd({
|
|
3920
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3921
|
-
"@type": "Create",
|
|
3922
|
-
"@id": "ap://did:key:z6MkOwner/create",
|
|
3923
|
-
"actor": "ap://did:key:z6MkOwner/actor",
|
|
3924
|
-
"object": {
|
|
3925
|
-
"@type": "Note",
|
|
3926
|
-
"@id": "ap://did:key:z6MkOther/note",
|
|
3927
|
-
"content": "Embedded portable note",
|
|
3928
|
-
},
|
|
3929
|
-
});
|
|
3930
|
-
|
|
3931
|
-
// deno-lint-ignore require-await
|
|
3932
|
-
const documentLoader = async (url: string) => {
|
|
3933
|
-
if (url === "ap+ef61://did:key:z6MkOther/note") {
|
|
3934
|
-
return {
|
|
3935
|
-
documentUrl: url,
|
|
3936
|
-
contextUrl: null,
|
|
3937
|
-
document: {
|
|
3938
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3939
|
-
"@type": "Note",
|
|
3940
|
-
"@id": "ap://did:key:z6MkOther/note",
|
|
3941
|
-
"content": "Fetched portable note",
|
|
3942
|
-
},
|
|
3943
|
-
};
|
|
3944
|
-
}
|
|
3945
|
-
throw new Error("Document not found");
|
|
3946
|
-
};
|
|
3947
|
-
|
|
3948
|
-
const result = await create.getObject({ documentLoader });
|
|
3949
|
-
assertInstanceOf(result, Note);
|
|
3950
|
-
deepStrictEqual(result.content, "Fetched portable note");
|
|
3951
|
-
},
|
|
3952
|
-
);
|
|
3953
|
-
|
|
3954
2612
|
test("FEP-fe34: Array properties respect cross-origin policy", async () => {
|
|
3955
2613
|
// deno-lint-ignore require-await
|
|
3956
2614
|
const crossOriginDocumentLoader = async (url: string) => {
|
|
@@ -4058,82 +2716,6 @@ test("FEP-fe34: Array properties with crossOrigin trust option", async () => {
|
|
|
4058
2716
|
deepStrictEqual((items[1] as Note).content, "Legitimate note 2");
|
|
4059
2717
|
});
|
|
4060
2718
|
|
|
4061
|
-
test("FEP-fe34: id-less arrays honor crossOrigin trust", async () => {
|
|
4062
|
-
const collection = await Collection.fromJsonLd({
|
|
4063
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
4064
|
-
"@type": "Collection",
|
|
4065
|
-
"items": [
|
|
4066
|
-
{
|
|
4067
|
-
"@type": "Note",
|
|
4068
|
-
"@id": "https://different-origin.com/note1",
|
|
4069
|
-
"content": "Embedded note 1",
|
|
4070
|
-
},
|
|
4071
|
-
{
|
|
4072
|
-
"@type": "Note",
|
|
4073
|
-
"@id": "https://different-origin.com/note2",
|
|
4074
|
-
"content": "Embedded note 2",
|
|
4075
|
-
},
|
|
4076
|
-
],
|
|
4077
|
-
});
|
|
4078
|
-
|
|
4079
|
-
const items = [];
|
|
4080
|
-
for await (
|
|
4081
|
-
const item of collection.getItems({
|
|
4082
|
-
crossOrigin: "trust",
|
|
4083
|
-
// deno-lint-ignore require-await
|
|
4084
|
-
documentLoader: async (url) => {
|
|
4085
|
-
throw new Error(`Unexpected fetch: ${url}`);
|
|
4086
|
-
},
|
|
4087
|
-
})
|
|
4088
|
-
) {
|
|
4089
|
-
items.push(item);
|
|
4090
|
-
}
|
|
4091
|
-
|
|
4092
|
-
deepStrictEqual(items.length, 2);
|
|
4093
|
-
assertInstanceOf(items[0], Note);
|
|
4094
|
-
assertInstanceOf(items[1], Note);
|
|
4095
|
-
deepStrictEqual((items[0] as Note).content, "Embedded note 1");
|
|
4096
|
-
deepStrictEqual((items[1] as Note).content, "Embedded note 2");
|
|
4097
|
-
});
|
|
4098
|
-
|
|
4099
|
-
test("FEP-fe34: Array properties track trust per item", async () => {
|
|
4100
|
-
const collection = new Collection({
|
|
4101
|
-
id: new URL("https://example.com/collection"),
|
|
4102
|
-
items: [
|
|
4103
|
-
new Note({
|
|
4104
|
-
id: new URL("https://malicious.com/fake-note1"),
|
|
4105
|
-
content: "Trusted constructor note 1",
|
|
4106
|
-
}),
|
|
4107
|
-
new URL("https://different-origin.com/note2"),
|
|
4108
|
-
],
|
|
4109
|
-
});
|
|
4110
|
-
// deno-lint-ignore require-await
|
|
4111
|
-
const documentLoader = async (url: string) => {
|
|
4112
|
-
if (url === "https://different-origin.com/note2") {
|
|
4113
|
-
return {
|
|
4114
|
-
documentUrl: url,
|
|
4115
|
-
contextUrl: null,
|
|
4116
|
-
document: {
|
|
4117
|
-
"@context": "https://www.w3.org/ns/activitystreams",
|
|
4118
|
-
"@type": "Note",
|
|
4119
|
-
"@id": "https://malicious.com/fake-note2",
|
|
4120
|
-
"content": "Untrusted fetched note 2",
|
|
4121
|
-
},
|
|
4122
|
-
};
|
|
4123
|
-
}
|
|
4124
|
-
throw new Error("Document not found");
|
|
4125
|
-
};
|
|
4126
|
-
|
|
4127
|
-
const items = [];
|
|
4128
|
-
for await (const item of collection.getItems({ documentLoader })) {
|
|
4129
|
-
items.push(item);
|
|
4130
|
-
}
|
|
4131
|
-
|
|
4132
|
-
deepStrictEqual(items.length, 1);
|
|
4133
|
-
assertInstanceOf(items[0], Note);
|
|
4134
|
-
deepStrictEqual((items[0] as Note).content, "Trusted constructor note 1");
|
|
4135
|
-
});
|
|
4136
|
-
|
|
4137
2719
|
test(
|
|
4138
2720
|
"FEP-fe34: Embedded objects in arrays from JSON-LD respect cross-origin policy",
|
|
4139
2721
|
async () => {
|