@fedify/fedify 2.4.0-pr.936.41 → 2.5.0-dev.2271
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/README.md +50 -39
- package/dist/{assert-CJ1KXcvv.mjs → assert-D1Eafmd_.mjs} +1 -1
- package/dist/{assert_equals-BV7oLMxm.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
- package/dist/assert_exists-cffSpJ7X.mjs +28 -0
- package/dist/assert_false-CPdRnc3E.mjs +23 -0
- package/dist/assert_greater_or_equal-BlafOF4-.mjs +31 -0
- package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
- package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
- package/dist/assert_rejects-CTptdYck.mjs +39 -0
- package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
- package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BYITOvPO.mjs} +2 -1
- package/dist/assertion_error-B-cx0fFA.mjs +31 -0
- package/dist/audience-CHQ-FlLD.mjs +95 -0
- package/dist/{builder-DonuxRl_.mjs → builder-Bda6LK7A.mjs} +169 -14
- package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-XJ53md4S.mjs} +224 -17
- package/dist/circuit-breaker-test-utils-DW6YC_Pe.mjs +14 -0
- package/dist/{client-CjF5IYQS.mjs → client-CEnNz8O7.mjs} +144 -8
- package/dist/{codec-BBga-FWI.mjs → codec-C6rTrpIp.mjs} +26 -3
- package/dist/{collection-BIhlldqK.mjs → collection-CnnP1UAv.mjs} +1 -1
- package/dist/compat/mod.cjs +1 -1
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/mod.js +1 -1
- package/dist/compat/outgoing-jsonld.test.mjs +71 -3
- package/dist/compat/public-audience.test.mjs +14 -5
- package/dist/compat/secured-document.test.d.mts +2 -0
- package/dist/compat/secured-document.test.mjs +58 -0
- package/dist/compat/transformers.test.mjs +5 -5
- package/dist/compound-proof-B-9mXxFW.mjs +989 -0
- package/dist/{context-Zii1f5xS.d.ts → context-7NyiqIcg.d.ts} +1600 -25
- package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
- package/dist/{context-lxX6I7as.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
- package/dist/{deno-BHzKn9Ig.mjs → deno-oR5aJKpU.mjs} +1 -1
- package/dist/dist-DJQM4u7i.mjs +189 -0
- package/dist/docloader-DBoYbvYW.mjs +87 -0
- package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
- package/dist/federation/audience.test.d.mts +2 -0
- package/dist/federation/audience.test.mjs +130 -0
- package/dist/federation/builder.test.mjs +54 -5
- package/dist/federation/circuit-breaker.test.mjs +838 -7
- package/dist/federation/collection.test.mjs +3 -3
- package/dist/federation/compound-fanout.test.d.mts +2 -0
- package/dist/federation/compound-fanout.test.mjs +228 -0
- package/dist/federation/handler-compound-proof.test.d.mts +2 -0
- package/dist/federation/handler-compound-proof.test.mjs +384 -0
- package/dist/federation/handler.test.mjs +385 -15
- package/dist/federation/hashlink-media.test.d.mts +2 -0
- package/dist/federation/hashlink-media.test.mjs +422 -0
- package/dist/federation/idempotency.test.mjs +6 -6
- package/dist/federation/inbox-report.test.d.mts +2 -0
- package/dist/federation/inbox-report.test.mjs +475 -0
- package/dist/federation/inbox.test.mjs +3 -3
- package/dist/federation/keycache.test.mjs +215 -14
- package/dist/federation/kv.test.mjs +3 -3
- package/dist/federation/metrics.test.mjs +5 -5
- package/dist/federation/middleware.test.mjs +967 -35
- package/dist/federation/mod.cjs +18 -261
- package/dist/federation/mod.d.cts +5 -5
- package/dist/federation/mod.d.ts +5 -5
- package/dist/federation/mod.js +279 -1
- package/dist/federation/mq.test.mjs +123 -47
- package/dist/federation/negotiation.test.mjs +4 -4
- package/dist/federation/outgoing-proof.test.d.mts +2 -0
- package/dist/federation/outgoing-proof.test.mjs +931 -0
- package/dist/federation/portable-actor.test.d.mts +2 -0
- package/dist/federation/portable-actor.test.mjs +496 -0
- package/dist/federation/portable-chain.test.d.mts +2 -0
- package/dist/federation/portable-chain.test.mjs +370 -0
- package/dist/federation/portable-collection.test.d.mts +2 -0
- package/dist/federation/portable-collection.test.mjs +832 -0
- package/dist/federation/portable-delivery.test.d.mts +2 -0
- package/dist/federation/portable-delivery.test.mjs +746 -0
- package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
- package/dist/federation/portable-gateway-keys.test.mjs +686 -0
- package/dist/federation/portable-inbox.test.d.mts +2 -0
- package/dist/federation/portable-inbox.test.mjs +1535 -0
- package/dist/federation/portable-parse-uri.test.d.mts +2 -0
- package/dist/federation/portable-parse-uri.test.mjs +348 -0
- package/dist/federation/portable-route-activity.test.d.mts +2 -0
- package/dist/federation/portable-route-activity.test.mjs +259 -0
- package/dist/federation/portable.test.d.mts +2 -0
- package/dist/federation/portable.test.mjs +1072 -0
- package/dist/federation/retry.test.mjs +4 -3
- package/dist/federation/router.test.mjs +9 -159
- package/dist/federation/send.test.mjs +245 -27
- package/dist/federation/tasks/codec.test.mjs +4 -4
- package/dist/federation/tasks/enqueue.test.mjs +42 -4
- package/dist/federation/tasks/tasks.test.mjs +7 -6
- package/dist/federation/temporal.test.mjs +4 -4
- package/dist/federation/webfinger.test.mjs +275 -12
- package/dist/{middleware-FrSMAYEx.cjs → federation-CkZiAcWY.cjs} +8640 -3722
- package/dist/http-B5JT115n.cjs +10630 -0
- package/dist/http-DydWCB7R.js +6527 -0
- package/dist/{http-CPVMUgsW.mjs → http-siciWkmx.mjs} +397 -168
- package/dist/key-BspPiXqn.mjs +951 -0
- package/dist/key-C1nv7_jD.d.ts +1125 -0
- package/dist/key-DYxuyd-s.d.cts +1125 -0
- package/dist/key-owner-evidence-APB6NpSk.mjs +108 -0
- package/dist/keycache-Da8A8mZa.mjs +200 -0
- package/dist/{kv-D6hNiMTK.d.ts → kv-B2mzK5tl.d.cts} +3 -2
- package/dist/{kv-gJ8LYbxX.d.cts → kv-B2mzK5tl.d.ts} +3 -2
- package/dist/kv-DBRWVx3Q.mjs +104 -0
- package/dist/{kv-cache-KyGqJqSp.mjs → kv-cache-BF1hnW65.mjs} +1 -1
- package/dist/{kv-cache-5bnX3-Jq.js → kv-cache-CTQr1tbn.js} +54 -16
- package/dist/{kv-cache-DQ29C4XL.cjs → kv-cache-DCac1nEU.cjs} +55 -19
- package/dist/{ld-Cj9F_5AP.mjs → ld-CzaP-hJl.mjs} +44 -12
- package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
- package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
- package/dist/{metrics-DMk-nTxI.mjs → metrics-CYg9yxBL.mjs} +3 -2
- package/dist/metrics-DVKYY6K1.d.cts +36 -0
- package/dist/metrics-DoRtI0qU.d.ts +36 -0
- package/dist/{middleware-Y-kpsp6S.js → middleware-CsDDXKuL.js} +5493 -1103
- package/dist/{middleware-CvwTUgnP.mjs → middleware-D7_LO-Vs.mjs} +3157 -272
- package/dist/{middleware-CEctxBN6.mjs → middleware-DWjrfpcz.mjs} +1 -1
- package/dist/{mod-gOlPDuT8.d.cts → mod-BojP2Bw3.d.cts} +1 -1
- package/dist/mod-CavhAgLw.d.cts +320 -0
- package/dist/mod-CtpF2BU5.d.ts +320 -0
- package/dist/{mod-BtEaIEcD.d.cts → mod-DEZXwV6J.d.ts} +10 -4
- package/dist/{mod-UMmveiO0.d.ts → mod-Dw-nPxQh.d.cts} +10 -4
- package/dist/{mod-DLc2Ot6f.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
- package/dist/mod.cjs +40 -39
- package/dist/mod.d.cts +10 -11
- package/dist/mod.d.ts +10 -11
- package/dist/mod.js +9 -9
- package/dist/{mq-llHKivST.mjs → mq-Dm1Wmtm-.mjs} +6 -0
- package/dist/nodeinfo/client.test.mjs +139 -4
- package/dist/nodeinfo/handler.test.mjs +5 -5
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.d.cts +1 -1
- package/dist/nodeinfo/mod.d.ts +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/nodeinfo/types.test.mjs +4 -4
- package/dist/otel/exporter.test.mjs +3 -3
- package/dist/otel/mod.cjs +0 -1
- package/dist/otel/mod.d.cts +1 -1
- package/dist/otel/mod.d.ts +1 -1
- package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
- package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
- package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
- package/dist/owner-DYgfTFHy.mjs +267 -0
- package/dist/portable-collection-BpsVsRov.js +670 -0
- package/dist/portable-collection-C74P1vtC.mjs +418 -0
- package/dist/portable-collection-DZd2bm7M.cjs +686 -0
- package/dist/portable-key-BIMLrAP4.mjs +549 -0
- package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
- package/dist/proof-Dxy6ByqI.mjs +1299 -0
- package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
- package/dist/router-u5O5KCQr.mjs +156 -0
- package/dist/runtime/mod.cjs +1 -1
- package/dist/runtime/mod.js +1 -1
- package/dist/secured-document-CxzZZ9nL.mjs +35 -0
- package/dist/send-C4dDpAxm.mjs +495 -0
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
- package/dist/sig/compound-proof-discovery.test.mjs +331 -0
- package/dist/sig/compound-proof-producer.test.d.mts +2 -0
- package/dist/sig/compound-proof-producer.test.mjs +107 -0
- package/dist/sig/compound-proof-verification.test.d.mts +2 -0
- package/dist/sig/compound-proof-verification.test.mjs +833 -0
- package/dist/sig/compound-proof.test.d.mts +2 -0
- package/dist/sig/compound-proof.test.mjs +411 -0
- package/dist/sig/http.test.mjs +702 -31
- package/dist/sig/key-owner-evidence.test.d.mts +2 -0
- package/dist/sig/key-owner-evidence.test.mjs +100 -0
- package/dist/sig/key.test.mjs +220 -8
- package/dist/sig/ld.test.mjs +65 -7
- package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
- package/dist/sig/mitra-receive-interop.test.mjs +260 -0
- package/dist/sig/mitra-send-interop.test.d.mts +2 -0
- package/dist/sig/mitra-send-interop.test.mjs +461 -0
- package/dist/sig/mod.cjs +18 -16
- package/dist/sig/mod.d.cts +4 -4
- package/dist/sig/mod.d.ts +4 -4
- package/dist/sig/mod.js +3 -3
- package/dist/sig/owner.test.mjs +108 -9
- package/dist/sig/portable-collection.test.d.mts +2 -0
- package/dist/sig/portable-collection.test.mjs +697 -0
- package/dist/sig/portable-interop.test.d.mts +2 -0
- package/dist/sig/portable-interop.test.mjs +156 -0
- package/dist/sig/portable-key-id.test.d.mts +2 -0
- package/dist/sig/portable-key-id.test.mjs +67 -0
- package/dist/sig/portable-key.test.d.mts +2 -0
- package/dist/sig/portable-key.test.mjs +1439 -0
- package/dist/sig/proof.test.mjs +1753 -16
- package/dist/sig/tootik-request-interop.test.d.mts +2 -0
- package/dist/sig/tootik-request-interop.test.mjs +190 -0
- package/dist/sig/tootik-send-interop.test.d.mts +2 -0
- package/dist/sig/tootik-send-interop.test.mjs +331 -0
- package/dist/sig/verification.test.d.mts +2 -0
- package/dist/sig/verification.test.mjs +310 -0
- package/dist/std__assert-DvMDRPes.mjs +8 -0
- package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
- package/dist/{temporal-fsXO5IvD.mjs → temporal-D0KJI4NF.mjs} +3 -3
- package/dist/testing/context.test.d.mts +2 -0
- package/dist/testing/context.test.mjs +19 -0
- package/dist/testing/kv.test.d.mts +2 -0
- package/dist/testing/kv.test.mjs +101 -0
- package/dist/testing/mod.d.mts +1617 -48
- package/dist/testing/mod.mjs +6 -3
- package/dist/testing-t8xDeJZ5.mjs +8 -0
- package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
- package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
- package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
- package/dist/utils/docloader.test.mjs +530 -8
- package/dist/utils/kv-cache.test.mjs +2 -2
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/dist/verification-C3954hQh.mjs +5 -0
- package/dist/verification-Dpfcw8ml.mjs +105 -0
- package/dist/vocab/cjs.test.mjs +1 -1
- package/package.json +8 -8
- package/dist/assert_rejects-EgstcQy5.mjs +0 -82
- package/dist/docloader-e1khNUKy.mjs +0 -49
- package/dist/http-CsmQ-BQ4.js +0 -2483
- package/dist/http-VyDTd4G3.d.cts +0 -553
- package/dist/http-hlIjmewS.cjs +0 -2694
- package/dist/http-lf8Hsd91.d.ts +0 -553
- package/dist/key-DfPsX8hv.mjs +0 -453
- package/dist/keycache-_DHqz5z_.mjs +0 -97
- package/dist/metrics-CoUJLQhZ.d.cts +0 -276
- package/dist/metrics-Dc4jR-IC.d.ts +0 -276
- package/dist/mod-B0hW12_O.d.cts +0 -307
- package/dist/mod-COIAjwRS.d.ts +0 -307
- package/dist/owner-Br9YYzn_.mjs +0 -120
- package/dist/proof-B4ngoaNQ.mjs +0 -316
- package/dist/proof-B6E0XUXJ.js +0 -1415
- package/dist/proof-NN4xCQGL.cjs +0 -1562
- package/dist/send-CxHKUNzv.mjs +0 -239
- package/dist/std__assert-B2NnY9bq.mjs +0 -79
- package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
- /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
- /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
- /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
- /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
- /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
- /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
- /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
- /package/dist/{retry-DgFqeS5k.mjs → retry-zX5xw5e0.mjs} +0 -0
- /package/dist/{chunk-D5IdezsZ.js → rolldown-runtime-BC-Eo5Mj.js} +0 -0
- /package/dist/{chunk-Czpeue4M.cjs → rolldown-runtime-Dmm3t92W.cjs} +0 -0
- /package/dist/{transformers-DXze6FUB.js → transformers-DAtXl_Kc.js} +0 -0
- /package/dist/{types-CrtdVuDP.mjs → types-DE_LV1JB.mjs} +0 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { configure, getConsoleSink, getLogger, reset } from "@logtape/logtape";
|
|
6
|
+
import "@opentelemetry/sdk-trace-base";
|
|
7
|
+
import "@opentelemetry/core";
|
|
8
|
+
//#region ../fixture/dist/mod.js
|
|
9
|
+
const fixtureFetch = globalThis.fetch.bind(globalThis);
|
|
10
|
+
const logger = getLogger(["fixture", "docloader"]);
|
|
11
|
+
/**
|
|
12
|
+
* A mock of the document loader. This does not make any actual HTTP requests
|
|
13
|
+
* towards the remote server, but looks up the local fixture files instead.
|
|
14
|
+
*
|
|
15
|
+
* For instance, `mockDocumentLoader("http://example.com/foo/bar")` will look up
|
|
16
|
+
* the file `testing/fixtures/http/example.com/foo/bar` (no suffix) and return
|
|
17
|
+
* its content as the response.
|
|
18
|
+
*/
|
|
19
|
+
async function mockDocumentLoader(resource, _options) {
|
|
20
|
+
const url = new URL(resource);
|
|
21
|
+
if ("navigator" in globalThis && navigator.userAgent === "Cloudflare-Workers") {
|
|
22
|
+
const testUrl = new URL(url);
|
|
23
|
+
testUrl.hostname += ".test";
|
|
24
|
+
const resp = await fixtureFetch(testUrl);
|
|
25
|
+
if (resp.ok) {
|
|
26
|
+
const document = await resp.json();
|
|
27
|
+
logger.debug("Successfully fetched fixture {resource}: {status} {statusText}\n{body}", {
|
|
28
|
+
resource,
|
|
29
|
+
status: resp.status,
|
|
30
|
+
statusText: resp.statusText,
|
|
31
|
+
body: document
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
contextUrl: null,
|
|
35
|
+
document,
|
|
36
|
+
documentUrl: resource
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const error = await resp.text();
|
|
40
|
+
logger.error("Failed to fetch fixture {resource}: {error}", {
|
|
41
|
+
resource,
|
|
42
|
+
error
|
|
43
|
+
});
|
|
44
|
+
throw new Error(error);
|
|
45
|
+
}
|
|
46
|
+
const fixturePath = `${"Deno" in globalThis ? "." : "@fedify/fixture"}/fixtures/${url.host}${url.pathname}.json`;
|
|
47
|
+
let document;
|
|
48
|
+
try {
|
|
49
|
+
document = (await import(fixturePath, { with: { type: "json" } })).default;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
logger.error("Failed to read fixture file {path}: {error}", {
|
|
52
|
+
path: fixturePath,
|
|
53
|
+
error
|
|
54
|
+
});
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
contextUrl: null,
|
|
59
|
+
document,
|
|
60
|
+
documentUrl: resource
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const testDefinitions = [];
|
|
64
|
+
function test(name, options, fn) {
|
|
65
|
+
const def = typeof name === "string" ? typeof options === "function" ? {
|
|
66
|
+
name,
|
|
67
|
+
fn: options
|
|
68
|
+
} : {
|
|
69
|
+
name,
|
|
70
|
+
...options,
|
|
71
|
+
fn
|
|
72
|
+
} : name;
|
|
73
|
+
testDefinitions.push(def);
|
|
74
|
+
if ("Deno" in globalThis) {
|
|
75
|
+
const func = def.fn;
|
|
76
|
+
Deno.test({
|
|
77
|
+
...def,
|
|
78
|
+
async fn(t) {
|
|
79
|
+
const records = [];
|
|
80
|
+
await configure({
|
|
81
|
+
sinks: {
|
|
82
|
+
buffer(record) {
|
|
83
|
+
if (record.category.length > 1 && record.category[0] === "logtape" && record.category[1] === "meta") return;
|
|
84
|
+
records.push(record);
|
|
85
|
+
},
|
|
86
|
+
console: getConsoleSink()
|
|
87
|
+
},
|
|
88
|
+
filters: {},
|
|
89
|
+
loggers: [{
|
|
90
|
+
category: [],
|
|
91
|
+
sinks: [Deno.env.get("LOG") === "always" ? "console" : "buffer"]
|
|
92
|
+
}]
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
await func(t);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
const consoleSink = getConsoleSink();
|
|
98
|
+
for (const record of records) consoleSink(record);
|
|
99
|
+
throw e;
|
|
100
|
+
} finally {
|
|
101
|
+
await reset();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
} else if ("Bun" in globalThis) {
|
|
106
|
+
let failed = void 0;
|
|
107
|
+
async function step(defOrNameOrFn, fn) {
|
|
108
|
+
let def;
|
|
109
|
+
if (typeof defOrNameOrFn === "string") def = {
|
|
110
|
+
name: defOrNameOrFn,
|
|
111
|
+
fn
|
|
112
|
+
};
|
|
113
|
+
else if (typeof defOrNameOrFn === "function") def = {
|
|
114
|
+
name: defOrNameOrFn.name,
|
|
115
|
+
fn: defOrNameOrFn
|
|
116
|
+
};
|
|
117
|
+
else def = defOrNameOrFn;
|
|
118
|
+
if (def.ignore) return false;
|
|
119
|
+
try {
|
|
120
|
+
await def.fn({
|
|
121
|
+
name: def.name,
|
|
122
|
+
origin: "",
|
|
123
|
+
step
|
|
124
|
+
});
|
|
125
|
+
} catch (e) {
|
|
126
|
+
failed ??= e;
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
const ctx = {
|
|
132
|
+
name: def.name,
|
|
133
|
+
origin: "",
|
|
134
|
+
step
|
|
135
|
+
};
|
|
136
|
+
async function fn() {
|
|
137
|
+
await def.fn(ctx);
|
|
138
|
+
if (failed) throw failed;
|
|
139
|
+
}
|
|
140
|
+
const bunTest = Bun.jest(caller()).test;
|
|
141
|
+
if (def.ignore) bunTest.skip(def.name, fn);
|
|
142
|
+
else bunTest(def.name, fn);
|
|
143
|
+
} else if (typeof process !== "undefined" && process.release?.name === "node" && !("navigator" in globalThis && navigator.userAgent === "Cloudflare-Workers")) {
|
|
144
|
+
const { test: nodeTest } = createRequire(process.cwd() + "/")("node:test");
|
|
145
|
+
nodeTest(def.name, { skip: def.ignore }, async (t) => {
|
|
146
|
+
await def.fn(intoTestContext(def.name, t));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function intoTestContext(name, ctx) {
|
|
151
|
+
async function step(defOrNameOrFn, fn) {
|
|
152
|
+
let def;
|
|
153
|
+
if (typeof defOrNameOrFn === "string") def = {
|
|
154
|
+
name: defOrNameOrFn,
|
|
155
|
+
fn
|
|
156
|
+
};
|
|
157
|
+
else if (typeof defOrNameOrFn === "function") def = {
|
|
158
|
+
name: defOrNameOrFn.name,
|
|
159
|
+
fn: defOrNameOrFn
|
|
160
|
+
};
|
|
161
|
+
else def = defOrNameOrFn;
|
|
162
|
+
let failed = false;
|
|
163
|
+
await ctx.test(def.name, { skip: def.ignore }, async (ctx2) => {
|
|
164
|
+
try {
|
|
165
|
+
await def.fn(intoTestContext(def.name, ctx2));
|
|
166
|
+
} catch (e) {
|
|
167
|
+
failed = true;
|
|
168
|
+
throw e;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return !def.ignore && !failed;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
name,
|
|
175
|
+
origin: ctx.filePath ?? "",
|
|
176
|
+
step
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/** Retrieve caller test file. */
|
|
180
|
+
function caller() {
|
|
181
|
+
const Trace = Error;
|
|
182
|
+
const _ = Trace.prepareStackTrace;
|
|
183
|
+
Trace.prepareStackTrace = (_, stack) => stack;
|
|
184
|
+
const { stack } = /* @__PURE__ */ new Error();
|
|
185
|
+
Trace.prepareStackTrace = _;
|
|
186
|
+
return stack[2].getFileName().replaceAll("\\", "/");
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { test as n, testDefinitions as r, mockDocumentLoader as t };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { c as validateCryptoKey } from "./key-BspPiXqn.mjs";
|
|
5
|
+
import { n as doubleKnock } from "./http-siciWkmx.mjs";
|
|
6
|
+
import { getLogger } from "@logtape/logtape";
|
|
7
|
+
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, resolveDocumentLoaderTimeout, validatePublicUrl, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
|
|
8
|
+
import { curry } from "es-toolkit";
|
|
9
|
+
//#region src/utils/docloader.ts
|
|
10
|
+
const logger = getLogger([
|
|
11
|
+
"fedify",
|
|
12
|
+
"utils",
|
|
13
|
+
"docloader"
|
|
14
|
+
]);
|
|
15
|
+
const DEFAULT_MAX_REDIRECTION = 20;
|
|
16
|
+
/**
|
|
17
|
+
* Gets an authenticated {@link DocumentLoader} for the given identity.
|
|
18
|
+
* Note that an authenticated document loader intentionally does not cache
|
|
19
|
+
* the fetched documents.
|
|
20
|
+
* At most 20 HTTP redirects and alternate document links are followed in total
|
|
21
|
+
* per call. Revisiting a URL within that chain throws a {@link FetchError}.
|
|
22
|
+
* Each call, including its double-knocking retries, times out after
|
|
23
|
+
* 10 seconds by default; see {@link DocumentLoaderFactoryOptions.timeout}.
|
|
24
|
+
* @param identity The identity to get the document loader for.
|
|
25
|
+
* The actor's key pair.
|
|
26
|
+
* @param options The options for the document loader.
|
|
27
|
+
* @returns The authenticated document loader.
|
|
28
|
+
* @throws {TypeError} If the key is invalid or unsupported.
|
|
29
|
+
* @throws {RangeError} If the `timeout` option is invalid.
|
|
30
|
+
* @since 0.4.0
|
|
31
|
+
*/
|
|
32
|
+
function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, timeout, tracerProvider } = {}) {
|
|
33
|
+
validateCryptoKey(identity.privateKey);
|
|
34
|
+
const resolvedTimeout = resolveDocumentLoaderTimeout(timeout);
|
|
35
|
+
async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
|
|
36
|
+
options?.signal?.throwIfAborted();
|
|
37
|
+
let currentUrl = new URL(url).href;
|
|
38
|
+
await validateUrl(currentUrl, options);
|
|
39
|
+
visited.add(currentUrl);
|
|
40
|
+
const originalRequest = createActivityPubRequest(currentUrl, { userAgent });
|
|
41
|
+
function follow(nextUrl) {
|
|
42
|
+
options?.signal?.throwIfAborted();
|
|
43
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
44
|
+
if (visited.has(nextUrl)) throw new FetchError(currentUrl, `Redirect loop detected: ${nextUrl}`);
|
|
45
|
+
redirected++;
|
|
46
|
+
}
|
|
47
|
+
const response = await doubleKnock(originalRequest, identity, {
|
|
48
|
+
maxRedirection,
|
|
49
|
+
specDeterminer,
|
|
50
|
+
log: curry(logRequest)(logger),
|
|
51
|
+
tracerProvider,
|
|
52
|
+
signal: options?.signal,
|
|
53
|
+
validateRedirect: async (nextUrl) => {
|
|
54
|
+
follow(nextUrl);
|
|
55
|
+
await validateUrl(nextUrl, options);
|
|
56
|
+
visited.add(nextUrl);
|
|
57
|
+
currentUrl = nextUrl;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
options?.signal?.throwIfAborted();
|
|
61
|
+
return getRemoteDocument(currentUrl, response, (alternateUrl) => {
|
|
62
|
+
follow(alternateUrl);
|
|
63
|
+
return load(alternateUrl, options, redirected, visited);
|
|
64
|
+
}, options);
|
|
65
|
+
}
|
|
66
|
+
async function validateUrl(url, options) {
|
|
67
|
+
if (!allowPrivateAddress) {
|
|
68
|
+
try {
|
|
69
|
+
await validatePublicUrl(url);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
72
|
+
url,
|
|
73
|
+
error
|
|
74
|
+
});
|
|
75
|
+
else logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
76
|
+
url,
|
|
77
|
+
error
|
|
78
|
+
});
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
options?.signal?.throwIfAborted();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return withDocumentLoaderTimeout((url, options) => load(url, options), resolvedTimeout);
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
export { getAuthenticatedDocumentLoader as t };
|
|
@@ -129,27 +129,27 @@ function parse(input, loose) {
|
|
|
129
129
|
}
|
|
130
130
|
//#endregion
|
|
131
131
|
//#region ../../node_modules/.pnpm/fetch-mock@12.6.0/node_modules/fetch-mock/dist/esm/TypeDescriptor.js
|
|
132
|
-
const valueTypes = new Set([
|
|
132
|
+
const valueTypes = /* @__PURE__ */ new Set([
|
|
133
133
|
"boolean",
|
|
134
134
|
"number",
|
|
135
135
|
"null",
|
|
136
136
|
"string",
|
|
137
137
|
"undefined"
|
|
138
138
|
]);
|
|
139
|
-
const referenceTypes = new Set([
|
|
139
|
+
const referenceTypes = /* @__PURE__ */ new Set([
|
|
140
140
|
"array",
|
|
141
141
|
"function",
|
|
142
142
|
"object",
|
|
143
143
|
"symbol"
|
|
144
144
|
]);
|
|
145
|
-
const detectableTypes = new Set([
|
|
145
|
+
const detectableTypes = /* @__PURE__ */ new Set([
|
|
146
146
|
"boolean",
|
|
147
147
|
"function",
|
|
148
148
|
"number",
|
|
149
149
|
"string",
|
|
150
150
|
"symbol"
|
|
151
151
|
]);
|
|
152
|
-
const typeConstructors = new Set([
|
|
152
|
+
const typeConstructors = /* @__PURE__ */ new Set([
|
|
153
153
|
Boolean,
|
|
154
154
|
Number,
|
|
155
155
|
String
|
|
@@ -220,7 +220,7 @@ var TypeDescriptor = class TypeDescriptor {
|
|
|
220
220
|
};
|
|
221
221
|
//#endregion
|
|
222
222
|
//#region ../../node_modules/.pnpm/fetch-mock@12.6.0/node_modules/fetch-mock/dist/esm/IsSubsetOf.js
|
|
223
|
-
const allowedTypes = new Set([
|
|
223
|
+
const allowedTypes = /* @__PURE__ */ new Set([
|
|
224
224
|
"array",
|
|
225
225
|
"object",
|
|
226
226
|
"function",
|
|
@@ -712,7 +712,14 @@ var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
|
712
712
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
713
713
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
714
714
|
};
|
|
715
|
-
var _Route_instances
|
|
715
|
+
var _Route_instances;
|
|
716
|
+
var _a;
|
|
717
|
+
var _Route_responseSubscriptions;
|
|
718
|
+
var _Route_validate;
|
|
719
|
+
var _Route_sanitize;
|
|
720
|
+
var _Route_generateMatcher;
|
|
721
|
+
var _Route_limit;
|
|
722
|
+
var _Route_delayResponse;
|
|
716
723
|
var RouteConfigWrapper = class {
|
|
717
724
|
constructor(config) {
|
|
718
725
|
Object.assign(this, config);
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { n as isPubliclyAddressedNode, t as isInAudience } from "../audience-CHQ-FlLD.mjs";
|
|
5
|
+
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
|
+
import "../std__assert-DvMDRPes.mjs";
|
|
7
|
+
import { Note, PUBLIC_COLLECTION, Person } from "@fedify/vocab";
|
|
8
|
+
import { parseIri, toCompatibleEf61Id } from "@fedify/vocab-runtime";
|
|
9
|
+
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
10
|
+
import jsonld from "@fedify/vocab-runtime/jsonld";
|
|
11
|
+
//#region src/federation/audience.test.ts
|
|
12
|
+
const did = "did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2";
|
|
13
|
+
async function expand(document) {
|
|
14
|
+
const [node] = await jsonld.expand({
|
|
15
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
16
|
+
id: "https://example.com/notes/1",
|
|
17
|
+
type: "Note",
|
|
18
|
+
...document
|
|
19
|
+
}, { documentLoader: mockDocumentLoader });
|
|
20
|
+
return node;
|
|
21
|
+
}
|
|
22
|
+
test("isPubliclyAddressedNode()", async (t) => {
|
|
23
|
+
for (const property of [
|
|
24
|
+
"to",
|
|
25
|
+
"cc",
|
|
26
|
+
"bto",
|
|
27
|
+
"bcc",
|
|
28
|
+
"audience"
|
|
29
|
+
]) for (const value of [
|
|
30
|
+
PUBLIC_COLLECTION.href,
|
|
31
|
+
"as:Public",
|
|
32
|
+
"Public",
|
|
33
|
+
["https://example.com/person", "as:Public"]
|
|
34
|
+
]) await t.step(`${JSON.stringify(value)} in ${property}`, async () => {
|
|
35
|
+
assertEquals(isPubliclyAddressedNode(await expand({ [property]: value })), true);
|
|
36
|
+
});
|
|
37
|
+
await t.step("not addressed", async () => {
|
|
38
|
+
assertEquals(isPubliclyAddressedNode(await expand({})), false);
|
|
39
|
+
});
|
|
40
|
+
await t.step("addressed to other recipients", async () => {
|
|
41
|
+
assertEquals(isPubliclyAddressedNode(await expand({
|
|
42
|
+
to: "https://example.com/person",
|
|
43
|
+
cc: "https://example.com/person/followers"
|
|
44
|
+
})), false);
|
|
45
|
+
});
|
|
46
|
+
await t.step("Public in other properties", async () => {
|
|
47
|
+
assertEquals(isPubliclyAddressedNode(await expand({ tag: PUBLIC_COLLECTION.href })), false);
|
|
48
|
+
});
|
|
49
|
+
await t.step("a Public literal rather than an ID", async () => {
|
|
50
|
+
assertEquals(isPubliclyAddressedNode(await expand({ to: { "@value": PUBLIC_COLLECTION.href } })), false);
|
|
51
|
+
});
|
|
52
|
+
await t.step("Public that the context maps elsewhere", async () => {
|
|
53
|
+
for (const [context, to] of [[{ as: "https://example.com/ns#" }, "as:Public"], [{ "@base": "https://example.com/" }, "Public"]]) {
|
|
54
|
+
const [node] = await jsonld.expand({
|
|
55
|
+
"@context": ["https://www.w3.org/ns/activitystreams", context],
|
|
56
|
+
id: "https://example.com/notes/1",
|
|
57
|
+
type: "Note",
|
|
58
|
+
to
|
|
59
|
+
}, { documentLoader: mockDocumentLoader });
|
|
60
|
+
assertEquals(isPubliclyAddressedNode(node), false, JSON.stringify(context));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
await t.step("only the node itself is checked", async () => {
|
|
64
|
+
assertEquals(isPubliclyAddressedNode(await expand({
|
|
65
|
+
type: "Create",
|
|
66
|
+
actor: "https://example.com/person",
|
|
67
|
+
object: {
|
|
68
|
+
type: "Note",
|
|
69
|
+
id: "https://example.com/notes/2",
|
|
70
|
+
to: PUBLIC_COLLECTION.href
|
|
71
|
+
}
|
|
72
|
+
})), false);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
test("isInAudience()", async (t) => {
|
|
76
|
+
const person = new Person({ id: new URL("https://example.com/person") });
|
|
77
|
+
const portableId = parseIri(`ap+ef61://${did}/actor`);
|
|
78
|
+
const portable = new Person({ id: toCompatibleEf61Id(portableId, "https://other.example") });
|
|
79
|
+
const followers = new URL("https://example.com/person2/followers");
|
|
80
|
+
await t.step("publicly addressed", async () => {
|
|
81
|
+
for (const actor of [null, person]) assertEquals(await isInAudience(new Note({ cc: PUBLIC_COLLECTION }), actor), true);
|
|
82
|
+
});
|
|
83
|
+
await t.step("no actor", async () => {
|
|
84
|
+
assertEquals(await isInAudience(new Note({ to: person.id }), null), false);
|
|
85
|
+
assertEquals(await isInAudience(new Note({}), null), false);
|
|
86
|
+
});
|
|
87
|
+
await t.step("directly addressed", async () => {
|
|
88
|
+
for (const property of [
|
|
89
|
+
"to",
|
|
90
|
+
"cc",
|
|
91
|
+
"bto",
|
|
92
|
+
"bcc",
|
|
93
|
+
"audience"
|
|
94
|
+
]) assertEquals(await isInAudience(new Note({ [property]: person.id }), person), true, property);
|
|
95
|
+
});
|
|
96
|
+
await t.step("not addressed", async () => {
|
|
97
|
+
assertEquals(await isInAudience(new Note({ to: new URL("https://example.com/other") }), person), false);
|
|
98
|
+
assertEquals(await isInAudience(new Note({ to: person.id }), new Person({})), false);
|
|
99
|
+
});
|
|
100
|
+
await t.step("portable IDs are compared canonically", async () => {
|
|
101
|
+
for (const addressee of [
|
|
102
|
+
portableId,
|
|
103
|
+
parseIri(`ap://${did}/actor`),
|
|
104
|
+
parseIri(`ap+ef61://${did.replaceAll(":", "%3A")}/actor`),
|
|
105
|
+
toCompatibleEf61Id(portableId, "https://example.com")
|
|
106
|
+
]) assertEquals(await isInAudience(new Note({ to: addressee }), portable), true, addressee.href);
|
|
107
|
+
assertEquals(await isInAudience(new Note({ to: parseIri(`ap+ef61://${did}/other`) }), portable), false);
|
|
108
|
+
assertEquals(await isInAudience(new Note({ to: new URL(`https://other.example/${did}/actor`) }), portable), false);
|
|
109
|
+
});
|
|
110
|
+
await t.step("isMember()", async () => {
|
|
111
|
+
const calls = [];
|
|
112
|
+
const isMember = (addressee, actor) => {
|
|
113
|
+
calls.push(`${addressee.href} ${actor.id?.href}`);
|
|
114
|
+
return addressee.href === followers.href;
|
|
115
|
+
};
|
|
116
|
+
const note = new Note({
|
|
117
|
+
to: new URL("https://example.com/other"),
|
|
118
|
+
cc: followers
|
|
119
|
+
});
|
|
120
|
+
assertEquals(await isInAudience(note, person, { isMember }), true);
|
|
121
|
+
assertEquals(calls, [`https://example.com/other ${person.id?.href}`, `${followers.href} ${person.id?.href}`]);
|
|
122
|
+
calls.length = 0;
|
|
123
|
+
assertEquals(await isInAudience(new Note({ to: person.id }), person, { isMember }), true);
|
|
124
|
+
assertEquals(await isInAudience(note, null, { isMember }), false);
|
|
125
|
+
assertEquals(calls, []);
|
|
126
|
+
assertEquals(await isInAudience(note, person, { isMember: () => false }), false);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
//#endregion
|
|
130
|
+
export {};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { t as MemoryKvStore } from "../kv-
|
|
5
|
-
import { t as assertEquals } from "../assert_equals-
|
|
6
|
-
import {
|
|
7
|
-
import { t as assertThrows } from "../assert_throws-
|
|
8
|
-
import
|
|
4
|
+
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
5
|
+
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
|
+
import { t as assertExists } from "../assert_exists-cffSpJ7X.mjs";
|
|
7
|
+
import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
|
|
8
|
+
import "../std__assert-DvMDRPes.mjs";
|
|
9
|
+
import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
|
|
10
|
+
import { r as createFederationBuilder } from "../builder-Bda6LK7A.mjs";
|
|
9
11
|
import { DisallowedOperatorError, DisallowedVarSpecModifierError, DuplicateRouteVariableError, RouteTemplateOptionsNotMatchedError, RouterError } from "@fedify/uri-template";
|
|
10
12
|
import { Activity, Note, Person } from "@fedify/vocab";
|
|
11
13
|
import { test } from "@fedify/fixture";
|
|
@@ -342,6 +344,53 @@ test("FederationBuilder", async (t) => {
|
|
|
342
344
|
});
|
|
343
345
|
builder.setCollectionDispatcher(strId, Note, "/string-id/{id}", dispatcher);
|
|
344
346
|
});
|
|
347
|
+
await t.step("propagates custom collection dispatchers to the built federation", async () => {
|
|
348
|
+
const kv = new MemoryKvStore();
|
|
349
|
+
const builder = createFederationBuilder();
|
|
350
|
+
builder.setCollectionDispatcher("test", Note, "/c/{id}", () => ({ items: [] }));
|
|
351
|
+
const impl = await builder.build({
|
|
352
|
+
kv,
|
|
353
|
+
origin: "https://example.com"
|
|
354
|
+
});
|
|
355
|
+
assertExists(impl.collectionCallbacks["test"]);
|
|
356
|
+
assertEquals(impl.collectionTypeIds["test"], Note);
|
|
357
|
+
assertEquals((await impl.fetch(new Request("https://example.com/c/x", { headers: { accept: "application/activity+json" } }), { contextData: void 0 })).status, 200);
|
|
358
|
+
});
|
|
359
|
+
await t.step("preserves symbol-named collections through build()", async () => {
|
|
360
|
+
const builder = createFederationBuilder();
|
|
361
|
+
const collection = Symbol("saved");
|
|
362
|
+
const ordered = Symbol("saved");
|
|
363
|
+
builder.setCollectionDispatcher(collection, Note, "/users/{identifier}/saved", () => ({ items: [] }));
|
|
364
|
+
builder.setOrderedCollectionDispatcher(ordered, Note, "/users/{identifier}/ordered-saved", () => ({ items: [] }));
|
|
365
|
+
for (let build = 0; build < 2; build++) {
|
|
366
|
+
const federation = await builder.build({ kv: new MemoryKvStore() });
|
|
367
|
+
const ctx = federation.createContext(new URL("https://example.com/"));
|
|
368
|
+
for (const [name, path, type] of [[
|
|
369
|
+
collection,
|
|
370
|
+
"/users/alice/saved",
|
|
371
|
+
"collection"
|
|
372
|
+
], [
|
|
373
|
+
ordered,
|
|
374
|
+
"/users/alice/ordered-saved",
|
|
375
|
+
"orderedCollection"
|
|
376
|
+
]]) {
|
|
377
|
+
const uri = ctx.getCollectionUri(name, { identifier: "alice" });
|
|
378
|
+
assertEquals(uri.pathname, path);
|
|
379
|
+
const parsed = ctx.parseUri(uri);
|
|
380
|
+
assertEquals(parsed?.type, type);
|
|
381
|
+
if (parsed?.type !== "collection" && parsed?.type !== "orderedCollection") throw new Error("Expected a custom collection URI");
|
|
382
|
+
assertStrictEquals(parsed.name, name);
|
|
383
|
+
assertStrictEquals(parsed.class, Note);
|
|
384
|
+
assertEquals(parsed.values, { identifier: "alice" });
|
|
385
|
+
for (const cursor of [null, "next"]) {
|
|
386
|
+
const pageUri = new URL(uri);
|
|
387
|
+
if (cursor != null) pageUri.searchParams.set("cursor", cursor);
|
|
388
|
+
assertEquals((await federation.fetch(new Request(pageUri, { headers: { accept: "application/activity+json" } }), { contextData: void 0 })).status, 200);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
assertThrows(() => federation.setCollectionDispatcher(collection, Note, "/users/{identifier}/duplicate", () => ({ items: [] })));
|
|
392
|
+
}
|
|
393
|
+
});
|
|
345
394
|
});
|
|
346
395
|
//#endregion
|
|
347
396
|
export {};
|