@fedify/vocab 2.4.0-dev.2035 → 2.4.0-dev.2047
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 +5472 -645
- package/dist/mod.d.cts +416 -1
- package/dist/mod.d.ts +416 -1
- package/dist/mod.js +5472 -645
- package/dist-tests/{actor-BX07d5tK.mjs → actor-chbmxipX.mjs} +71 -2
- package/dist-tests/actor.test.mjs +3 -3
- package/dist-tests/{esm-C_FjLvhG.mjs → esm-Df0Yo-Tp.mjs} +1 -1
- package/dist-tests/gateway.test.mjs +604 -0
- package/dist-tests/{lookup-B9lgdxnM.mjs → lookup-CvrMdVSJ.mjs} +211 -9
- package/dist-tests/lookup.test.mjs +3 -3
- package/dist-tests/portable-lookup.test.mjs +335 -0
- 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-Dw_Vm0NE.mjs → vocab-BJGPw--L.mjs} +5109 -551
- package/dist-tests/vocab.test.mjs +9 -4
- package/package.json +4 -4
- package/src/actor.ts +110 -1
- package/src/gateway.test.ts +872 -0
- package/src/lookup.ts +302 -2
- package/src/portable-lookup.test.ts +457 -0
- package/src/vocab.test.ts +8 -1
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
2
|
+
import {
|
|
3
|
+
type DocumentLoader,
|
|
4
|
+
FetchError,
|
|
5
|
+
parseIri,
|
|
6
|
+
type PortableObjectVerifier,
|
|
7
|
+
type RemoteDocument,
|
|
8
|
+
} from "@fedify/vocab-runtime";
|
|
9
|
+
import fetchMock from "fetch-mock";
|
|
10
|
+
import { deepStrictEqual, equal, rejects } from "node:assert/strict";
|
|
11
|
+
import { getActorHandle } from "./actor.ts";
|
|
12
|
+
import { lookupObject } from "./lookup.ts";
|
|
13
|
+
import { assertInstanceOf } from "./utils.ts";
|
|
14
|
+
import { Person } from "./vocab.ts";
|
|
15
|
+
|
|
16
|
+
const did = "did:key:z6Mkabc";
|
|
17
|
+
const actorId = `ap+ef61://${did}/actor`;
|
|
18
|
+
const gatewayPath = `/.well-known/apgateway/${did}/actor`;
|
|
19
|
+
const compatibleId = `https://example.com${gatewayPath}`;
|
|
20
|
+
const webFingerPrefix = "begin:https://example.com/.well-known/webfinger";
|
|
21
|
+
const AS_TYPE = "application/activity+json";
|
|
22
|
+
|
|
23
|
+
function person(
|
|
24
|
+
id: string = `ap://${did}/actor`,
|
|
25
|
+
extra: Record<string, unknown> = {},
|
|
26
|
+
): Record<string, unknown> {
|
|
27
|
+
return {
|
|
28
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
29
|
+
id,
|
|
30
|
+
type: "Person",
|
|
31
|
+
name: "Alice",
|
|
32
|
+
...extra,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createLoader(
|
|
37
|
+
responses: Record<string, Record<string, unknown>>,
|
|
38
|
+
): DocumentLoader & { readonly fetched: string[] } {
|
|
39
|
+
const fetched: string[] = [];
|
|
40
|
+
// deno-lint-ignore require-await
|
|
41
|
+
const loader = async (
|
|
42
|
+
url: string,
|
|
43
|
+
options?: { signal?: AbortSignal },
|
|
44
|
+
): Promise<RemoteDocument> => {
|
|
45
|
+
fetched.push(url);
|
|
46
|
+
options?.signal?.throwIfAborted();
|
|
47
|
+
const document = responses[url];
|
|
48
|
+
if (document == null) {
|
|
49
|
+
throw new FetchError(
|
|
50
|
+
url,
|
|
51
|
+
"HTTP 404",
|
|
52
|
+
new globalThis.Response(null, { status: 404 }),
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return { contextUrl: null, documentUrl: url, document };
|
|
56
|
+
};
|
|
57
|
+
return Object.assign(loader, { fetched });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function createVerifier(
|
|
61
|
+
verified = true,
|
|
62
|
+
): PortableObjectVerifier & { readonly documents: unknown[] } {
|
|
63
|
+
const documents: unknown[] = [];
|
|
64
|
+
// deno-lint-ignore require-await
|
|
65
|
+
const verifier = async (document: unknown) => {
|
|
66
|
+
documents.push(document);
|
|
67
|
+
return { verified };
|
|
68
|
+
};
|
|
69
|
+
return Object.assign(verifier, { documents });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function selfLinks(...hrefs: string[]) {
|
|
73
|
+
return {
|
|
74
|
+
subject: "acct:alice@example.com",
|
|
75
|
+
links: hrefs.map((href) => ({ rel: "self", type: AS_TYPE, href })),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
test("lookupObject() with FEP-ef61 portable actors", {
|
|
80
|
+
sanitizeResources: false,
|
|
81
|
+
sanitizeOps: false,
|
|
82
|
+
}, async (t) => {
|
|
83
|
+
fetchMock.spyGlobal();
|
|
84
|
+
try {
|
|
85
|
+
await t.step("compatible self link, alias-free JRD", async () => {
|
|
86
|
+
fetchMock.removeRoutes();
|
|
87
|
+
fetchMock.get(webFingerPrefix, selfLinks(compatibleId));
|
|
88
|
+
const document = person();
|
|
89
|
+
const documentLoader = createLoader({ [compatibleId]: document });
|
|
90
|
+
const verifyPortableObject = createVerifier();
|
|
91
|
+
const actor = await lookupObject("@alice@example.com", {
|
|
92
|
+
documentLoader,
|
|
93
|
+
contextLoader: mockDocumentLoader,
|
|
94
|
+
verifyPortableObject,
|
|
95
|
+
});
|
|
96
|
+
assertInstanceOf(actor, Person);
|
|
97
|
+
deepStrictEqual(actor.id, parseIri(actorId));
|
|
98
|
+
deepStrictEqual(documentLoader.fetched, [compatibleId]);
|
|
99
|
+
deepStrictEqual(verifyPortableObject.documents, [document]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await t.step(
|
|
103
|
+
"canonical self link asks the WebFinger host first",
|
|
104
|
+
async () => {
|
|
105
|
+
fetchMock.removeRoutes();
|
|
106
|
+
fetchMock.get(webFingerPrefix, {
|
|
107
|
+
subject: "acct:alice@example.com",
|
|
108
|
+
links: [{
|
|
109
|
+
rel: "self",
|
|
110
|
+
type:
|
|
111
|
+
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
|
112
|
+
href: `ap://${did}/actor?@gateway=https%3A%2F%2Fhint.example`,
|
|
113
|
+
}],
|
|
114
|
+
});
|
|
115
|
+
const hinted = `https://hint.example${gatewayPath}`;
|
|
116
|
+
const documentLoader = createLoader({ [hinted]: person() });
|
|
117
|
+
const actor = await lookupObject("@alice@example.com", {
|
|
118
|
+
documentLoader,
|
|
119
|
+
contextLoader: mockDocumentLoader,
|
|
120
|
+
verifyPortableObject: createVerifier(),
|
|
121
|
+
});
|
|
122
|
+
assertInstanceOf(actor, Person);
|
|
123
|
+
deepStrictEqual(documentLoader.fetched, [compatibleId, hinted]);
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
await t.step("tries the next self link after a failure", async () => {
|
|
128
|
+
fetchMock.removeRoutes();
|
|
129
|
+
const other = `https://other.example${gatewayPath}`;
|
|
130
|
+
fetchMock.get(
|
|
131
|
+
webFingerPrefix,
|
|
132
|
+
selfLinks(`ap://${did}/actor`, compatibleId, other),
|
|
133
|
+
);
|
|
134
|
+
const documentLoader = createLoader({ [other]: person() });
|
|
135
|
+
const actor = await lookupObject("@alice@example.com", {
|
|
136
|
+
documentLoader,
|
|
137
|
+
contextLoader: mockDocumentLoader,
|
|
138
|
+
verifyPortableObject: createVerifier(),
|
|
139
|
+
});
|
|
140
|
+
assertInstanceOf(actor, Person);
|
|
141
|
+
// The same gateway is not asked twice for the same portable ID:
|
|
142
|
+
deepStrictEqual(documentLoader.fetched, [compatibleId, other]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await t.step("rejects objects that fail the checks", async () => {
|
|
146
|
+
fetchMock.removeRoutes();
|
|
147
|
+
fetchMock.get(webFingerPrefix, selfLinks(compatibleId));
|
|
148
|
+
for (
|
|
149
|
+
const [document, verified] of [
|
|
150
|
+
[person(), false],
|
|
151
|
+
// Same DID, but another object:
|
|
152
|
+
[person(`ap://${did}/other`), true],
|
|
153
|
+
// A compatible identifier as the object ID is not portable:
|
|
154
|
+
[person(compatibleId), true],
|
|
155
|
+
] as const
|
|
156
|
+
) {
|
|
157
|
+
const documentLoader = createLoader({ [compatibleId]: document });
|
|
158
|
+
const verifyPortableObject = createVerifier(verified);
|
|
159
|
+
equal(
|
|
160
|
+
await lookupObject("@alice@example.com", {
|
|
161
|
+
documentLoader,
|
|
162
|
+
contextLoader: mockDocumentLoader,
|
|
163
|
+
verifyPortableObject,
|
|
164
|
+
}),
|
|
165
|
+
null,
|
|
166
|
+
);
|
|
167
|
+
// No fallback to fetching the compatible identifier as an ordinary
|
|
168
|
+
// HTTPS URL:
|
|
169
|
+
deepStrictEqual(documentLoader.fetched, [compatibleId]);
|
|
170
|
+
await rejects(
|
|
171
|
+
() =>
|
|
172
|
+
lookupObject("@alice@example.com", {
|
|
173
|
+
documentLoader,
|
|
174
|
+
contextLoader: mockDocumentLoader,
|
|
175
|
+
verifyPortableObject,
|
|
176
|
+
crossOrigin: "throw",
|
|
177
|
+
}),
|
|
178
|
+
{ name: "PortableObjectRejectedError" },
|
|
179
|
+
);
|
|
180
|
+
equal(
|
|
181
|
+
await lookupObject("@alice@example.com", {
|
|
182
|
+
documentLoader,
|
|
183
|
+
contextLoader: mockDocumentLoader,
|
|
184
|
+
verifyPortableObject,
|
|
185
|
+
crossOrigin: "trust",
|
|
186
|
+
}),
|
|
187
|
+
null,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
await t.step("without verifyPortableObject", async () => {
|
|
193
|
+
fetchMock.removeRoutes();
|
|
194
|
+
fetchMock.get(
|
|
195
|
+
webFingerPrefix,
|
|
196
|
+
selfLinks(`ap://${did}/actor`, compatibleId),
|
|
197
|
+
);
|
|
198
|
+
const documentLoader = createLoader({ [compatibleId]: person() });
|
|
199
|
+
for (const crossOrigin of ["ignore", "trust"] as const) {
|
|
200
|
+
// The canonical link is skipped, and the compatible identifier is
|
|
201
|
+
// fetched as an ordinary URL, but its portable object is refused:
|
|
202
|
+
equal(
|
|
203
|
+
await lookupObject("@alice@example.com", {
|
|
204
|
+
documentLoader,
|
|
205
|
+
contextLoader: mockDocumentLoader,
|
|
206
|
+
crossOrigin,
|
|
207
|
+
}),
|
|
208
|
+
null,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
deepStrictEqual(documentLoader.fetched, [compatibleId, compatibleId]);
|
|
212
|
+
await rejects(
|
|
213
|
+
() =>
|
|
214
|
+
lookupObject("@alice@example.com", {
|
|
215
|
+
documentLoader,
|
|
216
|
+
contextLoader: mockDocumentLoader,
|
|
217
|
+
crossOrigin: "throw",
|
|
218
|
+
}),
|
|
219
|
+
/has a different origin than the document URL/,
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// An object with an ordinary ID served at a compatible identifier
|
|
223
|
+
// keeps working as before:
|
|
224
|
+
const httpLoader = createLoader({ [compatibleId]: person(compatibleId) });
|
|
225
|
+
const actor = await lookupObject("@alice@example.com", {
|
|
226
|
+
documentLoader: httpLoader,
|
|
227
|
+
contextLoader: mockDocumentLoader,
|
|
228
|
+
});
|
|
229
|
+
assertInstanceOf(actor, Person);
|
|
230
|
+
deepStrictEqual(actor.id, new URL(compatibleId));
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
await t.step("refuses portable IRIs changed by URL parsing", async () => {
|
|
234
|
+
fetchMock.removeRoutes();
|
|
235
|
+
fetchMock.get(
|
|
236
|
+
webFingerPrefix,
|
|
237
|
+
selfLinks(
|
|
238
|
+
`ap://${did}/x/../actor`,
|
|
239
|
+
`ap://${did}/x/%2e%2e/actor`,
|
|
240
|
+
),
|
|
241
|
+
);
|
|
242
|
+
const documentLoader = createLoader({ [compatibleId]: person() });
|
|
243
|
+
const options = {
|
|
244
|
+
documentLoader,
|
|
245
|
+
contextLoader: mockDocumentLoader,
|
|
246
|
+
verifyPortableObject: createVerifier(),
|
|
247
|
+
};
|
|
248
|
+
equal(await lookupObject("@alice@example.com", options), null);
|
|
249
|
+
equal(
|
|
250
|
+
await lookupObject(
|
|
251
|
+
`ap://${did}/x/../actor?@gateway=https%3A%2F%2Fexample.com`,
|
|
252
|
+
options,
|
|
253
|
+
),
|
|
254
|
+
null,
|
|
255
|
+
);
|
|
256
|
+
deepStrictEqual(documentLoader.fetched, []);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await t.step("bounds gateway requests", async () => {
|
|
260
|
+
fetchMock.removeRoutes();
|
|
261
|
+
const hints = Array.from(
|
|
262
|
+
{ length: 5 },
|
|
263
|
+
(_, i) => `@gateway=https%3A%2F%2Fg${i}.example`,
|
|
264
|
+
).join("&");
|
|
265
|
+
fetchMock.get(
|
|
266
|
+
webFingerPrefix,
|
|
267
|
+
selfLinks(
|
|
268
|
+
`ap://${did}/actor?${hints}`,
|
|
269
|
+
`ap://${did}/actor2?${hints}`,
|
|
270
|
+
`https://g9.example/.well-known/apgateway/${did}/actor`,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
const documentLoader = createLoader({});
|
|
274
|
+
equal(
|
|
275
|
+
await lookupObject("@alice@example.com", {
|
|
276
|
+
documentLoader,
|
|
277
|
+
contextLoader: mockDocumentLoader,
|
|
278
|
+
verifyPortableObject: createVerifier(),
|
|
279
|
+
}),
|
|
280
|
+
null,
|
|
281
|
+
);
|
|
282
|
+
deepStrictEqual(documentLoader.fetched, [
|
|
283
|
+
compatibleId,
|
|
284
|
+
...[0, 1, 2, 3].map((i) => `https://g${i}.example${gatewayPath}`),
|
|
285
|
+
]);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
await t.step("cancellation", async () => {
|
|
289
|
+
fetchMock.removeRoutes();
|
|
290
|
+
fetchMock.get(
|
|
291
|
+
webFingerPrefix,
|
|
292
|
+
selfLinks(
|
|
293
|
+
`ap://${did}/actor`,
|
|
294
|
+
`https://other.example${gatewayPath}`,
|
|
295
|
+
),
|
|
296
|
+
);
|
|
297
|
+
const controller = new AbortController();
|
|
298
|
+
const verifyPortableObject: PortableObjectVerifier = () => {
|
|
299
|
+
controller.abort();
|
|
300
|
+
return Promise.resolve({ verified: true });
|
|
301
|
+
};
|
|
302
|
+
const documentLoader = createLoader({ [compatibleId]: person() });
|
|
303
|
+
equal(
|
|
304
|
+
await lookupObject("@alice@example.com", {
|
|
305
|
+
documentLoader,
|
|
306
|
+
contextLoader: mockDocumentLoader,
|
|
307
|
+
verifyPortableObject,
|
|
308
|
+
signal: controller.signal,
|
|
309
|
+
}),
|
|
310
|
+
null,
|
|
311
|
+
);
|
|
312
|
+
deepStrictEqual(documentLoader.fetched, [compatibleId]);
|
|
313
|
+
});
|
|
314
|
+
} finally {
|
|
315
|
+
fetchMock.removeRoutes();
|
|
316
|
+
fetchMock.hardReset();
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("lookupObject() looks up portable identifiers directly", async () => {
|
|
321
|
+
const verifyPortableObject = createVerifier();
|
|
322
|
+
const hinted = `https://gw.example${gatewayPath}`;
|
|
323
|
+
const documentLoader = createLoader({
|
|
324
|
+
[hinted]: person(),
|
|
325
|
+
[`https://example.com${gatewayPath}`]: person(),
|
|
326
|
+
[actorId]: person(),
|
|
327
|
+
});
|
|
328
|
+
const options = {
|
|
329
|
+
documentLoader,
|
|
330
|
+
contextLoader: mockDocumentLoader,
|
|
331
|
+
verifyPortableObject,
|
|
332
|
+
};
|
|
333
|
+
for (
|
|
334
|
+
const identifier of [
|
|
335
|
+
`ap://${did}/actor?@gateway=https%3A%2F%2Fgw.example`,
|
|
336
|
+
compatibleId,
|
|
337
|
+
new URL(compatibleId),
|
|
338
|
+
// Without hints, the document loader gets the portable ID itself:
|
|
339
|
+
`ap://${did}/actor`,
|
|
340
|
+
parseIri(`ap://${did}/actor`),
|
|
341
|
+
]
|
|
342
|
+
) {
|
|
343
|
+
const actor = await lookupObject(identifier, options);
|
|
344
|
+
assertInstanceOf(actor, Person);
|
|
345
|
+
deepStrictEqual(actor.id, parseIri(actorId));
|
|
346
|
+
}
|
|
347
|
+
deepStrictEqual(documentLoader.fetched, [
|
|
348
|
+
hinted,
|
|
349
|
+
compatibleId,
|
|
350
|
+
compatibleId,
|
|
351
|
+
actorId,
|
|
352
|
+
actorId,
|
|
353
|
+
]);
|
|
354
|
+
// Portable identifiers are not looked up without a verifier:
|
|
355
|
+
equal(
|
|
356
|
+
await lookupObject(`ap://${did}/actor`, {
|
|
357
|
+
documentLoader,
|
|
358
|
+
contextLoader: mockDocumentLoader,
|
|
359
|
+
}),
|
|
360
|
+
null,
|
|
361
|
+
);
|
|
362
|
+
deepStrictEqual(documentLoader.fetched.length, 5);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("getActorHandle() with FEP-ef61 portable actors", {
|
|
366
|
+
sanitizeResources: false,
|
|
367
|
+
sanitizeOps: false,
|
|
368
|
+
}, async (t) => {
|
|
369
|
+
const actor = new Person({
|
|
370
|
+
id: parseIri(actorId),
|
|
371
|
+
preferredUsername: "alice",
|
|
372
|
+
gateways: [new URL("https://example.com"), new URL("https://example.org")],
|
|
373
|
+
});
|
|
374
|
+
fetchMock.spyGlobal();
|
|
375
|
+
try {
|
|
376
|
+
await t.step("verified through the first gateway", async () => {
|
|
377
|
+
fetchMock.removeRoutes();
|
|
378
|
+
fetchMock.get(
|
|
379
|
+
"https://example.com/.well-known/webfinger?resource=acct%3Aalice%40example.com",
|
|
380
|
+
selfLinks(compatibleId),
|
|
381
|
+
);
|
|
382
|
+
deepStrictEqual(await getActorHandle(actor), "@alice@example.com");
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
await t.step("canonical self link", async () => {
|
|
386
|
+
fetchMock.removeRoutes();
|
|
387
|
+
fetchMock.get(webFingerPrefix, selfLinks(`ap://${did}/actor`));
|
|
388
|
+
deepStrictEqual(await getActorHandle(actor), "@alice@example.com");
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
await t.step("follows a verified subject", async () => {
|
|
392
|
+
fetchMock.removeRoutes();
|
|
393
|
+
fetchMock.get(webFingerPrefix, {
|
|
394
|
+
...selfLinks(compatibleId),
|
|
395
|
+
subject: "acct:alice@example.org",
|
|
396
|
+
});
|
|
397
|
+
fetchMock.get(
|
|
398
|
+
"begin:https://example.org/.well-known/webfinger",
|
|
399
|
+
{ ...selfLinks(compatibleId), subject: "acct:alice@example.org" },
|
|
400
|
+
);
|
|
401
|
+
deepStrictEqual(await getActorHandle(actor), "@alice@example.org");
|
|
402
|
+
|
|
403
|
+
// An unverified subject is ignored:
|
|
404
|
+
fetchMock.removeRoutes();
|
|
405
|
+
fetchMock.get(webFingerPrefix, {
|
|
406
|
+
...selfLinks(compatibleId),
|
|
407
|
+
subject: "acct:alice@example.org",
|
|
408
|
+
});
|
|
409
|
+
fetchMock.get(
|
|
410
|
+
"begin:https://example.org/.well-known/webfinger",
|
|
411
|
+
selfLinks(`ap://${did}/other`),
|
|
412
|
+
);
|
|
413
|
+
deepStrictEqual(await getActorHandle(actor), "@alice@example.com");
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
await t.step("rejects a WebFinger response for another actor", async () => {
|
|
417
|
+
for (
|
|
418
|
+
const jrd of [
|
|
419
|
+
selfLinks(`https://example.com/.well-known/apgateway/${did}/other`),
|
|
420
|
+
selfLinks("https://example.com/users/alice"),
|
|
421
|
+
{ subject: "acct:alice@example.com", links: [] },
|
|
422
|
+
]
|
|
423
|
+
) {
|
|
424
|
+
fetchMock.removeRoutes();
|
|
425
|
+
fetchMock.get(webFingerPrefix, jrd);
|
|
426
|
+
await rejects(() => getActorHandle(actor), TypeError);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
await t.step("does not fall back when WebFinger fails", async () => {
|
|
431
|
+
fetchMock.removeRoutes();
|
|
432
|
+
fetchMock.get(webFingerPrefix, 404);
|
|
433
|
+
await rejects(() => getActorHandle(actor), TypeError);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
await t.step("not enough information", async () => {
|
|
437
|
+
fetchMock.removeRoutes();
|
|
438
|
+
fetchMock.clearHistory();
|
|
439
|
+
for (
|
|
440
|
+
const target of [
|
|
441
|
+
parseIri(actorId),
|
|
442
|
+
new Person({ id: parseIri(actorId), preferredUsername: "alice" }),
|
|
443
|
+
new Person({
|
|
444
|
+
id: parseIri(actorId),
|
|
445
|
+
gateways: [new URL("https://example.com")],
|
|
446
|
+
}),
|
|
447
|
+
]
|
|
448
|
+
) {
|
|
449
|
+
await rejects(() => getActorHandle(target), TypeError);
|
|
450
|
+
}
|
|
451
|
+
deepStrictEqual(fetchMock.callHistory.calls().length, 0);
|
|
452
|
+
});
|
|
453
|
+
} finally {
|
|
454
|
+
fetchMock.removeRoutes();
|
|
455
|
+
fetchMock.hardReset();
|
|
456
|
+
}
|
|
457
|
+
});
|
package/src/vocab.test.ts
CHANGED
|
@@ -1830,6 +1830,8 @@ test("Activity.getObject() fetches canonical portable IRIs", async () => {
|
|
|
1830
1830
|
const object = await activity.getObject({
|
|
1831
1831
|
documentLoader,
|
|
1832
1832
|
contextLoader: mockDocumentLoader,
|
|
1833
|
+
// deno-lint-ignore require-await
|
|
1834
|
+
verifyPortableObject: async () => ({ verified: true }),
|
|
1833
1835
|
});
|
|
1834
1836
|
|
|
1835
1837
|
assertInstanceOf(object, Note);
|
|
@@ -4284,7 +4286,12 @@ test(
|
|
|
4284
4286
|
throw new Error("Document not found");
|
|
4285
4287
|
};
|
|
4286
4288
|
|
|
4287
|
-
const result = await create.getObject({
|
|
4289
|
+
const result = await create.getObject({
|
|
4290
|
+
documentLoader,
|
|
4291
|
+
contextLoader: mockDocumentLoader,
|
|
4292
|
+
// deno-lint-ignore require-await
|
|
4293
|
+
verifyPortableObject: async () => ({ verified: true }),
|
|
4294
|
+
});
|
|
4288
4295
|
assertInstanceOf(result, Note);
|
|
4289
4296
|
deepStrictEqual(result.content, "Fetched portable note");
|
|
4290
4297
|
},
|