@fedify/vocab 2.4.0-dev.2056 → 2.4.0-dev.2063
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 +3926 -749
- package/dist/mod.d.cts +23 -0
- package/dist/mod.d.ts +23 -0
- package/dist/mod.js +3927 -750
- package/dist-tests/{actor-BgeBgt_8.mjs → actor-hpNVHQvY.mjs} +2 -2
- package/dist-tests/actor.test.mjs +3 -3
- package/dist-tests/{esm-Df0Yo-Tp.mjs → esm-CuilqPDu.mjs} +1 -1
- package/dist-tests/gateway.test.mjs +239 -2
- package/dist-tests/{lookup-C13R72YU.mjs → lookup-Bi6dOTm_.mjs} +2 -2
- package/dist-tests/lookup.test.mjs +3 -3
- package/dist-tests/portable-lookup.test.mjs +4 -4
- package/dist-tests/signed-representation.test.mjs +1 -1
- package/dist-tests/translation.test.mjs +3 -3
- package/dist-tests/type.test.mjs +1 -1
- package/dist-tests/{vocab-BJGPw--L.mjs → vocab-DZq1JW3s.mjs} +3927 -750
- package/dist-tests/vocab.test.mjs +1 -1
- package/package.json +4 -4
- package/src/gateway.test.ts +355 -1
- package/src/lookup.ts +25 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
globalThis.addEventListener = () => {};
|
|
3
|
-
import { A as
|
|
3
|
+
import { A as Object$1, B as QuoteAuthorization, C as Intent, D as Measure, E as Link, F as Person, G as Tombstone, H as Reject, I as Place, L as PropertyValue, N as OrderedCollectionPage, O as Multikey, P as Organization, R as Proposal, S as Image, T as InteractionRule, U as Service, V as QuoteRequest, W as Source, X as vocab_exports, _ as FeaturedCollection, a as Application, b as Group, d as CryptographicKey, f as Delete, g as FeatureRequest, h as FeatureAuthorization, i as Announce, j as Offer, k as Note, l as Commitment, m as Endpoints, n as Activity, p as Document, r as Agreement, s as Collection, t as Accept, u as Create, v as FeaturedItem, w as InteractionPolicy, x as Hashtag, y as Follow, z as Question } from "./vocab-DZq1JW3s.mjs";
|
|
4
4
|
import { t as assertInstanceOf } from "./utils-Df2odC27.mjs";
|
|
5
5
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
6
6
|
import { deepStrictEqual, notDeepStrictEqual, ok, rejects, throws } from "node:assert/strict";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/vocab",
|
|
3
|
-
"version": "2.4.0-dev.
|
|
3
|
+
"version": "2.4.0-dev.2063+366c0362",
|
|
4
4
|
"homepage": "https://fedify.dev/",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"jsonld": "^9.0.0",
|
|
44
44
|
"pkijs": "^3.3.3",
|
|
45
45
|
"temporal-polyfill": "^1.0.1",
|
|
46
|
-
"@fedify/vocab-tools": "2.4.0-dev.
|
|
47
|
-
"@fedify/webfinger": "2.4.0-dev.
|
|
48
|
-
"@fedify/vocab-runtime": "2.4.0-dev.
|
|
46
|
+
"@fedify/vocab-tools": "2.4.0-dev.2063+366c0362",
|
|
47
|
+
"@fedify/webfinger": "2.4.0-dev.2063+366c0362",
|
|
48
|
+
"@fedify/vocab-runtime": "2.4.0-dev.2063+366c0362"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "^24.12.2",
|
package/src/gateway.test.ts
CHANGED
|
@@ -7,13 +7,23 @@ import {
|
|
|
7
7
|
type DocumentLoader,
|
|
8
8
|
FetchError,
|
|
9
9
|
getDocumentLoader,
|
|
10
|
+
type PortableObjectVerification,
|
|
10
11
|
type PortableObjectVerifier,
|
|
12
|
+
type PortableObjectVerifierOptions,
|
|
11
13
|
type RemoteDocument,
|
|
12
14
|
} from "@fedify/vocab-runtime";
|
|
13
15
|
import fetchMock from "fetch-mock";
|
|
14
16
|
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
17
|
+
import { traverseCollection } from "./lookup.ts";
|
|
15
18
|
import { assertInstanceOf } from "./utils.ts";
|
|
16
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
Collection,
|
|
21
|
+
CollectionPage,
|
|
22
|
+
Create,
|
|
23
|
+
Note,
|
|
24
|
+
OrderedCollection,
|
|
25
|
+
Person,
|
|
26
|
+
} from "./vocab.ts";
|
|
17
27
|
|
|
18
28
|
const did = "did:key:z6Mkabc";
|
|
19
29
|
const objectId = `ap+ef61://${did}/objects/1`;
|
|
@@ -870,3 +880,347 @@ test("getObject() sends the ActivityStreams Accept header to gateways", {
|
|
|
870
880
|
fetchMock.hardReset();
|
|
871
881
|
}
|
|
872
882
|
});
|
|
883
|
+
|
|
884
|
+
const AS = "https://www.w3.org/ns/activitystreams#";
|
|
885
|
+
|
|
886
|
+
function gatewayUrl(gateway: string, path: string): string {
|
|
887
|
+
return `${gateway}/.well-known/apgateway/${did}${path}`;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
function createRecordingVerifier(
|
|
891
|
+
decide: (
|
|
892
|
+
document: unknown,
|
|
893
|
+
options: PortableObjectVerifierOptions,
|
|
894
|
+
) => PortableObjectVerification = () => ({ verified: true }),
|
|
895
|
+
): PortableObjectVerifier & {
|
|
896
|
+
readonly calls: {
|
|
897
|
+
document: unknown;
|
|
898
|
+
options: PortableObjectVerifierOptions;
|
|
899
|
+
}[];
|
|
900
|
+
} {
|
|
901
|
+
const calls: {
|
|
902
|
+
document: unknown;
|
|
903
|
+
options: PortableObjectVerifierOptions;
|
|
904
|
+
}[] = [];
|
|
905
|
+
// deno-lint-ignore require-await
|
|
906
|
+
const verifier = async (
|
|
907
|
+
document: unknown,
|
|
908
|
+
options: PortableObjectVerifierOptions,
|
|
909
|
+
) => {
|
|
910
|
+
calls.push({ document, options });
|
|
911
|
+
return decide(document, options);
|
|
912
|
+
};
|
|
913
|
+
return Object.assign(verifier, { calls });
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
function portableCollection(
|
|
917
|
+
path: string,
|
|
918
|
+
extra: Record<string, unknown> = {},
|
|
919
|
+
): Record<string, unknown> {
|
|
920
|
+
return {
|
|
921
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
922
|
+
id: `ap://${did}${path}`,
|
|
923
|
+
type: "OrderedCollection",
|
|
924
|
+
totalItems: 0,
|
|
925
|
+
...extra,
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
test("getOutbox() passes the fetch source and referrer to the verifier", async () => {
|
|
930
|
+
const person = await Person.fromJsonLd({
|
|
931
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
932
|
+
id: `ap://${did}/actor`,
|
|
933
|
+
type: "Person",
|
|
934
|
+
inbox: `ap://${did}/actor/inbox`,
|
|
935
|
+
outbox: `ap://${did}/actor/outbox?@gateway=${
|
|
936
|
+
encodeURIComponent("https://hint.example")
|
|
937
|
+
}`,
|
|
938
|
+
}, { contextLoader: mockDocumentLoader });
|
|
939
|
+
const documentLoader = createLoader({
|
|
940
|
+
[gatewayUrl("https://hint.example", "/actor/outbox")]: portableCollection(
|
|
941
|
+
"/actor/outbox",
|
|
942
|
+
),
|
|
943
|
+
});
|
|
944
|
+
const verifier = createRecordingVerifier();
|
|
945
|
+
const outbox = await person.getOutbox({
|
|
946
|
+
documentLoader,
|
|
947
|
+
contextLoader: mockDocumentLoader,
|
|
948
|
+
verifyPortableObject: verifier,
|
|
949
|
+
});
|
|
950
|
+
assertInstanceOf(outbox, Collection);
|
|
951
|
+
deepStrictEqual(verifier.calls.length, 1);
|
|
952
|
+
const { options } = verifier.calls[0];
|
|
953
|
+
deepStrictEqual(
|
|
954
|
+
options.documentUrl,
|
|
955
|
+
new URL(gatewayUrl("https://hint.example", "/actor/outbox")),
|
|
956
|
+
);
|
|
957
|
+
deepStrictEqual(options.gateways, undefined);
|
|
958
|
+
deepStrictEqual(options.gatewayHints, [new URL("https://hint.example")]);
|
|
959
|
+
ok(options.referrer?.object === person);
|
|
960
|
+
deepStrictEqual(options.referrer?.property, `${AS}outbox`);
|
|
961
|
+
deepStrictEqual(options.referrer?.acceptance, undefined);
|
|
962
|
+
|
|
963
|
+
// Explicit gateways are passed as such:
|
|
964
|
+
const person2 = await Person.fromJsonLd({
|
|
965
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
966
|
+
id: `ap://${did}/actor`,
|
|
967
|
+
type: "Person",
|
|
968
|
+
inbox: `ap://${did}/actor/inbox`,
|
|
969
|
+
outbox: `ap://${did}/actor/outbox`,
|
|
970
|
+
}, { contextLoader: mockDocumentLoader });
|
|
971
|
+
const verifier2 = createRecordingVerifier();
|
|
972
|
+
await person2.getOutbox({
|
|
973
|
+
documentLoader: createLoader({
|
|
974
|
+
[gatewayUrl("https://gw.example", "/actor/outbox")]: portableCollection(
|
|
975
|
+
"/actor/outbox",
|
|
976
|
+
),
|
|
977
|
+
}),
|
|
978
|
+
contextLoader: mockDocumentLoader,
|
|
979
|
+
gateways: ["https://gw.example"],
|
|
980
|
+
verifyPortableObject: verifier2,
|
|
981
|
+
});
|
|
982
|
+
deepStrictEqual(verifier2.calls[0].options.gateways, [
|
|
983
|
+
new URL("https://gw.example"),
|
|
984
|
+
]);
|
|
985
|
+
deepStrictEqual(verifier2.calls[0].options.gatewayHints, undefined);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
test("getFirst() passes the referrer chain and collection context", async () => {
|
|
989
|
+
const context = Object.freeze({});
|
|
990
|
+
const documentLoader = createLoader({
|
|
991
|
+
[gatewayUrl("https://gw.example", "/actor")]: {
|
|
992
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
993
|
+
id: `ap://${did}/actor`,
|
|
994
|
+
type: "Person",
|
|
995
|
+
inbox: `ap://${did}/actor/inbox`,
|
|
996
|
+
outbox: `ap://${did}/actor/outbox`,
|
|
997
|
+
},
|
|
998
|
+
[gatewayUrl("https://gw.example", "/actor/outbox")]: portableCollection(
|
|
999
|
+
"/actor/outbox",
|
|
1000
|
+
{
|
|
1001
|
+
first: {
|
|
1002
|
+
id: `ap://${did}/actor/outbox?page=1`,
|
|
1003
|
+
type: "OrderedCollectionPage",
|
|
1004
|
+
next: `ap://${did}/actor/outbox?page=2`,
|
|
1005
|
+
},
|
|
1006
|
+
},
|
|
1007
|
+
),
|
|
1008
|
+
[gatewayUrl("https://gw.example", "/actor/outbox?page=2")]: {
|
|
1009
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1010
|
+
id: `ap://${did}/actor/outbox?page=2`,
|
|
1011
|
+
type: "OrderedCollectionPage",
|
|
1012
|
+
orderedItems: [],
|
|
1013
|
+
},
|
|
1014
|
+
});
|
|
1015
|
+
// The collection is signed in this scenario (verified without the
|
|
1016
|
+
// unsecured flag), so its embedded first page is trusted by origin:
|
|
1017
|
+
const verifier = createRecordingVerifier((document) =>
|
|
1018
|
+
(document as Record<string, unknown>).type === "OrderedCollection"
|
|
1019
|
+
? { verified: true, collectionContext: context }
|
|
1020
|
+
: { verified: true }
|
|
1021
|
+
);
|
|
1022
|
+
const options = {
|
|
1023
|
+
documentLoader,
|
|
1024
|
+
contextLoader: mockDocumentLoader,
|
|
1025
|
+
gateways: ["https://gw.example"],
|
|
1026
|
+
verifyPortableObject: verifier,
|
|
1027
|
+
};
|
|
1028
|
+
const create = await createActivity(`ap://${did}/actor`);
|
|
1029
|
+
const actor = await create.getObject(options);
|
|
1030
|
+
assertInstanceOf(actor, Person);
|
|
1031
|
+
const outbox = await actor.getOutbox(options);
|
|
1032
|
+
assertInstanceOf(outbox, Collection);
|
|
1033
|
+
const first = await outbox.getFirst(options);
|
|
1034
|
+
assertInstanceOf(first, CollectionPage);
|
|
1035
|
+
const next = await first.getNext(options);
|
|
1036
|
+
assertInstanceOf(next, CollectionPage);
|
|
1037
|
+
const { referrer } = verifier.calls[verifier.calls.length - 1].options;
|
|
1038
|
+
// next ← (embedded) first ← outbox ← actor ← create:
|
|
1039
|
+
ok(referrer?.object === first);
|
|
1040
|
+
deepStrictEqual(referrer?.property, `${AS}next`);
|
|
1041
|
+
deepStrictEqual(referrer?.acceptance, undefined);
|
|
1042
|
+
ok(referrer?.referrer?.object === outbox);
|
|
1043
|
+
deepStrictEqual(referrer?.referrer?.property, `${AS}first`);
|
|
1044
|
+
deepStrictEqual(referrer?.referrer?.acceptance, "verified");
|
|
1045
|
+
ok(referrer?.referrer?.collectionContext === context);
|
|
1046
|
+
ok(referrer?.referrer?.referrer?.object === actor);
|
|
1047
|
+
deepStrictEqual(referrer?.referrer?.referrer?.property, `${AS}outbox`);
|
|
1048
|
+
deepStrictEqual(referrer?.referrer?.referrer?.acceptance, "verified");
|
|
1049
|
+
ok(referrer?.referrer?.referrer?.referrer?.object === create);
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
test("accessors do not trust objects embedded in unsecured collections", async () => {
|
|
1053
|
+
const itemPath = "/objects/1";
|
|
1054
|
+
const documentLoader = createLoader({
|
|
1055
|
+
[gatewayUrl("https://gw.example", "/actor/outbox")]: portableCollection(
|
|
1056
|
+
"/actor/outbox",
|
|
1057
|
+
{
|
|
1058
|
+
orderedItems: [
|
|
1059
|
+
// A forged copy of a portable object:
|
|
1060
|
+
{ id: `ap://${did}${itemPath}`, type: "Note", content: "Forged" },
|
|
1061
|
+
// An object that cannot be verified on its own:
|
|
1062
|
+
{ type: "Note", content: "Anonymous" },
|
|
1063
|
+
],
|
|
1064
|
+
},
|
|
1065
|
+
),
|
|
1066
|
+
[gatewayUrl("https://gw.example", itemPath)]: note(),
|
|
1067
|
+
});
|
|
1068
|
+
const verifier = createRecordingVerifier((document) =>
|
|
1069
|
+
(document as Record<string, unknown>).type === "OrderedCollection"
|
|
1070
|
+
? { verified: true, unsecured: true }
|
|
1071
|
+
: { verified: true }
|
|
1072
|
+
);
|
|
1073
|
+
const options = {
|
|
1074
|
+
documentLoader,
|
|
1075
|
+
contextLoader: mockDocumentLoader,
|
|
1076
|
+
gateways: ["https://gw.example"],
|
|
1077
|
+
verifyPortableObject: verifier,
|
|
1078
|
+
};
|
|
1079
|
+
const createPerson = () =>
|
|
1080
|
+
Person.fromJsonLd({
|
|
1081
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1082
|
+
id: `ap://${did}/actor`,
|
|
1083
|
+
type: "Person",
|
|
1084
|
+
inbox: `ap://${did}/actor/inbox`,
|
|
1085
|
+
outbox: `ap://${did}/actor/outbox`,
|
|
1086
|
+
}, { contextLoader: mockDocumentLoader });
|
|
1087
|
+
const outbox = await (await createPerson()).getOutbox(options);
|
|
1088
|
+
assertInstanceOf(outbox, Collection);
|
|
1089
|
+
const items = await Array.fromAsync(outbox.getItems(options));
|
|
1090
|
+
deepStrictEqual(
|
|
1091
|
+
items.map((item) => item instanceof Note ? item.content : null),
|
|
1092
|
+
["Portable note"],
|
|
1093
|
+
);
|
|
1094
|
+
// Even crossOrigin: "trust" does not make them trusted:
|
|
1095
|
+
const outbox2 = await (await createPerson()).getOutbox(options);
|
|
1096
|
+
assertInstanceOf(outbox2, Collection);
|
|
1097
|
+
const items2 = await Array.fromAsync(
|
|
1098
|
+
outbox2.getItems({ ...options, crossOrigin: "trust" }),
|
|
1099
|
+
);
|
|
1100
|
+
deepStrictEqual(items2.length, 1);
|
|
1101
|
+
|
|
1102
|
+
// A clone keeps the restriction, so its embedded objects are fetched
|
|
1103
|
+
// again (and fail here, since nothing can be fetched):
|
|
1104
|
+
const outbox3 = await (await createPerson()).getOutbox(options);
|
|
1105
|
+
assertInstanceOf(outbox3, Collection);
|
|
1106
|
+
const items3 = await Array.fromAsync(
|
|
1107
|
+
outbox3.clone().getItems({
|
|
1108
|
+
...options,
|
|
1109
|
+
documentLoader: createLoader({}),
|
|
1110
|
+
suppressError: true,
|
|
1111
|
+
}),
|
|
1112
|
+
);
|
|
1113
|
+
deepStrictEqual(items3, []);
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
test("accessors reject compatible identifiers from portable objects", async () => {
|
|
1117
|
+
const compatibleId = gatewayUrl("https://evil.example", "/actor/outbox");
|
|
1118
|
+
const collection = (id: string) => ({
|
|
1119
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1120
|
+
id,
|
|
1121
|
+
type: "OrderedCollection",
|
|
1122
|
+
totalItems: 0,
|
|
1123
|
+
});
|
|
1124
|
+
const person = (outbox: unknown) =>
|
|
1125
|
+
Person.fromJsonLd({
|
|
1126
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1127
|
+
id: `ap://${did}/actor`,
|
|
1128
|
+
type: "Person",
|
|
1129
|
+
inbox: `ap://${did}/actor/inbox`,
|
|
1130
|
+
outbox,
|
|
1131
|
+
}, { contextLoader: mockDocumentLoader });
|
|
1132
|
+
const redirectingLoader: DocumentLoader = (url) =>
|
|
1133
|
+
Promise.resolve({
|
|
1134
|
+
contextUrl: null,
|
|
1135
|
+
documentUrl: url === "https://example.com/outbox" ? compatibleId : url,
|
|
1136
|
+
document: collection(
|
|
1137
|
+
url === "https://example.com/outbox" ? compatibleId : url,
|
|
1138
|
+
),
|
|
1139
|
+
});
|
|
1140
|
+
for (const crossOrigin of [undefined, "trust"] as const) {
|
|
1141
|
+
const options = {
|
|
1142
|
+
documentLoader: redirectingLoader,
|
|
1143
|
+
contextLoader: mockDocumentLoader,
|
|
1144
|
+
verifyPortableObject: createRecordingVerifier(),
|
|
1145
|
+
crossOrigin,
|
|
1146
|
+
};
|
|
1147
|
+
// A compatible identifier as the reference:
|
|
1148
|
+
deepStrictEqual(
|
|
1149
|
+
await (await person(compatibleId)).getOutbox(options),
|
|
1150
|
+
null,
|
|
1151
|
+
);
|
|
1152
|
+
// A redirect to a compatible identifier:
|
|
1153
|
+
deepStrictEqual(
|
|
1154
|
+
await (await person("https://example.com/outbox")).getOutbox(options),
|
|
1155
|
+
null,
|
|
1156
|
+
);
|
|
1157
|
+
// An embedded object with a compatible identifier:
|
|
1158
|
+
deepStrictEqual(
|
|
1159
|
+
await (await person(collection(compatibleId))).getOutbox(options),
|
|
1160
|
+
null,
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
// A throwing crossOrigin option throws:
|
|
1164
|
+
await rejects(
|
|
1165
|
+
async () =>
|
|
1166
|
+
await (await person(compatibleId)).getOutbox({
|
|
1167
|
+
documentLoader: redirectingLoader,
|
|
1168
|
+
contextLoader: mockDocumentLoader,
|
|
1169
|
+
crossOrigin: "throw",
|
|
1170
|
+
}),
|
|
1171
|
+
/portable object/,
|
|
1172
|
+
);
|
|
1173
|
+
// Compatible identifiers from ordinary HTTP(S) objects are not affected:
|
|
1174
|
+
const httpPerson = await Person.fromJsonLd({
|
|
1175
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1176
|
+
id: "https://evil.example/actor",
|
|
1177
|
+
type: "Person",
|
|
1178
|
+
inbox: "https://evil.example/actor/inbox",
|
|
1179
|
+
outbox: compatibleId,
|
|
1180
|
+
}, { contextLoader: mockDocumentLoader });
|
|
1181
|
+
assertInstanceOf(
|
|
1182
|
+
await httpPerson.getOutbox({
|
|
1183
|
+
documentLoader: redirectingLoader,
|
|
1184
|
+
contextLoader: mockDocumentLoader,
|
|
1185
|
+
}),
|
|
1186
|
+
OrderedCollection,
|
|
1187
|
+
);
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
test("singular accessors drop anonymous objects embedded in unsecured collections", async () => {
|
|
1191
|
+
const documentLoader = createLoader({
|
|
1192
|
+
[gatewayUrl("https://gw.example", "/actor/outbox")]: portableCollection(
|
|
1193
|
+
"/actor/outbox",
|
|
1194
|
+
{
|
|
1195
|
+
// An anonymous page cannot be fetched and verified on its own:
|
|
1196
|
+
first: {
|
|
1197
|
+
type: "OrderedCollectionPage",
|
|
1198
|
+
orderedItems: [{ type: "Note", content: "Anonymous" }],
|
|
1199
|
+
},
|
|
1200
|
+
},
|
|
1201
|
+
),
|
|
1202
|
+
});
|
|
1203
|
+
const options = {
|
|
1204
|
+
documentLoader,
|
|
1205
|
+
contextLoader: mockDocumentLoader,
|
|
1206
|
+
gateways: ["https://gw.example"],
|
|
1207
|
+
verifyPortableObject: createRecordingVerifier(() => ({
|
|
1208
|
+
verified: true,
|
|
1209
|
+
unsecured: true,
|
|
1210
|
+
})),
|
|
1211
|
+
};
|
|
1212
|
+
const person = await Person.fromJsonLd({
|
|
1213
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
1214
|
+
id: `ap://${did}/actor`,
|
|
1215
|
+
type: "Person",
|
|
1216
|
+
inbox: `ap://${did}/actor/inbox`,
|
|
1217
|
+
outbox: `ap://${did}/actor/outbox`,
|
|
1218
|
+
}, { contextLoader: mockDocumentLoader });
|
|
1219
|
+
const outbox = await person.getOutbox(options);
|
|
1220
|
+
assertInstanceOf(outbox, OrderedCollection);
|
|
1221
|
+
deepStrictEqual(await outbox.getFirst(options), null);
|
|
1222
|
+
deepStrictEqual(
|
|
1223
|
+
await Array.fromAsync(traverseCollection(outbox, options)),
|
|
1224
|
+
[],
|
|
1225
|
+
);
|
|
1226
|
+
});
|
package/src/lookup.ts
CHANGED
|
@@ -687,6 +687,31 @@ export interface TraverseCollectionOptions {
|
|
|
687
687
|
* @default `{ seconds: 0 }`
|
|
688
688
|
*/
|
|
689
689
|
interval?: Temporal.Duration | Temporal.DurationLike;
|
|
690
|
+
/**
|
|
691
|
+
* Whether to trust objects whose origin differs from the collection or page
|
|
692
|
+
* that refers to them. See the `crossOrigin` option of property accessors
|
|
693
|
+
* such as `Collection.getItems()`.
|
|
694
|
+
* @since 2.4.0
|
|
695
|
+
*/
|
|
696
|
+
crossOrigin?: "ignore" | "throw" | "trust";
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* The [FEP-ef61] gateways to fetch portable (`ap:`/`ap+ef61:`) pages and
|
|
700
|
+
* items through, in order. See the `gateways` option of property
|
|
701
|
+
* accessors.
|
|
702
|
+
*
|
|
703
|
+
* [FEP-ef61]: https://w3id.org/fep/ef61
|
|
704
|
+
* @since 2.4.0
|
|
705
|
+
*/
|
|
706
|
+
gateways?: readonly (string | URL)[];
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* The policy to apply to portable pages and items fetched through
|
|
710
|
+
* gateways, typically `verifyPortableObject()` from `@fedify/fedify`.
|
|
711
|
+
* Portable pages and items are not fetched without it.
|
|
712
|
+
* @since 2.4.0
|
|
713
|
+
*/
|
|
714
|
+
verifyPortableObject?: PortableObjectVerifier;
|
|
690
715
|
}
|
|
691
716
|
|
|
692
717
|
/**
|