@fedify/fedify 2.4.0-dev.1666 → 2.4.0-dev.1727
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 +1 -1
- package/dist/{assert-CJ1KXcvv.mjs → assert-CebeUf0C.mjs} +1 -1
- package/dist/assert_exists-DtzkXC47.mjs +28 -0
- package/dist/assert_false-3pLLLsO4.mjs +23 -0
- package/dist/assert_greater_or_equal-BApOTh1h.mjs +30 -0
- package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-g3WcyYNR.mjs} +1 -1
- package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-BN7yDMWe.mjs} +1 -1
- package/dist/assert_rejects-wFbSPn1O.mjs +39 -0
- package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-Bpjl4Psw.mjs} +1 -1
- package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BJ5wuvR2.mjs} +1 -1
- package/dist/{builder-BGpBs-US.mjs → builder-f5-YwHfj.mjs} +5 -3
- package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-BT7CiPbz.mjs} +191 -9
- package/dist/circuit-breaker-test-utils-BYIHoliq.mjs +14 -0
- package/dist/{client-CjF5IYQS.mjs → client-CtxvmazV.mjs} +63 -5
- 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 +3 -3
- package/dist/compat/public-audience.test.mjs +3 -3
- package/dist/compat/transformers.test.mjs +5 -5
- package/dist/{context-C05Rgxmu.d.cts → context-B-dsBjZ9.d.cts} +281 -7
- package/dist/{context-Cjnr0ig1.d.ts → context-DrLXudbA.d.ts} +281 -7
- package/dist/{deno-CaQlEENR.mjs → deno-Deyoxesx.mjs} +1 -1
- package/dist/{docloader-CTm2Lcpn.mjs → docloader-B3kuDBg9.mjs} +2 -2
- package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
- package/dist/federation/builder.test.mjs +18 -5
- package/dist/federation/circuit-breaker.test.mjs +626 -7
- package/dist/federation/collection.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +14 -13
- package/dist/federation/idempotency.test.mjs +6 -6
- package/dist/federation/inbox.test.mjs +3 -3
- package/dist/federation/keycache.test.mjs +5 -5
- package/dist/federation/kv.test.mjs +3 -3
- package/dist/federation/metrics.test.mjs +4 -4
- package/dist/federation/middleware.test.mjs +37 -28
- package/dist/federation/mod.cjs +18 -540
- package/dist/federation/mod.d.cts +3 -4
- package/dist/federation/mod.d.ts +3 -4
- package/dist/federation/mod.js +1 -1
- package/dist/federation/mq.test.mjs +32 -5
- package/dist/federation/negotiation.test.mjs +4 -4
- package/dist/federation/retry.test.mjs +3 -3
- package/dist/federation/router.test.mjs +7 -7
- package/dist/federation/send.test.mjs +28 -26
- package/dist/federation/tasks/codec.test.mjs +4 -4
- package/dist/federation/tasks/enqueue.test.mjs +4 -4
- package/dist/federation/tasks/tasks.test.mjs +6 -6
- package/dist/federation/temporal.test.mjs +4 -4
- package/dist/federation/webfinger.test.mjs +74 -12
- package/dist/{middleware-Dnzqy4sk.cjs → federation-BzRjeOky.cjs} +855 -114
- package/dist/{temporal-polyfill-BCdTHexd.cjs → http-AyKngJ_h.cjs} +2801 -104
- package/dist/{http-BX5xiNUh.js → http-Bw6s_dOB.js} +3 -3
- package/dist/{http-BaSuRiWJ.mjs → http-TjhZfiSN.mjs} +5 -5
- package/dist/{key-BvJYxJoY.mjs → key-b4kf4yZT.mjs} +2 -2
- package/dist/{kv-cache-BPapnm-V.cjs → kv-cache-BTVaZrf-.cjs} +2 -4
- package/dist/{kv-cache-C04NtL2n.js → kv-cache-CQsh-KUw.js} +1 -1
- package/dist/{kv-cache-B9fTkVpc.mjs → kv-cache-CpILvhUV.mjs} +1 -1
- package/dist/{ld-DU12IAt8.mjs → ld-CKujkAfG.mjs} +5 -5
- package/dist/{metrics-BYUxSscw.mjs → metrics-AlCGTDrr.mjs} +2 -2
- package/dist/metrics-DVKYY6K1.d.cts +36 -0
- package/dist/metrics-DoRtI0qU.d.ts +36 -0
- package/dist/{middleware-BEd40QBF.mjs → middleware-C9Y5lLZN.mjs} +60 -43
- package/dist/{middleware-_VQWtF1B.js → middleware-CZcuedl-.js} +241 -40
- package/dist/{middleware-C4oS_tdq.mjs → middleware-LPbZz6-1.mjs} +1 -1
- package/dist/{mod-BrpVsSfY.d.cts → mod-CLHkCwLm.d.cts} +3 -3
- package/dist/{mod-B0hW12_O.d.cts → mod-CuDDaIIt.d.cts} +1 -1
- package/dist/{mod-COIAjwRS.d.ts → mod-D-IhOEOP.d.ts} +1 -1
- package/dist/{mod-DdONo-ep.d.cts → mod-D-abvu2C.d.cts} +1 -1
- package/dist/{mod-BsCE5Ihq.d.ts → mod-D6O8C7eN.d.ts} +1 -1
- package/dist/{mod-CNef4in0.d.ts → mod-DypxPS9H.d.ts} +3 -3
- package/dist/mod.cjs +24 -25
- package/dist/mod.d.cts +8 -9
- package/dist/mod.d.ts +8 -9
- package/dist/mod.js +7 -7
- package/dist/nodeinfo/client.test.mjs +64 -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-BQSHRLhg.mjs} +2 -2
- package/dist/{owner-DFF9ltAs.mjs → owner-D1O8v8FB.mjs} +2 -2
- package/dist/{proof-rOoEb_P4.js → proof-BTBolSnd.js} +6 -6
- package/dist/{proof-DcbeTQMG.cjs → proof-DcSm-2eG.cjs} +10 -11
- package/dist/{proof-DEV-fO9I.mjs → proof-DeMR7Akd.mjs} +6 -6
- package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--9hx7IGx.mjs} +1 -1
- package/dist/runtime/mod.cjs +1 -1
- package/dist/runtime/mod.js +1 -1
- package/dist/{send-BVkabUz0.mjs → send-DG7JG280.mjs} +3 -3
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +37 -11
- package/dist/sig/key.test.mjs +6 -6
- package/dist/sig/ld.test.mjs +9 -7
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +3 -3
- package/dist/sig/mod.d.ts +3 -3
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +6 -6
- package/dist/sig/proof.test.mjs +10 -8
- package/dist/std__assert-CxFT0MNt.mjs +8 -0
- package/dist/{temporal-X0BllGgC.mjs → temporal-DA3jx8x1.mjs} +3 -3
- package/dist/testing/mod.d.mts +10 -0
- package/dist/testing/mod.mjs +2 -2
- package/dist/{testing-CO7ftO8A.mjs → testing-BX0Nicyq.mjs} +2 -2
- package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
- package/dist/{types-DC1pNgJA.js → types-Dtyf8lVj.js} +63 -5
- package/dist/{types-CPym83zc.cjs → types-RXm5YxpC.cjs} +62 -5
- package/dist/utils/docloader.test.mjs +7 -7
- package/dist/utils/kv-cache.test.mjs +1 -1
- 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/package.json +7 -7
- package/skills/fedify/SKILL.md +462 -0
- package/dist/assert_rejects-EgstcQy5.mjs +0 -82
- package/dist/http-BIJdA1mF.cjs +0 -2694
- package/dist/metrics-DN13mCAw.d.cts +0 -294
- package/dist/metrics-v_e0n5GQ.d.ts +0 -294
- package/dist/std__assert-B2NnY9bq.mjs +0 -79
- /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/{assert_equals-BV7oLMxm.mjs → assert_equals-CBlRfA-_.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/{codec-BBga-FWI.mjs → codec-peqOdBaE.mjs} +0 -0
- /package/dist/{context-BJXxPElm.mjs → context-Dt36KFEJ.mjs} +0 -0
- /package/dist/{http-VyDTd4G3.d.cts → http-6TI0tI03.d.cts} +0 -0
- /package/dist/{http-lf8Hsd91.d.ts → http-CdrSn2ip.d.ts} +0 -0
- /package/dist/{keycache-_DHqz5z_.mjs → keycache-0Jk78XmB.mjs} +0 -0
- /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
- /package/dist/{kv-D6hNiMTK.d.ts → kv-BhNbN8Ed.d.cts} +0 -0
- /package/dist/{kv-gJ8LYbxX.d.cts → kv-BhNbN8Ed.d.ts} +0 -0
- /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
- /package/dist/{mq-Bo7Etgh6.mjs → mq-Dm1Wmtm-.mjs} +0 -0
- /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
- /package/dist/{owner-CnngXDNJ.d.ts → owner-DGSfntI-.d.ts} +0 -0
- /package/dist/{owner-DEvZuyOE.d.cts → owner-r_waTiQj.d.cts} +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
package/README.md
CHANGED
|
@@ -207,7 +207,7 @@ This project exists thanks to all the people who contribute, donate, and sponsor
|
|
|
207
207
|
it. We are grateful for their support. We would like to thank the following
|
|
208
208
|
financial contributors:[^2]
|
|
209
209
|
|
|
210
|
-
[^2]: Those lists are automatically updated
|
|
210
|
+
[^2]: Those lists are automatically updated twice a day.
|
|
211
211
|
|
|
212
212
|
<!-- hongdown-disable -->
|
|
213
213
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { l as AssertionError } from "./assert_equals-
|
|
4
|
+
import { l as AssertionError } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
5
|
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert.js
|
|
6
6
|
/**
|
|
7
7
|
* Make an assertion, error will be thrown if `expr` does not have truthy value.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { l as AssertionError } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_exists.js
|
|
6
|
+
/**
|
|
7
|
+
* Make an assertion that actual is not null or undefined.
|
|
8
|
+
* If not then throw.
|
|
9
|
+
*
|
|
10
|
+
* @example Usage
|
|
11
|
+
* ```ts no-eval
|
|
12
|
+
* import { assertExists } from "@std/assert/assert-exists";
|
|
13
|
+
*
|
|
14
|
+
* assertExists("something"); // Doesn't throw
|
|
15
|
+
* assertExists(undefined); // Throws
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @typeParam T The type of the actual value.
|
|
19
|
+
* @param actual The actual value to check.
|
|
20
|
+
* @param msg The optional message to include in the error if the assertion fails.
|
|
21
|
+
*/ function assertExists(actual, msg) {
|
|
22
|
+
if (actual === void 0 || actual === null) {
|
|
23
|
+
msg = `Expected actual: "${actual}" to not be null or undefined${msg ? `: ${msg}` : "."}`;
|
|
24
|
+
throw new AssertionError(msg);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { assertExists as t };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { l as AssertionError } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_false.js
|
|
6
|
+
/**
|
|
7
|
+
* Make an assertion, error will be thrown if `expr` have truthy value.
|
|
8
|
+
*
|
|
9
|
+
* @example Usage
|
|
10
|
+
* ```ts no-eval
|
|
11
|
+
* import { assertFalse } from "@std/assert/assert-false";
|
|
12
|
+
*
|
|
13
|
+
* assertFalse(false); // Doesn't throw
|
|
14
|
+
* assertFalse(true); // Throws
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param expr The expression to test.
|
|
18
|
+
* @param msg The optional message to display if the assertion fails.
|
|
19
|
+
*/ function assertFalse(expr, msg = "") {
|
|
20
|
+
if (expr) throw new AssertionError(msg);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { assertFalse as t };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { l as AssertionError, s as format } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_greater_or_equal.js
|
|
6
|
+
/**
|
|
7
|
+
* Make an assertion that `actual` is greater than or equal to `expected`.
|
|
8
|
+
* If not then throw.
|
|
9
|
+
*
|
|
10
|
+
* @example Usage
|
|
11
|
+
* ```ts no-eval
|
|
12
|
+
* import { assertGreaterOrEqual } from "@std/assert/assert-greater-or-equal";
|
|
13
|
+
*
|
|
14
|
+
* assertGreaterOrEqual(2, 1); // Doesn't throw
|
|
15
|
+
* assertGreaterOrEqual(1, 1); // Doesn't throw
|
|
16
|
+
* assertGreaterOrEqual(0, 1); // Throws
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @typeParam T The type of the values to compare.
|
|
20
|
+
* @param actual The actual value to compare.
|
|
21
|
+
* @param expected The expected value to compare.
|
|
22
|
+
* @param msg The optional message to display if the assertion fails.
|
|
23
|
+
*/ function assertGreaterOrEqual(actual, expected, msg) {
|
|
24
|
+
if (actual >= expected) return;
|
|
25
|
+
const actualString = format(actual);
|
|
26
|
+
const expectedString = format(expected);
|
|
27
|
+
throw new AssertionError(msg ?? `Expect ${actualString} >= ${expectedString}`);
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { assertGreaterOrEqual as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { l as AssertionError } from "./assert_equals-
|
|
4
|
+
import { l as AssertionError } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
5
|
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_instance_of.js
|
|
6
6
|
/**
|
|
7
7
|
* Make an assertion that `obj` is an instance of `type`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { c as equal, l as AssertionError } from "./assert_equals-
|
|
4
|
+
import { c as equal, l as AssertionError } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
5
|
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_not_equals.js
|
|
6
6
|
/**
|
|
7
7
|
* Make an assertion that `actual` and `expected` are not equal, deeply.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { l as AssertionError } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
|
+
import { n as assertIsError } from "./assert_throws-BJ5wuvR2.mjs";
|
|
6
|
+
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_rejects.js
|
|
7
|
+
async function assertRejects(fn, errorClassOrMsg, msgIncludesOrMsg, msg) {
|
|
8
|
+
let ErrorClass = void 0;
|
|
9
|
+
let msgIncludes = void 0;
|
|
10
|
+
let err;
|
|
11
|
+
if (typeof errorClassOrMsg !== "string") {
|
|
12
|
+
if (errorClassOrMsg === void 0 || errorClassOrMsg.prototype instanceof Error || errorClassOrMsg.prototype === Error.prototype) {
|
|
13
|
+
ErrorClass = errorClassOrMsg;
|
|
14
|
+
msgIncludes = msgIncludesOrMsg;
|
|
15
|
+
}
|
|
16
|
+
} else msg = errorClassOrMsg;
|
|
17
|
+
let doesThrow = false;
|
|
18
|
+
let isPromiseReturned = false;
|
|
19
|
+
const msgSuffix = msg ? `: ${msg}` : ".";
|
|
20
|
+
try {
|
|
21
|
+
const possiblePromise = fn();
|
|
22
|
+
if (possiblePromise && typeof possiblePromise === "object" && typeof possiblePromise.then === "function") {
|
|
23
|
+
isPromiseReturned = true;
|
|
24
|
+
await possiblePromise;
|
|
25
|
+
} else throw Error();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (!isPromiseReturned) throw new AssertionError(`Function throws when expected to reject${msgSuffix}`);
|
|
28
|
+
if (ErrorClass) {
|
|
29
|
+
if (!(error instanceof Error)) throw new AssertionError(`A non-Error object was rejected${msgSuffix}`);
|
|
30
|
+
assertIsError(error, ErrorClass, msgIncludes, msg);
|
|
31
|
+
}
|
|
32
|
+
err = error;
|
|
33
|
+
doesThrow = true;
|
|
34
|
+
}
|
|
35
|
+
if (!doesThrow) throw new AssertionError(`Expected function to reject${msgSuffix}`);
|
|
36
|
+
return err;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { assertRejects as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { a as red, i as buildMessage, l as AssertionError, n as diffStr, r as diff, s as format } from "./assert_equals-
|
|
4
|
+
import { a as red, i as buildMessage, l as AssertionError, n as diffStr, r as diff, s as format } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
5
|
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_strict_equals.js
|
|
6
6
|
/**
|
|
7
7
|
* Make an assertion that `actual` and `expected` are equal using
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { l as AssertionError, o as stripAnsiCode } from "./assert_equals-
|
|
4
|
+
import { l as AssertionError, o as stripAnsiCode } from "./assert_equals-CBlRfA-_.mjs";
|
|
5
5
|
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_is_error.js
|
|
6
6
|
/**
|
|
7
7
|
* Make an assertion that `error` is an `Error`.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { t as ActivityListenerSet } from "./activity-listener-
|
|
4
|
+
import { n as version, t as name } from "./deno-Deyoxesx.mjs";
|
|
5
|
+
import { t as ActivityListenerSet } from "./activity-listener-C-BSbKI7.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { Router, RouterError, assertPath } from "@fedify/uri-template";
|
|
8
8
|
import { Tombstone, getTypeId } from "@fedify/vocab";
|
|
@@ -85,7 +85,7 @@ var FederationBuilderImpl = class {
|
|
|
85
85
|
* specified.
|
|
86
86
|
*/
|
|
87
87
|
async build(options) {
|
|
88
|
-
const { FederationImpl } = await import("./middleware-
|
|
88
|
+
const { FederationImpl } = await import("./middleware-LPbZz6-1.mjs");
|
|
89
89
|
const f = new FederationImpl(options);
|
|
90
90
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
91
91
|
f.router = this.router.clone();
|
|
@@ -96,6 +96,8 @@ var FederationBuilderImpl = class {
|
|
|
96
96
|
f.webFingerLinksDispatcher = this.webFingerLinksDispatcher;
|
|
97
97
|
f.objectCallbacks = { ...this.objectCallbacks };
|
|
98
98
|
f.objectTypeIds = { ...this.objectTypeIds };
|
|
99
|
+
f.collectionCallbacks = { ...this.collectionCallbacks };
|
|
100
|
+
f.collectionTypeIds = { ...this.collectionTypeIds };
|
|
99
101
|
f.inboxPath = this.inboxPath;
|
|
100
102
|
f.outboxPath = this.outboxPath;
|
|
101
103
|
f.inboxCallbacks = this.inboxCallbacks == null ? void 0 : { ...this.inboxCallbacks };
|
|
@@ -3,7 +3,13 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
//#region src/federation/circuit-breaker.ts
|
|
6
|
-
const
|
|
6
|
+
const LEGACY_SWEEP_MARKER = ["__fedify_meta", "circuit_breaker_state_ttl_sweep_v1"];
|
|
7
|
+
const LEGACY_SWEEP_DELETING_MARKER = { __fedifyDeletingCircuitBreakerLegacyState: true };
|
|
8
|
+
const CIRCUIT_BREAKER_STATE_VERSION = 1;
|
|
9
|
+
const LEGACY_SWEEP_LOCK_TTL = Temporal.Duration.from({ minutes: 5 });
|
|
10
|
+
const LEGACY_SWEEP_RETRY_WINDOW = Temporal.Duration.from({ hours: 168 });
|
|
11
|
+
const LEGACY_SWEEP_WAIT_INTERVAL = 10;
|
|
12
|
+
const LEGACY_SWEEP_CAS_ATTEMPTS = 3;
|
|
7
13
|
/**
|
|
8
14
|
* Tracks reachability state for remote outbox delivery hosts.
|
|
9
15
|
* @since 2.3.0
|
|
@@ -13,6 +19,8 @@ var CircuitBreaker = class {
|
|
|
13
19
|
#prefix;
|
|
14
20
|
#options;
|
|
15
21
|
#now;
|
|
22
|
+
#legacySweep;
|
|
23
|
+
#legacySweepDone;
|
|
16
24
|
#stateChangeObserver;
|
|
17
25
|
constructor(options) {
|
|
18
26
|
this.#kv = options.kv;
|
|
@@ -29,6 +37,7 @@ var CircuitBreaker = class {
|
|
|
29
37
|
return now.until(this.#capHeldRetryAt(now, heldSince, now.add(delay)));
|
|
30
38
|
}
|
|
31
39
|
async beforeSend(remoteHost, message) {
|
|
40
|
+
this.#sweepLegacyStates();
|
|
32
41
|
const heldSince = parseHeldSince(message.circuitHeldSince);
|
|
33
42
|
const now = this.#now();
|
|
34
43
|
if (heldSince != null && Temporal.Instant.compare(heldSince.add(this.#options.heldActivityTtl), now) <= 0) return {
|
|
@@ -110,6 +119,7 @@ var CircuitBreaker = class {
|
|
|
110
119
|
throw new Error(`Failed to update circuit breaker state for ${remoteHost}`);
|
|
111
120
|
}
|
|
112
121
|
async recordSuccess(remoteHost) {
|
|
122
|
+
this.#sweepLegacyStates();
|
|
113
123
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
114
124
|
const oldState = await this.#get(remoteHost);
|
|
115
125
|
if (oldState == null) return void 0;
|
|
@@ -130,6 +140,7 @@ var CircuitBreaker = class {
|
|
|
130
140
|
return await this.recordSuccess(remoteHost);
|
|
131
141
|
}
|
|
132
142
|
async recordFailure(remoteHost) {
|
|
143
|
+
this.#sweepLegacyStates();
|
|
133
144
|
const now = this.#now();
|
|
134
145
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
135
146
|
const oldState = await this.#get(remoteHost);
|
|
@@ -177,26 +188,122 @@ var CircuitBreaker = class {
|
|
|
177
188
|
}
|
|
178
189
|
}
|
|
179
190
|
async getState(remoteHost) {
|
|
180
|
-
|
|
191
|
+
this.#sweepLegacyStates();
|
|
192
|
+
return stripStoredCircuitBreakerState(await this.#get(remoteHost));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The currently running background legacy sweep, if any.
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
get pendingSweep() {
|
|
199
|
+
return this.#legacySweep;
|
|
181
200
|
}
|
|
182
201
|
#key(remoteHost) {
|
|
183
202
|
return [...this.#prefix, remoteHost];
|
|
184
203
|
}
|
|
204
|
+
#legacySweepMarkerKey() {
|
|
205
|
+
return [...this.#prefix, ...LEGACY_SWEEP_MARKER];
|
|
206
|
+
}
|
|
207
|
+
#sweepLegacyStates() {
|
|
208
|
+
if (this.#kv.cas == null) return;
|
|
209
|
+
if (this.#options.stateTtl == null) return;
|
|
210
|
+
if (this.#legacySweep != null) return;
|
|
211
|
+
if (this.#isLegacySweepDone()) return;
|
|
212
|
+
this.#legacySweep = this.#sweepLegacyStatesImpl().catch((error) => {
|
|
213
|
+
getLogger([
|
|
214
|
+
"fedify",
|
|
215
|
+
"federation",
|
|
216
|
+
"circuit"
|
|
217
|
+
]).warn("Failed to sweep legacy circuit breaker state:\n{error}", { error });
|
|
218
|
+
}).finally(() => {
|
|
219
|
+
this.#legacySweep = void 0;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
async #sweepLegacyStatesImpl() {
|
|
223
|
+
const markerKey = this.#legacySweepMarkerKey();
|
|
224
|
+
const marker = await this.#acquireLegacySweep(markerKey);
|
|
225
|
+
if (marker === "done") return;
|
|
226
|
+
try {
|
|
227
|
+
for await (const { key, value } of this.#kv.list(this.#prefix)) {
|
|
228
|
+
if (key.length !== this.#prefix.length + 1) continue;
|
|
229
|
+
await this.#migrateLegacyState(key, value);
|
|
230
|
+
}
|
|
231
|
+
} catch (error) {
|
|
232
|
+
await this.#deleteIfUnchanged(markerKey, marker);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
const finishedMarker = this.#finishLegacySweepMarker(marker);
|
|
236
|
+
if (await this.#kv.cas(markerKey, marker, finishedMarker)) this.#rememberLegacySweepMarker(finishedMarker);
|
|
237
|
+
}
|
|
238
|
+
#finishLegacySweepMarker(marker) {
|
|
239
|
+
const retryUntil = getLegacySweepRetryUntil(marker);
|
|
240
|
+
if (retryUntil != null && Temporal.Instant.compare(this.#now(), Temporal.Instant.from(retryUntil)) < 0) return {
|
|
241
|
+
state: "done",
|
|
242
|
+
retryUntil
|
|
243
|
+
};
|
|
244
|
+
return { state: "final" };
|
|
245
|
+
}
|
|
246
|
+
async #migrateLegacyState(key, value) {
|
|
247
|
+
if (isCurrentCircuitBreakerState(value)) return;
|
|
248
|
+
const state = parseCircuitBreakerKvState(value);
|
|
249
|
+
if (state != null) {
|
|
250
|
+
await this.#kv.cas(key, value, markCircuitBreakerState(state), this.#setOptions());
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
await this.#deleteIfUnchanged(key, value);
|
|
254
|
+
}
|
|
255
|
+
async #deleteIfUnchanged(key, value) {
|
|
256
|
+
if (await this.#kv.cas(key, value, LEGACY_SWEEP_DELETING_MARKER, { ttl: LEGACY_SWEEP_LOCK_TTL })) await this.#kv.delete(key);
|
|
257
|
+
}
|
|
258
|
+
async #acquireLegacySweep(markerKey) {
|
|
259
|
+
for (let attempt = 0; attempt < LEGACY_SWEEP_CAS_ATTEMPTS; attempt++) {
|
|
260
|
+
const marker = await this.#kv.get(markerKey);
|
|
261
|
+
const now = this.#now();
|
|
262
|
+
if (isLegacySweepActive(marker, now)) {
|
|
263
|
+
this.#rememberLegacySweepMarker(marker);
|
|
264
|
+
return "done";
|
|
265
|
+
}
|
|
266
|
+
const retryUntil = isLegacySweepRetryDue(marker, now) ? marker.retryUntil : getLegacySweepRetryUntil(marker) ?? now.add(LEGACY_SWEEP_RETRY_WINDOW).toString();
|
|
267
|
+
const sweeping = {
|
|
268
|
+
state: "sweeping",
|
|
269
|
+
started: now.toString(),
|
|
270
|
+
retryUntil
|
|
271
|
+
};
|
|
272
|
+
if (await this.#kv.cas(markerKey, marker ?? void 0, sweeping, { ttl: LEGACY_SWEEP_LOCK_TTL })) return sweeping;
|
|
273
|
+
await delay(LEGACY_SWEEP_WAIT_INTERVAL);
|
|
274
|
+
}
|
|
275
|
+
return "done";
|
|
276
|
+
}
|
|
277
|
+
#isLegacySweepDone() {
|
|
278
|
+
if (this.#legacySweepDone === "final") return true;
|
|
279
|
+
if (this.#legacySweepDone == null) return false;
|
|
280
|
+
if (Temporal.Instant.compare(this.#now(), this.#legacySweepDone) < 0) return true;
|
|
281
|
+
this.#legacySweepDone = void 0;
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
#rememberLegacySweepMarker(marker) {
|
|
285
|
+
const doneUntil = getLegacySweepDoneUntil(marker, this.#now());
|
|
286
|
+
if (doneUntil != null) this.#legacySweepDone = doneUntil;
|
|
287
|
+
}
|
|
185
288
|
#capHeldRetryAt(now, heldSince, retryAt) {
|
|
186
289
|
const expiresAt = (heldSince ?? now).add(this.#options.heldActivityTtl);
|
|
187
290
|
return Temporal.Instant.compare(expiresAt, retryAt) < 0 ? expiresAt : retryAt;
|
|
188
291
|
}
|
|
189
292
|
async #get(remoteHost) {
|
|
190
|
-
return
|
|
293
|
+
return parseStoredCircuitBreakerKvState(await this.#kv.get(this.#key(remoteHost)));
|
|
191
294
|
}
|
|
192
295
|
async #replace(remoteHost, oldState, newState) {
|
|
193
296
|
const key = this.#key(remoteHost);
|
|
297
|
+
const storedState = newState == null ? void 0 : markCircuitBreakerState(newState);
|
|
194
298
|
if (this.#kv.cas == null) {
|
|
195
|
-
if (
|
|
196
|
-
else await this.#kv.set(key,
|
|
299
|
+
if (storedState == null) await this.#kv.delete(key);
|
|
300
|
+
else await this.#kv.set(key, storedState, this.#setOptions());
|
|
197
301
|
return true;
|
|
198
302
|
}
|
|
199
|
-
return await this.#kv.cas(key, oldState,
|
|
303
|
+
return await this.#kv.cas(key, oldState, storedState, storedState == null ? void 0 : this.#setOptions());
|
|
304
|
+
}
|
|
305
|
+
#setOptions() {
|
|
306
|
+
return this.#options.stateTtl == null ? void 0 : { ttl: this.#options.stateTtl };
|
|
200
307
|
}
|
|
201
308
|
async #notifyStateChange(remoteHost, previousState, newState) {
|
|
202
309
|
try {
|
|
@@ -236,18 +343,25 @@ var CircuitBreaker = class {
|
|
|
236
343
|
* @param options The public circuit breaker options supplied to Fedify.
|
|
237
344
|
* @returns The normalized failure predicate, failure pruning function,
|
|
238
345
|
* duration values, and optional callbacks with defaults applied.
|
|
239
|
-
* @throws {RangeError} If any configured duration is not positive
|
|
346
|
+
* @throws {RangeError} If any configured duration is not positive, or if
|
|
347
|
+
* `stateTtl` is shorter than `recoveryDelay`.
|
|
240
348
|
* @throws {TypeError} If `failureThreshold` is not a positive integer.
|
|
241
349
|
*/
|
|
242
350
|
function normalizeCircuitBreakerOptions(options) {
|
|
243
351
|
const recoveryDelay = toInstantDuration(options.recoveryDelay ?? { minutes: 30 });
|
|
244
352
|
const heldActivityTtl = toInstantDuration(options.heldActivityTtl ?? { hours: 168 });
|
|
245
353
|
const releaseInterval = toInstantDuration(options.releaseInterval ?? { seconds: 1 });
|
|
354
|
+
const configuredStateTtl = options.stateTtl == null ? void 0 : toInstantDuration(options.stateTtl);
|
|
246
355
|
assertPositiveDuration(recoveryDelay, "recoveryDelay");
|
|
247
356
|
assertPositiveDuration(heldActivityTtl, "heldActivityTtl");
|
|
248
357
|
assertPositiveDuration(releaseInterval, "releaseInterval");
|
|
358
|
+
if (configuredStateTtl != null) {
|
|
359
|
+
assertPositiveDuration(configuredStateTtl, "stateTtl");
|
|
360
|
+
if (Temporal.Duration.compare(configuredStateTtl, recoveryDelay) < 0) throw new RangeError("stateTtl must be at least recoveryDelay.");
|
|
361
|
+
}
|
|
249
362
|
let failure;
|
|
250
363
|
let pruneFailures;
|
|
364
|
+
let stateTtl;
|
|
251
365
|
if (options.failure == null) {
|
|
252
366
|
const failureThreshold = options.failureThreshold ?? 5;
|
|
253
367
|
if (!Number.isInteger(failureThreshold) || failureThreshold <= 0) throw new TypeError("failureThreshold must be a positive integer.");
|
|
@@ -263,9 +377,11 @@ function normalizeCircuitBreakerOptions(options) {
|
|
|
263
377
|
const last = timestamps[timestamps.length - 1];
|
|
264
378
|
return Temporal.Duration.compare(first.until(last), failureWindow) <= 0;
|
|
265
379
|
};
|
|
380
|
+
stateTtl = configuredStateTtl ?? maxDuration(recoveryDelay.add(failureWindow), recoveryDelay.add(heldActivityTtl));
|
|
266
381
|
} else {
|
|
267
382
|
failure = options.failure;
|
|
268
|
-
pruneFailures = (timestamps) => timestamps.slice(-
|
|
383
|
+
pruneFailures = (timestamps) => timestamps.slice(-100);
|
|
384
|
+
stateTtl = configuredStateTtl;
|
|
269
385
|
}
|
|
270
386
|
return {
|
|
271
387
|
failure,
|
|
@@ -273,10 +389,72 @@ function normalizeCircuitBreakerOptions(options) {
|
|
|
273
389
|
recoveryDelay,
|
|
274
390
|
heldActivityTtl,
|
|
275
391
|
releaseInterval,
|
|
392
|
+
stateTtl,
|
|
276
393
|
onStateChange: options.onStateChange,
|
|
277
394
|
onActivityDrop: options.onActivityDrop
|
|
278
395
|
};
|
|
279
396
|
}
|
|
397
|
+
function maxDuration(duration, ...durations) {
|
|
398
|
+
return durations.reduce((max, candidate) => Temporal.Duration.compare(candidate, max) > 0 ? candidate : max, duration);
|
|
399
|
+
}
|
|
400
|
+
function isLegacySweepDone(value, now) {
|
|
401
|
+
return getLegacySweepDoneUntil(value, now) != null;
|
|
402
|
+
}
|
|
403
|
+
function getLegacySweepDoneUntil(value, now) {
|
|
404
|
+
if (typeof value !== "object" || value == null || !("state" in value)) return;
|
|
405
|
+
if (value.state === "final") return "final";
|
|
406
|
+
if (value.state === "done" && "retryUntil" in value && typeof value.retryUntil === "string") try {
|
|
407
|
+
const retryUntil = Temporal.Instant.from(value.retryUntil);
|
|
408
|
+
return Temporal.Instant.compare(now, retryUntil) < 0 ? retryUntil : void 0;
|
|
409
|
+
} catch {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function isLegacySweepRetryDue(value, now) {
|
|
414
|
+
if (typeof value !== "object" || value == null || !("state" in value) || value.state !== "done" || !("retryUntil" in value) || typeof value.retryUntil !== "string") return false;
|
|
415
|
+
try {
|
|
416
|
+
return Temporal.Instant.compare(now, Temporal.Instant.from(value.retryUntil)) >= 0;
|
|
417
|
+
} catch {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
function isLegacySweepActive(value, now) {
|
|
422
|
+
return isLegacySweepDone(value, now) || isLegacySweepInProgress(value, now);
|
|
423
|
+
}
|
|
424
|
+
function isLegacySweepInProgress(value, now) {
|
|
425
|
+
if (typeof value !== "object" || value == null || !("state" in value) || value.state !== "sweeping" || !("started" in value) || typeof value.started !== "string") return false;
|
|
426
|
+
try {
|
|
427
|
+
return Temporal.Instant.compare(now, Temporal.Instant.from(value.started).add(LEGACY_SWEEP_LOCK_TTL)) < 0;
|
|
428
|
+
} catch {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function getLegacySweepRetryUntil(value) {
|
|
433
|
+
if (typeof value !== "object" || value == null || !("retryUntil" in value) || typeof value.retryUntil !== "string") return;
|
|
434
|
+
try {
|
|
435
|
+
Temporal.Instant.from(value.retryUntil);
|
|
436
|
+
return value.retryUntil;
|
|
437
|
+
} catch {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function isCurrentCircuitBreakerState(value) {
|
|
442
|
+
return typeof value === "object" && value != null && "__fedifyCircuitBreakerStateVersion" in value && value.__fedifyCircuitBreakerStateVersion === CIRCUIT_BREAKER_STATE_VERSION;
|
|
443
|
+
}
|
|
444
|
+
function markCircuitBreakerState(state) {
|
|
445
|
+
return {
|
|
446
|
+
...state,
|
|
447
|
+
__fedifyCircuitBreakerStateVersion: CIRCUIT_BREAKER_STATE_VERSION
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function stripStoredCircuitBreakerState(state) {
|
|
451
|
+
if (state == null) return void 0;
|
|
452
|
+
const { __fedifyCircuitBreakerStateVersion: _, ...publicState } = state;
|
|
453
|
+
return publicState;
|
|
454
|
+
}
|
|
455
|
+
function delay(milliseconds) {
|
|
456
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
457
|
+
}
|
|
280
458
|
function toInstantDuration(duration) {
|
|
281
459
|
const parsed = Temporal.Duration.from(duration);
|
|
282
460
|
return Temporal.Duration.from({ milliseconds: Math.trunc(parsed.total({
|
|
@@ -311,6 +489,9 @@ function parseHeldSince(value) {
|
|
|
311
489
|
* valid instant strings, or `undefined` when the stored value is malformed.
|
|
312
490
|
*/
|
|
313
491
|
function parseCircuitBreakerKvState(value) {
|
|
492
|
+
return stripStoredCircuitBreakerState(parseStoredCircuitBreakerKvState(value));
|
|
493
|
+
}
|
|
494
|
+
function parseStoredCircuitBreakerKvState(value) {
|
|
314
495
|
const isInstantString = (v) => {
|
|
315
496
|
if (typeof v !== "string") return false;
|
|
316
497
|
try {
|
|
@@ -330,7 +511,8 @@ function parseCircuitBreakerKvState(value) {
|
|
|
330
511
|
state: record.state,
|
|
331
512
|
failures: record.failures,
|
|
332
513
|
...record.opened == null ? {} : { opened: record.opened },
|
|
333
|
-
...record.halfOpened == null ? {} : { halfOpened: record.halfOpened }
|
|
514
|
+
...record.halfOpened == null ? {} : { halfOpened: record.halfOpened },
|
|
515
|
+
...record.__fedifyCircuitBreakerStateVersion === CIRCUIT_BREAKER_STATE_VERSION ? { __fedifyCircuitBreakerStateVersion: CIRCUIT_BREAKER_STATE_VERSION } : {}
|
|
334
516
|
};
|
|
335
517
|
}
|
|
336
518
|
//#endregion
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
//#region src/federation/circuit-breaker-test-utils.ts
|
|
5
|
+
function markCircuitBreakerLegacySweepDone(kv) {
|
|
6
|
+
return kv.set([
|
|
7
|
+
"_fedify",
|
|
8
|
+
"circuit",
|
|
9
|
+
"__fedify_meta",
|
|
10
|
+
"circuit_breaker_state_ttl_sweep_v1"
|
|
11
|
+
], { state: "final" });
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { markCircuitBreakerLegacySweepDone as t };
|
|
@@ -2,22 +2,79 @@ import "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
|
-
import { getUserAgent } from "@fedify/vocab-runtime";
|
|
5
|
+
import { UrlError, getUserAgent, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
6
6
|
//#region src/nodeinfo/client.ts
|
|
7
7
|
const logger = getLogger([
|
|
8
8
|
"fedify",
|
|
9
9
|
"nodeinfo",
|
|
10
10
|
"client"
|
|
11
11
|
]);
|
|
12
|
+
const DEFAULT_MAX_REDIRECTION = 5;
|
|
13
|
+
/**
|
|
14
|
+
* Fetches a URL while guarding against SSRF. Before every request—including
|
|
15
|
+
* each redirect hop—the destination is validated with
|
|
16
|
+
* {@link validatePublicUrl}, so that loopback, link-local, and private
|
|
17
|
+
* addresses, as well as non-HTTP(S) schemes such as `data:`, are rejected.
|
|
18
|
+
* Redirects are followed manually with a cap, so that a public URL cannot
|
|
19
|
+
* bounce the request to an internal address.
|
|
20
|
+
* @param url The URL to fetch.
|
|
21
|
+
* @param headers The request headers.
|
|
22
|
+
* @returns The final response, or `null` if the URL is disallowed or there
|
|
23
|
+
* are too many redirects.
|
|
24
|
+
*/
|
|
25
|
+
async function fetchPublicUrl(url, headers) {
|
|
26
|
+
let current = url instanceof URL ? url : new URL(url);
|
|
27
|
+
let redirected = 0;
|
|
28
|
+
while (true) {
|
|
29
|
+
try {
|
|
30
|
+
await validatePublicUrl(current.href);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
if (e instanceof UrlError) {
|
|
33
|
+
logger.error("Refused to fetch a private or invalid URL {url}: {error}", {
|
|
34
|
+
url: current.href,
|
|
35
|
+
error: e
|
|
36
|
+
});
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
throw e;
|
|
40
|
+
}
|
|
41
|
+
const response = await fetch(current, {
|
|
42
|
+
headers,
|
|
43
|
+
redirect: "manual"
|
|
44
|
+
});
|
|
45
|
+
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
46
|
+
redirected++;
|
|
47
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) {
|
|
48
|
+
logger.error("Too many redirections ({redirections}) while fetching {url}.", {
|
|
49
|
+
redirections: redirected,
|
|
50
|
+
url: current.href
|
|
51
|
+
});
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const next = new URL(response.headers.get("Location"), response.url == null || response.url === "" ? current : response.url);
|
|
55
|
+
if (next.protocol !== current.protocol) {
|
|
56
|
+
logger.error("Refused a redirect to a different protocol ({protocol} to {redirectedProtocol}) while fetching NodeInfo.", {
|
|
57
|
+
protocol: current.protocol,
|
|
58
|
+
redirectedProtocol: next.protocol
|
|
59
|
+
});
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
current = next;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
return response;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
12
68
|
async function getNodeInfo(url, options = {}) {
|
|
13
69
|
try {
|
|
14
70
|
let nodeInfoUrl = url;
|
|
15
71
|
if (!options.direct) {
|
|
16
72
|
const wellKnownUrl = new URL("/.well-known/nodeinfo", url);
|
|
17
|
-
const wellKnownResponse = await
|
|
73
|
+
const wellKnownResponse = await fetchPublicUrl(wellKnownUrl, {
|
|
18
74
|
Accept: "application/json",
|
|
19
75
|
"User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
|
|
20
|
-
}
|
|
76
|
+
});
|
|
77
|
+
if (wellKnownResponse == null) return void 0;
|
|
21
78
|
if (!wellKnownResponse.ok) {
|
|
22
79
|
logger.error("Failed to fetch {url}: {status} {statusText}", {
|
|
23
80
|
url: wellKnownUrl.href,
|
|
@@ -37,10 +94,11 @@ async function getNodeInfo(url, options = {}) {
|
|
|
37
94
|
}
|
|
38
95
|
nodeInfoUrl = link.href;
|
|
39
96
|
}
|
|
40
|
-
const response = await
|
|
97
|
+
const response = await fetchPublicUrl(nodeInfoUrl, {
|
|
41
98
|
Accept: "application/json",
|
|
42
99
|
"User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
|
|
43
|
-
}
|
|
100
|
+
});
|
|
101
|
+
if (response == null) return void 0;
|
|
44
102
|
if (!response.ok) {
|
|
45
103
|
logger.error("Failed to fetch NodeInfo document from {url}: {status} {statusText}", {
|
|
46
104
|
url: nodeInfoUrl.toString(),
|
|
@@ -13,7 +13,7 @@ import { encodeHex } from "byte-encodings/hex";
|
|
|
13
13
|
async function digest(uris) {
|
|
14
14
|
const processed = /* @__PURE__ */ new Set();
|
|
15
15
|
const encoder = new TextEncoder();
|
|
16
|
-
const result = new Uint8Array(32);
|
|
16
|
+
const result = /* @__PURE__ */ new Uint8Array(32);
|
|
17
17
|
for (const uri of uris) {
|
|
18
18
|
const u = uri instanceof URL ? uri.href : uri;
|
|
19
19
|
if (processed.has(u)) continue;
|
package/dist/compat/mod.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_transformers = require("../transformers-
|
|
3
|
+
const require_transformers = require("../transformers-BalCrSsr.cjs");
|
|
4
4
|
exports.actorDehydrator = require_transformers.actorDehydrator;
|
|
5
5
|
exports.autoIdAssigner = require_transformers.autoIdAssigner;
|
|
6
6
|
exports.getDefaultActivityTransformers = require_transformers.getDefaultActivityTransformers;
|
package/dist/compat/mod.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { Gt as ActivityTransformer, n as Context } from "../context-B-dsBjZ9.cjs";
|
|
3
3
|
import { Activity } from "@fedify/vocab";
|
|
4
4
|
|
|
5
5
|
//#region src/compat/transformers.d.ts
|
package/dist/compat/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { Gt as ActivityTransformer, n as Context } from "../context-DrLXudbA.js";
|
|
3
3
|
import { Activity } from "@fedify/vocab";
|
|
4
4
|
|
|
5
5
|
//#region src/compat/transformers.d.ts
|