@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
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { t as esm_default } from "../esm-
|
|
5
|
-
import { t as assertEquals } from "../assert_equals-
|
|
6
|
-
import "../std__assert-
|
|
7
|
-
import { t as assertRejects } from "../assert_rejects-
|
|
8
|
-
import {
|
|
9
|
-
import { i as rsaPrivateKey2 } from "../keys-
|
|
10
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
4
|
+
import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
|
|
5
|
+
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
|
+
import "../std__assert-DvMDRPes.mjs";
|
|
7
|
+
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
8
|
+
import { f as verifyRequest } from "../http-siciWkmx.mjs";
|
|
9
|
+
import { i as rsaPrivateKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
10
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-DBoYbvYW.mjs";
|
|
11
|
+
import { configure, reset } from "@logtape/logtape";
|
|
12
|
+
import { FetchError, UrlError } from "@fedify/vocab-runtime";
|
|
11
13
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
|
-
import
|
|
14
|
+
import dns from "node:dns/promises";
|
|
15
|
+
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
13
16
|
//#region src/utils/docloader.test.ts
|
|
14
17
|
test("getAuthenticatedDocumentLoader()", async (t) => {
|
|
15
18
|
esm_default.spyGlobal();
|
|
@@ -63,6 +66,39 @@ test("getAuthenticatedDocumentLoader()", async (t) => {
|
|
|
63
66
|
esm_default.hardReset();
|
|
64
67
|
});
|
|
65
68
|
});
|
|
69
|
+
test("getAuthenticatedDocumentLoader() validates redirects", async (t) => {
|
|
70
|
+
esm_default.spyGlobal();
|
|
71
|
+
let privateRequestCount = 0;
|
|
72
|
+
esm_default.get("https://example.com/redirect-to-private", () => Response.redirect("http://localhost/private", 302));
|
|
73
|
+
esm_default.get("http://localhost/private", () => {
|
|
74
|
+
privateRequestCount++;
|
|
75
|
+
return Response.json({ private: true });
|
|
76
|
+
});
|
|
77
|
+
await t.step("deny public-to-private redirects", async () => {
|
|
78
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
79
|
+
keyId: new URL("https://example.com/key2"),
|
|
80
|
+
privateKey: rsaPrivateKey2
|
|
81
|
+
});
|
|
82
|
+
await assertRejects(() => loader("https://example.com/redirect-to-private"), UrlError);
|
|
83
|
+
assertEquals(privateRequestCount, 0);
|
|
84
|
+
});
|
|
85
|
+
esm_default.get("https://example.com/redirect-to-public", () => Response.redirect("https://www.example.com/document", 302));
|
|
86
|
+
esm_default.get("https://www.example.com/document", () => Response.json({ public: true }));
|
|
87
|
+
await t.step("allow public-to-public redirects", async () => {
|
|
88
|
+
assertEquals((await getAuthenticatedDocumentLoader({
|
|
89
|
+
keyId: new URL("https://example.com/key2"),
|
|
90
|
+
privateKey: rsaPrivateKey2
|
|
91
|
+
})("https://example.com/redirect-to-public")).document, { public: true });
|
|
92
|
+
});
|
|
93
|
+
await t.step("allow private redirects when explicitly enabled", async () => {
|
|
94
|
+
assertEquals((await getAuthenticatedDocumentLoader({
|
|
95
|
+
keyId: new URL("https://example.com/key2"),
|
|
96
|
+
privateKey: rsaPrivateKey2
|
|
97
|
+
}, { allowPrivateAddress: true })("https://example.com/redirect-to-private")).document, { private: true });
|
|
98
|
+
assertEquals(privateRequestCount, 1);
|
|
99
|
+
});
|
|
100
|
+
esm_default.hardReset();
|
|
101
|
+
});
|
|
66
102
|
test("getAuthenticatedDocumentLoader() cancellation", {
|
|
67
103
|
sanitizeResources: false,
|
|
68
104
|
sanitizeOps: false
|
|
@@ -103,5 +139,491 @@ test("getAuthenticatedDocumentLoader() cancellation", {
|
|
|
103
139
|
});
|
|
104
140
|
esm_default.hardReset();
|
|
105
141
|
});
|
|
142
|
+
test("getAuthenticatedDocumentLoader() bounds JSON after redirects", async () => {
|
|
143
|
+
esm_default.mockGlobal();
|
|
144
|
+
let oversized = true;
|
|
145
|
+
try {
|
|
146
|
+
const url = "https://example.com/bounded";
|
|
147
|
+
esm_default.get(url, {
|
|
148
|
+
status: 302,
|
|
149
|
+
headers: { Location: `${url}/document` }
|
|
150
|
+
});
|
|
151
|
+
esm_default.get(`${url}/document`, () => new Response("{\"name\":\"hello\"}", { headers: {
|
|
152
|
+
"Content-Type": "application/activity+json",
|
|
153
|
+
...oversized ? { "Content-Length": String(16777217) } : {}
|
|
154
|
+
} }));
|
|
155
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
156
|
+
privateKey: rsaPrivateKey2,
|
|
157
|
+
keyId: new URL("https://example.com/key2")
|
|
158
|
+
}, { allowPrivateAddress: true });
|
|
159
|
+
await assertRejects(() => loader(url), FetchError);
|
|
160
|
+
oversized = false;
|
|
161
|
+
assertEquals((await loader(url)).document, { name: "hello" });
|
|
162
|
+
} finally {
|
|
163
|
+
esm_default.hardReset();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
test("authenticated document loader suppresses HTTP failure logs", async () => {
|
|
167
|
+
const records = [];
|
|
168
|
+
const url = "https://example.com/missing-authenticated-document";
|
|
169
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
170
|
+
keyId: new URL("https://example.com/key2"),
|
|
171
|
+
privateKey: rsaPrivateKey2
|
|
172
|
+
}, { allowPrivateAddress: true });
|
|
173
|
+
await reset();
|
|
174
|
+
await configure({
|
|
175
|
+
sinks: { capture: (record) => records.push(record) },
|
|
176
|
+
loggers: [{
|
|
177
|
+
category: ["fedify"],
|
|
178
|
+
lowestLevel: "debug",
|
|
179
|
+
sinks: ["capture"]
|
|
180
|
+
}]
|
|
181
|
+
});
|
|
182
|
+
esm_default.mockGlobal();
|
|
183
|
+
esm_default.get(url, { status: 404 });
|
|
184
|
+
try {
|
|
185
|
+
for (const suppressError of [
|
|
186
|
+
true,
|
|
187
|
+
false,
|
|
188
|
+
void 0
|
|
189
|
+
]) {
|
|
190
|
+
records.length = 0;
|
|
191
|
+
assertEquals((await assertRejects(() => loader(url, { suppressError }), FetchError)).response?.status, 404);
|
|
192
|
+
const failures = records.filter((record) => record.rawMessage === "Failed to fetch document: {status} {url} {headers}");
|
|
193
|
+
assertEquals(failures.length, 1);
|
|
194
|
+
assertEquals(failures[0].level, suppressError ? "warning" : "error");
|
|
195
|
+
if (suppressError) assertEquals(records.filter((record) => record.level === "error"), []);
|
|
196
|
+
}
|
|
197
|
+
} finally {
|
|
198
|
+
esm_default.hardReset();
|
|
199
|
+
await reset();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
test("authenticated document loader suppresses private URL logs", async () => {
|
|
203
|
+
const records = [];
|
|
204
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
205
|
+
keyId: new URL("https://example.com/key2"),
|
|
206
|
+
privateKey: rsaPrivateKey2
|
|
207
|
+
});
|
|
208
|
+
await reset();
|
|
209
|
+
await configure({
|
|
210
|
+
sinks: { capture: (record) => {
|
|
211
|
+
records.push(record);
|
|
212
|
+
} },
|
|
213
|
+
loggers: [{
|
|
214
|
+
category: ["fedify"],
|
|
215
|
+
lowestLevel: "debug",
|
|
216
|
+
sinks: ["capture"]
|
|
217
|
+
}]
|
|
218
|
+
});
|
|
219
|
+
esm_default.spyGlobal();
|
|
220
|
+
let requests = 0;
|
|
221
|
+
esm_default.get("https://example.com/private-redirect", () => {
|
|
222
|
+
requests++;
|
|
223
|
+
return Response.redirect("http://127.0.0.1/private", 302);
|
|
224
|
+
});
|
|
225
|
+
try {
|
|
226
|
+
for (const url of ["http://127.0.0.1/private", "https://example.com/private-redirect"]) for (const suppressError of [
|
|
227
|
+
true,
|
|
228
|
+
false,
|
|
229
|
+
void 0
|
|
230
|
+
]) {
|
|
231
|
+
records.length = 0;
|
|
232
|
+
requests = 0;
|
|
233
|
+
await assertRejects(() => loader(url, { suppressError }), UrlError);
|
|
234
|
+
const failures = records.filter((r) => r.rawMessage === "Disallowed private URL: {url}");
|
|
235
|
+
assertEquals(failures.length, 1);
|
|
236
|
+
assertEquals(failures[0].level, suppressError ? "warning" : "error");
|
|
237
|
+
assertEquals(requests, url.startsWith("http://127") ? 0 : 1);
|
|
238
|
+
}
|
|
239
|
+
} finally {
|
|
240
|
+
esm_default.hardReset();
|
|
241
|
+
await reset();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
test("getAuthenticatedDocumentLoader() logs DNS failures as such", { ignore: "Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted" }, async (t) => {
|
|
245
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
246
|
+
keyId: new URL("https://example.com/key2"),
|
|
247
|
+
privateKey: rsaPrivateKey2
|
|
248
|
+
});
|
|
249
|
+
for (const result of [
|
|
250
|
+
"throws",
|
|
251
|
+
"empty",
|
|
252
|
+
"private"
|
|
253
|
+
]) await t.step(result, async () => {
|
|
254
|
+
const originalLookup = dns.lookup;
|
|
255
|
+
dns.lookup = (() => result === "throws" ? Promise.reject(/* @__PURE__ */ new Error("Resolver unavailable")) : Promise.resolve(result === "empty" ? [] : [{
|
|
256
|
+
address: "127.0.0.1",
|
|
257
|
+
family: 4
|
|
258
|
+
}]));
|
|
259
|
+
const records = [];
|
|
260
|
+
await configure({
|
|
261
|
+
sinks: { buffer: (record) => records.push(record) },
|
|
262
|
+
loggers: [{
|
|
263
|
+
category: "fedify",
|
|
264
|
+
sinks: ["buffer"],
|
|
265
|
+
lowestLevel: "debug"
|
|
266
|
+
}, {
|
|
267
|
+
category: ["logtape", "meta"],
|
|
268
|
+
sinks: []
|
|
269
|
+
}],
|
|
270
|
+
reset: true
|
|
271
|
+
});
|
|
272
|
+
try {
|
|
273
|
+
const url = "https://dns-failure.invalid/object";
|
|
274
|
+
const error = await assertRejects(() => loader(url), UrlError);
|
|
275
|
+
assertEquals(error.reason, result === "private" ? "disallowed" : "dns");
|
|
276
|
+
assertEquals(records.map((r) => [
|
|
277
|
+
r.level,
|
|
278
|
+
r.rawMessage,
|
|
279
|
+
r.properties.url
|
|
280
|
+
]), [result === "private" ? [
|
|
281
|
+
"error",
|
|
282
|
+
"Disallowed private URL: {url}",
|
|
283
|
+
url
|
|
284
|
+
] : [
|
|
285
|
+
"debug",
|
|
286
|
+
"DNS lookup failed for {url}",
|
|
287
|
+
url
|
|
288
|
+
]]);
|
|
289
|
+
assertEquals(records[0].properties.error, error);
|
|
290
|
+
} finally {
|
|
291
|
+
await reset();
|
|
292
|
+
dns.lookup = originalLookup;
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
test("getAuthenticatedDocumentLoader() bounds alternate document chains", async (t) => {
|
|
297
|
+
const base = "https://example.com/alternate-chain/";
|
|
298
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
299
|
+
keyId: new URL("https://example.com/key2"),
|
|
300
|
+
privateKey: rsaPrivateKey2
|
|
301
|
+
}, { allowPrivateAddress: true });
|
|
302
|
+
for (const mode of [
|
|
303
|
+
"header",
|
|
304
|
+
"html",
|
|
305
|
+
"mixed"
|
|
306
|
+
]) for (const hops of [20, 21]) await t.step(`${mode}: ${hops} hops`, async () => {
|
|
307
|
+
esm_default.mockGlobal();
|
|
308
|
+
let requests = 0;
|
|
309
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
310
|
+
requests++;
|
|
311
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
312
|
+
if (index === hops || requests > 30) return Response.json({ done: true });
|
|
313
|
+
const next = `${base}${index + 1}`;
|
|
314
|
+
if (mode === "mixed" && index % 2 === 1) return Response.redirect(next, 302);
|
|
315
|
+
return alternate(next, mode === "html");
|
|
316
|
+
});
|
|
317
|
+
try {
|
|
318
|
+
if (hops === 20) deepStrictEqual((await loader(`${base}0`)).document, { done: true });
|
|
319
|
+
else await rejects(loader(`${base}0`), (error) => {
|
|
320
|
+
ok(error instanceof FetchError);
|
|
321
|
+
ok(error.message.includes("Too many redirections (21)"));
|
|
322
|
+
return true;
|
|
323
|
+
});
|
|
324
|
+
deepStrictEqual(requests, 21);
|
|
325
|
+
} finally {
|
|
326
|
+
esm_default.hardReset();
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
for (const mode of [
|
|
330
|
+
"header",
|
|
331
|
+
"html",
|
|
332
|
+
"alternate-redirect",
|
|
333
|
+
"redirect-alternate",
|
|
334
|
+
"redirect-intermediate"
|
|
335
|
+
]) await t.step(`${mode}: cycle`, async () => {
|
|
336
|
+
esm_default.mockGlobal();
|
|
337
|
+
let requests = 0;
|
|
338
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
339
|
+
requests++;
|
|
340
|
+
if (requests > 30) return Response.json({ stopped: true });
|
|
341
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
342
|
+
const next = `${base}${mode === "redirect-intermediate" ? index === 0 ? 1 : index === 1 ? 2 : 1 : 1 - index}`;
|
|
343
|
+
if (mode === "alternate-redirect" && index === 1 || (mode === "redirect-alternate" || mode === "redirect-intermediate") && index === 0) return Response.redirect(next, 302);
|
|
344
|
+
return alternate(next, mode === "html");
|
|
345
|
+
});
|
|
346
|
+
try {
|
|
347
|
+
await rejects(loader(`${base}0`), (error) => {
|
|
348
|
+
ok(error instanceof FetchError);
|
|
349
|
+
ok(error.message.includes("Redirect loop detected:"));
|
|
350
|
+
return true;
|
|
351
|
+
});
|
|
352
|
+
deepStrictEqual(requests, mode === "redirect-intermediate" ? 3 : 2);
|
|
353
|
+
} finally {
|
|
354
|
+
esm_default.hardReset();
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
await t.step("alternate followed by 20 redirects shares the limit", async () => {
|
|
358
|
+
esm_default.mockGlobal();
|
|
359
|
+
let requests = 0;
|
|
360
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
361
|
+
requests++;
|
|
362
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
363
|
+
if (index === 21) return Response.json({ done: true });
|
|
364
|
+
return index === 0 ? alternate(`${base}1`, false) : Response.redirect(`${base}${index + 1}`, 302);
|
|
365
|
+
});
|
|
366
|
+
try {
|
|
367
|
+
await rejects(loader(`${base}0`), (error) => {
|
|
368
|
+
ok(error instanceof FetchError);
|
|
369
|
+
ok(error.message.includes("Too many redirections (21)"));
|
|
370
|
+
return true;
|
|
371
|
+
});
|
|
372
|
+
deepStrictEqual(requests, 21);
|
|
373
|
+
} finally {
|
|
374
|
+
esm_default.hardReset();
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
await t.step("relative alternate after redirect and isolated calls", async () => {
|
|
378
|
+
esm_default.mockGlobal();
|
|
379
|
+
esm_default.get(`${base}start`, Response.redirect(`${base}html`, 302));
|
|
380
|
+
esm_default.get(`${base}html`, alternate("./document", true));
|
|
381
|
+
esm_default.get(`${base}document`, Response.json({ done: true }));
|
|
382
|
+
try {
|
|
383
|
+
for (let i = 0; i < 2; i++) {
|
|
384
|
+
const results = await Promise.all([loader(`${base}start`), loader(`${base}start`)]);
|
|
385
|
+
for (const result of results) {
|
|
386
|
+
deepStrictEqual(result.document, { done: true });
|
|
387
|
+
deepStrictEqual(result.documentUrl, `${base}document`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
} finally {
|
|
391
|
+
esm_default.hardReset();
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
function alternate(next, html) {
|
|
395
|
+
return html ? new Response(`<link rel="alternate" type="application/activity+json" href="${next}">`, { headers: { "Content-Type": "text/html" } }) : new Response("not JSON", { headers: {
|
|
396
|
+
"Content-Type": "text/plain",
|
|
397
|
+
Link: `<${next}>; rel="alternate"; type="application/activity+json"`
|
|
398
|
+
} });
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
test("getAuthenticatedDocumentLoader() preserves cancellation across alternates", async (t) => {
|
|
402
|
+
const base = "https://example.com/alternate-abort/";
|
|
403
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
404
|
+
keyId: new URL("https://example.com/key2"),
|
|
405
|
+
privateKey: rsaPrivateKey2
|
|
406
|
+
}, { allowPrivateAddress: true });
|
|
407
|
+
for (const html of [false, true]) await t.step(html ? "HTML" : "Link header", async () => {
|
|
408
|
+
esm_default.mockGlobal();
|
|
409
|
+
const controller = new AbortController();
|
|
410
|
+
const reason = /* @__PURE__ */ new Error("Alternate document loading cancelled");
|
|
411
|
+
let requests = 0;
|
|
412
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
413
|
+
requests++;
|
|
414
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
415
|
+
if (index === 2) return Response.json({ done: true });
|
|
416
|
+
if (index === 1) controller.abort(reason);
|
|
417
|
+
const next = `${base}${index + 1}`;
|
|
418
|
+
return new Response(html ? `<link rel="alternate" type="application/activity+json" href="${next}">` : "not JSON", { headers: html ? { "Content-Type": "text/html" } : {
|
|
419
|
+
"Content-Type": "text/plain",
|
|
420
|
+
Link: `<${next}>; rel="alternate"; type="application/activity+json"`
|
|
421
|
+
} });
|
|
422
|
+
});
|
|
423
|
+
try {
|
|
424
|
+
await rejects(loader(`${base}0`, { signal: controller.signal }), (error) => {
|
|
425
|
+
ok(error === reason);
|
|
426
|
+
return true;
|
|
427
|
+
});
|
|
428
|
+
deepStrictEqual(requests, 2);
|
|
429
|
+
} finally {
|
|
430
|
+
esm_default.hardReset();
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
test("getAuthenticatedDocumentLoader() tracks fallback redirects after alternates", async () => {
|
|
435
|
+
esm_default.mockGlobal();
|
|
436
|
+
let requests = 0;
|
|
437
|
+
let knocks = 0;
|
|
438
|
+
const first = "https://example.com/fallback-alternate/a";
|
|
439
|
+
const second = "https://example.com/fallback-alternate/b";
|
|
440
|
+
esm_default.get(first, () => {
|
|
441
|
+
requests++;
|
|
442
|
+
if (requests > 30) return Response.json({ stopped: true });
|
|
443
|
+
return new Response("", { headers: {
|
|
444
|
+
"Content-Type": "text/plain",
|
|
445
|
+
Link: `<${second}>; rel="alternate"; type="application/activity+json"`
|
|
446
|
+
} });
|
|
447
|
+
});
|
|
448
|
+
esm_default.get(second, () => {
|
|
449
|
+
requests++;
|
|
450
|
+
return ++knocks % 2 === 1 ? new Response("", { status: 401 }) : Response.redirect(first, 302);
|
|
451
|
+
});
|
|
452
|
+
try {
|
|
453
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
454
|
+
keyId: new URL("https://example.com/key2"),
|
|
455
|
+
privateKey: rsaPrivateKey2
|
|
456
|
+
}, { allowPrivateAddress: true });
|
|
457
|
+
await assertRejects(() => loader(first), FetchError, "Redirect loop detected:");
|
|
458
|
+
assertEquals(requests, 3);
|
|
459
|
+
} finally {
|
|
460
|
+
esm_default.hardReset();
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
test("getAuthenticatedDocumentLoader() resolves relative alternates without response URLs", async () => {
|
|
464
|
+
const originalFetch = globalThis.fetch;
|
|
465
|
+
const base = "https://example.com/empty-response-url/";
|
|
466
|
+
const urls = [];
|
|
467
|
+
globalThis.fetch = (input) => {
|
|
468
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
469
|
+
urls.push(url);
|
|
470
|
+
if (url === `${base}start`) return Promise.resolve(Response.redirect(`${base}nested/page`, 302));
|
|
471
|
+
if (url === `${base}nested/page`) return Promise.resolve(new Response("<link rel=\"alternate\" type=\"application/activity+json\" href=\"document\">", { headers: { "Content-Type": "text/html" } }));
|
|
472
|
+
assertEquals(url, `${base}nested/document`);
|
|
473
|
+
return Promise.resolve(Response.json({ done: true }));
|
|
474
|
+
};
|
|
475
|
+
try {
|
|
476
|
+
assertEquals(await getAuthenticatedDocumentLoader({
|
|
477
|
+
keyId: new URL("https://example.com/key2"),
|
|
478
|
+
privateKey: rsaPrivateKey2
|
|
479
|
+
}, { allowPrivateAddress: true })(`${base}start`), {
|
|
480
|
+
contextUrl: null,
|
|
481
|
+
document: { done: true },
|
|
482
|
+
documentUrl: `${base}nested/document`
|
|
483
|
+
});
|
|
484
|
+
assertEquals(urls, [
|
|
485
|
+
`${base}start`,
|
|
486
|
+
`${base}nested/page`,
|
|
487
|
+
`${base}nested/document`
|
|
488
|
+
]);
|
|
489
|
+
} finally {
|
|
490
|
+
globalThis.fetch = originalFetch;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
test("getAuthenticatedDocumentLoader() validates alternate addresses", async () => {
|
|
494
|
+
esm_default.mockGlobal();
|
|
495
|
+
let privateRequests = 0;
|
|
496
|
+
const url = "https://8.8.8.8/alternate";
|
|
497
|
+
esm_default.get(url, new Response("", { headers: {
|
|
498
|
+
"Content-Type": "text/plain",
|
|
499
|
+
Link: "<http://127.0.0.1/private>; rel=\"alternate\"; type=\"application/activity+json\""
|
|
500
|
+
} }));
|
|
501
|
+
esm_default.get("http://127.0.0.1/private", () => {
|
|
502
|
+
privateRequests++;
|
|
503
|
+
return Response.json({ private: true });
|
|
504
|
+
});
|
|
505
|
+
try {
|
|
506
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
507
|
+
keyId: new URL("https://example.com/key2"),
|
|
508
|
+
privateKey: rsaPrivateKey2
|
|
509
|
+
});
|
|
510
|
+
await assertRejects(() => loader(url), UrlError);
|
|
511
|
+
assertEquals(privateRequests, 0);
|
|
512
|
+
} finally {
|
|
513
|
+
esm_default.hardReset();
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
test("getAuthenticatedDocumentLoader() rejects cancellation before fetching", async () => {
|
|
517
|
+
esm_default.mockGlobal();
|
|
518
|
+
let requests = 0;
|
|
519
|
+
const url = "https://example.com/pre-aborted-alternate";
|
|
520
|
+
esm_default.get(url, () => {
|
|
521
|
+
requests++;
|
|
522
|
+
return Response.json({ done: true });
|
|
523
|
+
});
|
|
524
|
+
try {
|
|
525
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
526
|
+
keyId: new URL("https://example.com/key2"),
|
|
527
|
+
privateKey: rsaPrivateKey2
|
|
528
|
+
}, { allowPrivateAddress: true });
|
|
529
|
+
const controller = new AbortController();
|
|
530
|
+
controller.abort();
|
|
531
|
+
await rejects(loader(url, { signal: controller.signal }), { name: "AbortError" });
|
|
532
|
+
deepStrictEqual(requests, 0);
|
|
533
|
+
} finally {
|
|
534
|
+
esm_default.hardReset();
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
function assertTimeoutFetchError(error, url) {
|
|
538
|
+
ok(error instanceof FetchError, String(error));
|
|
539
|
+
deepStrictEqual(error.url.href, url);
|
|
540
|
+
deepStrictEqual(error.response, void 0);
|
|
541
|
+
ok(error.cause instanceof DOMException);
|
|
542
|
+
deepStrictEqual(error.cause.name, "TimeoutError");
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
545
|
+
test("getAuthenticatedDocumentLoader() times out", async (t) => {
|
|
546
|
+
const identity = {
|
|
547
|
+
keyId: new URL("https://example.com/key2"),
|
|
548
|
+
privateKey: rsaPrivateKey2
|
|
549
|
+
};
|
|
550
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
551
|
+
await t.step("a request without a response", async () => {
|
|
552
|
+
esm_default.mockGlobal();
|
|
553
|
+
const url = "https://example.com/hang";
|
|
554
|
+
esm_default.get(url, () => new Promise(() => {}));
|
|
555
|
+
try {
|
|
556
|
+
await rejects(getAuthenticatedDocumentLoader(identity, {
|
|
557
|
+
allowPrivateAddress: true,
|
|
558
|
+
timeout: 100
|
|
559
|
+
})(url), (e) => assertTimeoutFetchError(e, url));
|
|
560
|
+
} finally {
|
|
561
|
+
esm_default.hardReset();
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
await t.step("double-knocking shares the timeout", async () => {
|
|
565
|
+
esm_default.mockGlobal();
|
|
566
|
+
const url = "https://example.com/double-knock";
|
|
567
|
+
let requests = 0;
|
|
568
|
+
esm_default.get(url, async () => {
|
|
569
|
+
requests++;
|
|
570
|
+
await delay(200);
|
|
571
|
+
return new Response(null, { status: 401 });
|
|
572
|
+
});
|
|
573
|
+
try {
|
|
574
|
+
await rejects(getAuthenticatedDocumentLoader(identity, {
|
|
575
|
+
allowPrivateAddress: true,
|
|
576
|
+
timeout: 300
|
|
577
|
+
})(url), (e) => assertTimeoutFetchError(e, url));
|
|
578
|
+
deepStrictEqual(requests, 2);
|
|
579
|
+
await delay(250);
|
|
580
|
+
deepStrictEqual(requests, 2);
|
|
581
|
+
} finally {
|
|
582
|
+
esm_default.hardReset();
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
for (const step of ["determineSpec", "rememberSpec"]) await t.step(`a slow ${step}()`, async () => {
|
|
586
|
+
esm_default.mockGlobal();
|
|
587
|
+
const url = `https://example.com/slow-${step}`;
|
|
588
|
+
let requests = 0;
|
|
589
|
+
esm_default.get(url, () => {
|
|
590
|
+
requests++;
|
|
591
|
+
return Response.json({ parsed: true });
|
|
592
|
+
});
|
|
593
|
+
try {
|
|
594
|
+
await rejects(getAuthenticatedDocumentLoader(identity, {
|
|
595
|
+
allowPrivateAddress: true,
|
|
596
|
+
timeout: 50,
|
|
597
|
+
specDeterminer: {
|
|
598
|
+
async determineSpec() {
|
|
599
|
+
if (step === "determineSpec") await delay(150);
|
|
600
|
+
return "rfc9421";
|
|
601
|
+
},
|
|
602
|
+
async rememberSpec() {
|
|
603
|
+
if (step === "rememberSpec") await delay(150);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
})(url), (e) => assertTimeoutFetchError(e, url));
|
|
607
|
+
await delay(200);
|
|
608
|
+
deepStrictEqual(requests, step === "determineSpec" ? 0 : 1);
|
|
609
|
+
} finally {
|
|
610
|
+
esm_default.hardReset();
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
await t.step("the caller's signal still aborts", async () => {
|
|
614
|
+
esm_default.mockGlobal();
|
|
615
|
+
const url = "https://example.com/hang";
|
|
616
|
+
esm_default.get(url, () => new Promise(() => {}));
|
|
617
|
+
try {
|
|
618
|
+
const loader = getAuthenticatedDocumentLoader(identity, { allowPrivateAddress: true });
|
|
619
|
+
const controller = new AbortController();
|
|
620
|
+
const reason = /* @__PURE__ */ new Error("Canceled by the caller");
|
|
621
|
+
setTimeout(() => controller.abort(reason), 50);
|
|
622
|
+
await rejects(loader(url, { signal: controller.signal }), (e) => e === reason);
|
|
623
|
+
} finally {
|
|
624
|
+
esm_default.hardReset();
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
});
|
|
106
628
|
//#endregion
|
|
107
629
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as kvCache, t as MockKvStore } from "../kv-cache-
|
|
4
|
+
import { n as kvCache, t as MockKvStore } from "../kv-cache-BF1hnW65.mjs";
|
|
5
|
+
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
5
6
|
import { deepStrictEqual, throws } from "node:assert";
|
|
6
7
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
7
|
-
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
8
8
|
//#region src/utils/kv-cache.test.ts
|
|
9
9
|
test("kvCache()", async (t) => {
|
|
10
10
|
const kv = new MockKvStore();
|
package/dist/utils/mod.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_kv_cache = require("../kv-cache-
|
|
3
|
+
const require_kv_cache = require("../kv-cache-DCac1nEU.cjs");
|
|
4
4
|
exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
|
|
5
5
|
exports.kvCache = require_kv_cache.kvCache;
|
package/dist/utils/mod.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-
|
|
2
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-Dw-nPxQh.cjs";
|
|
3
3
|
export { getAuthenticatedDocumentLoader, kvCache };
|
package/dist/utils/mod.d.ts
CHANGED
package/dist/utils/mod.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-
|
|
3
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-CTQr1tbn.js";
|
|
4
4
|
export { getAuthenticatedDocumentLoader, kvCache };
|