@fedify/fedify 2.0.15 → 2.0.17-dev.1080

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.
Files changed (45) hide show
  1. package/dist/{builder-rsIMkx0e.mjs → builder-C_byVzVJ.mjs} +3 -3
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-xSddAZaQ.mjs → deno-D5gaJgRc.mjs} +1 -1
  4. package/dist/{docloader-EEa8l7rO.mjs → docloader-CvKTIDM7.mjs} +2 -2
  5. package/dist/federation/builder.test.mjs +1 -1
  6. package/dist/federation/handler.test.mjs +3 -3
  7. package/dist/federation/idempotency.test.mjs +2 -2
  8. package/dist/federation/inbox.test.mjs +1 -1
  9. package/dist/federation/middleware.test.mjs +6 -6
  10. package/dist/federation/mod.cjs +1 -1
  11. package/dist/federation/mod.js +1 -1
  12. package/dist/federation/send.test.mjs +3 -3
  13. package/dist/federation/webfinger.test.mjs +1 -1
  14. package/dist/{http-jayDBg25.js → http-C19JWDY5.js} +57 -9
  15. package/dist/{http-DB5aGn32.cjs → http-DW1wS5OQ.cjs} +57 -9
  16. package/dist/{http-CPD4PQw4.mjs → http-Dcu53K4y.mjs} +58 -10
  17. package/dist/{inbox-B9vUzjTt.mjs → inbox-CjBSPOkc.mjs} +1 -1
  18. package/dist/{key-Cf_ZePpW.mjs → key-BIpsBirA.mjs} +1 -1
  19. package/dist/{kv-cache-CX7QaY_P.js → kv-cache-CRCy-MKv.js} +1 -1
  20. package/dist/{kv-cache-CWn2N2gc.cjs → kv-cache-DMuTztCK.cjs} +1 -1
  21. package/dist/{ld-Bo_rc82m.mjs → ld-DIubdqww.mjs} +2 -2
  22. package/dist/{middleware-AofmfEvT.mjs → middleware-0aOx7tFs.mjs} +10 -10
  23. package/dist/{middleware-dpkHvN8F.cjs → middleware-6_tXcikP.cjs} +4 -4
  24. package/dist/{middleware-CTusQ_ge.js → middleware-BGhaaIwq.js} +3 -3
  25. package/dist/{middleware-4-n8zsaK.mjs → middleware-D5oazePf.mjs} +1 -1
  26. package/dist/{middleware-_eeUkjGS.cjs → middleware-MNB__QV2.cjs} +1 -1
  27. package/dist/mod.cjs +4 -4
  28. package/dist/mod.js +4 -4
  29. package/dist/nodeinfo/handler.test.mjs +1 -1
  30. package/dist/{owner-dxnNrpf6.mjs → owner-G_2WBguN.mjs} +2 -2
  31. package/dist/{proof-DQRM6x31.js → proof-BBaK9BGh.js} +1 -1
  32. package/dist/{proof-CSJIYTru.cjs → proof-D0WmM_BP.cjs} +1 -1
  33. package/dist/{proof-CxgjjxQX.mjs → proof-DaNQaDFZ.mjs} +2 -2
  34. package/dist/{send-CExoEh2q.mjs → send-B74ipE6l.mjs} +2 -2
  35. package/dist/sig/http.test.mjs +121 -3
  36. package/dist/sig/key.test.mjs +1 -1
  37. package/dist/sig/ld.test.mjs +2 -2
  38. package/dist/sig/mod.cjs +2 -2
  39. package/dist/sig/mod.js +2 -2
  40. package/dist/sig/owner.test.mjs +1 -1
  41. package/dist/sig/proof.test.mjs +1 -1
  42. package/dist/utils/docloader.test.mjs +2 -2
  43. package/dist/utils/mod.cjs +1 -1
  44. package/dist/utils/mod.js +1 -1
  45. package/package.json +5 -5
@@ -2,8 +2,8 @@ import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError, t as Router } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
6
- import { t as InboxListenerSet } from "./inbox-B9vUzjTt.mjs";
5
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
6
+ import { t as InboxListenerSet } from "./inbox-CjBSPOkc.mjs";
7
7
  import { getTypeId } from "@fedify/vocab";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { getLogger } from "@logtape/logtape";
@@ -42,7 +42,7 @@ var FederationBuilderImpl = class {
42
42
  this.collectionTypeIds = {};
43
43
  }
44
44
  async build(options) {
45
- const { FederationImpl } = await import("./middleware-4-n8zsaK.mjs");
45
+ const { FederationImpl } = await import("./middleware-D5oazePf.mjs");
46
46
  const f = new FederationImpl(options);
47
47
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
48
48
  f.router = this.router.clone();
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
6
6
  import { t as assert } from "../assert-ddO5KLpe.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-AofmfEvT.mjs";
8
+ import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-0aOx7tFs.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Follow, Person } from "@fedify/vocab";
11
11
  //#region src/compat/transformers.test.ts
@@ -3,6 +3,6 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  //#region deno.json
5
5
  var name = "@fedify/fedify";
6
- var version = "2.0.15";
6
+ var version = "2.0.17-dev.1080+6cfb9a34";
7
7
  //#endregion
8
8
  export { version as n, name as t };
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { a as validateCryptoKey } from "./key-Cf_ZePpW.mjs";
5
- import { n as doubleKnock } from "./http-CPD4PQw4.mjs";
4
+ import { a as validateCryptoKey } from "./key-BIpsBirA.mjs";
5
+ import { n as doubleKnock } from "./http-Dcu53K4y.mjs";
6
6
  import { curry } from "es-toolkit";
7
7
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, validatePublicUrl } from "@fedify/vocab-runtime";
8
8
  import { getLogger } from "@logtape/logtape";
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { a as assertExists } from "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { n as createFederationBuilder } from "../builder-rsIMkx0e.mjs";
8
+ import { n as createFederationBuilder } from "../builder-C_byVzVJ.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Activity, Note, Person } from "@fedify/vocab";
11
11
  //#region src/federation/builder.test.ts
@@ -5,11 +5,11 @@ import { n as createRequestContext, t as createInboxContext } from "../context-J
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-Duiq_YC9.mjs";
7
7
  import { t as assert } from "../assert-ddO5KLpe.mjs";
8
- import { s as signRequest } from "../http-CPD4PQw4.mjs";
8
+ import { s as signRequest } from "../http-Dcu53K4y.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
10
10
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
11
- import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-AofmfEvT.mjs";
12
- import { t as InboxListenerSet } from "../inbox-B9vUzjTt.mjs";
11
+ import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-0aOx7tFs.mjs";
12
+ import { t as InboxListenerSet } from "../inbox-CjBSPOkc.mjs";
13
13
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { Create, Note, Person } from "@fedify/vocab";
15
15
  //#region src/federation/handler.test.ts
@@ -4,9 +4,9 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-Duiq_YC9.mjs";
6
6
  import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
7
- import { n as signObject } from "../proof-CxgjjxQX.mjs";
7
+ import { n as signObject } from "../proof-DaNQaDFZ.mjs";
8
8
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
9
- import { a as createFederation } from "../middleware-AofmfEvT.mjs";
9
+ import { a as createFederation } from "../middleware-0aOx7tFs.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, Follow, Person } from "@fedify/vocab";
12
12
  //#region src/federation/idempotency.test.ts
@@ -3,7 +3,7 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
6
- import { t as InboxListenerSet } from "../inbox-B9vUzjTt.mjs";
6
+ import { t as InboxListenerSet } from "../inbox-CjBSPOkc.mjs";
7
7
  import { test } from "@fedify/fixture";
8
8
  import { Activity, Create, Invite, Offer, Update } from "@fedify/vocab";
9
9
  //#region src/federation/inbox.test.ts
@@ -10,14 +10,14 @@ import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
10
10
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
11
11
  import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
12
12
  import { t as assert } from "../assert-ddO5KLpe.mjs";
13
- import { l as verifyRequest, s as signRequest } from "../http-CPD4PQw4.mjs";
13
+ import { l as verifyRequest, s as signRequest } from "../http-Dcu53K4y.mjs";
14
14
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
15
- import { t as getAuthenticatedDocumentLoader } from "../docloader-EEa8l7rO.mjs";
16
- import { a as signJsonLd, o as verifyJsonLd, r as detachSignature } from "../ld-Bo_rc82m.mjs";
17
- import { t as doesActorOwnKey } from "../owner-dxnNrpf6.mjs";
18
- import { n as signObject, r as verifyObject } from "../proof-CxgjjxQX.mjs";
15
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-CvKTIDM7.mjs";
16
+ import { a as signJsonLd, o as verifyJsonLd, r as detachSignature } from "../ld-DIubdqww.mjs";
17
+ import { t as doesActorOwnKey } from "../owner-G_2WBguN.mjs";
18
+ import { n as signObject, r as verifyObject } from "../proof-DaNQaDFZ.mjs";
19
19
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
20
- import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-AofmfEvT.mjs";
20
+ import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-0aOx7tFs.mjs";
21
21
  import { mockDocumentLoader, test } from "@fedify/fixture";
22
22
  import * as vocab from "@fedify/vocab";
23
23
  import { getTypeId, lookupObject } from "@fedify/vocab";
@@ -2,7 +2,7 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
4
  require("../chunk-DDcVe30Y.cjs");
5
- const require_middleware = require("../middleware-dpkHvN8F.cjs");
5
+ const require_middleware = require("../middleware-6_tXcikP.cjs");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  //#region src/federation/kv.ts
8
8
  /**
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "../middleware-CTusQ_ge.js";
3
+ import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "../middleware-BGhaaIwq.js";
4
4
  import { isEqual } from "es-toolkit";
5
5
  //#region src/federation/kv.ts
6
6
  /**
@@ -8,10 +8,10 @@ import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z
8
8
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
9
9
  import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
10
10
  import { t as assert } from "../assert-ddO5KLpe.mjs";
11
- import { l as verifyRequest } from "../http-CPD4PQw4.mjs";
11
+ import { l as verifyRequest } from "../http-Dcu53K4y.mjs";
12
12
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
13
- import { t as doesActorOwnKey } from "../owner-dxnNrpf6.mjs";
14
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-CExoEh2q.mjs";
13
+ import { t as doesActorOwnKey } from "../owner-G_2WBguN.mjs";
14
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-B74ipE6l.mjs";
15
15
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
16
16
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
17
17
  //#region src/federation/send.test.ts
@@ -5,7 +5,7 @@ import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-Duiq_YC9.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { a as createFederation, o as handleWebFinger } from "../middleware-AofmfEvT.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-0aOx7tFs.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Image, Link, Person } from "@fedify/vocab";
11
11
  //#region src/federation/webfinger.test.ts
@@ -10,7 +10,7 @@ import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
10
10
  import { Item, decodeDict, encodeItem } from "structured-field-values";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.0.15";
13
+ var version = "2.0.17-dev.1080+6cfb9a34";
14
14
  //#endregion
15
15
  //#region src/sig/key.ts
16
16
  /**
@@ -260,6 +260,7 @@ async function fetchKeyInternal(keyId, cls, { documentLoader, contextLoader, key
260
260
  //#endregion
261
261
  //#region src/sig/http.ts
262
262
  const DEFAULT_MAX_REDIRECTION = 20;
263
+ const DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS = 100;
263
264
  /**
264
265
  * Signs a request using the given private key.
265
266
  * @param request The request to sign.
@@ -950,6 +951,59 @@ function createRedirectRequest(request, location, body) {
950
951
  cache: request.cache
951
952
  });
952
953
  }
954
+ async function fetchDoubleKnockRequest(request, signedRequest, signal) {
955
+ const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
956
+ for (let attempt = 1;; attempt++) try {
957
+ return await fetch(signedRequest, {
958
+ redirect: "manual",
959
+ signal
960
+ });
961
+ } catch (error) {
962
+ const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
963
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
964
+ if (isAbortError(error)) throw error;
965
+ if (attempt >= maxAttempts) throw createFetchError(request.url, error);
966
+ await sleep(DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS, signal, request.signal, signedRequest.signal);
967
+ }
968
+ }
969
+ function createFetchError(url, cause) {
970
+ const error = new FetchError(url, cause instanceof Error ? cause.message : String(cause));
971
+ error.cause = cause;
972
+ return error;
973
+ }
974
+ function isAbortError(error) {
975
+ return error instanceof Error && error.name === "AbortError";
976
+ }
977
+ async function sleep(ms, ...signals) {
978
+ const abortSignals = signals.filter((signal) => signal != null);
979
+ const abortedSignal = getAbortedSignal(...abortSignals);
980
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
981
+ if (abortSignals.length < 1) {
982
+ await new Promise((resolve) => setTimeout(resolve, ms));
983
+ return;
984
+ }
985
+ await new Promise((resolve, reject) => {
986
+ const removeAbortListeners = () => {
987
+ for (const signal of abortSignals) signal.removeEventListener("abort", handleAbort);
988
+ };
989
+ const timeout = setTimeout(() => {
990
+ removeAbortListeners();
991
+ resolve();
992
+ }, ms);
993
+ function handleAbort(event) {
994
+ clearTimeout(timeout);
995
+ removeAbortListeners();
996
+ reject(getAbortReason(event.currentTarget));
997
+ }
998
+ for (const signal of abortSignals) signal.addEventListener("abort", handleAbort, { once: true });
999
+ });
1000
+ }
1001
+ function getAbortedSignal(...signals) {
1002
+ return signals.find((signal) => signal?.aborted);
1003
+ }
1004
+ function getAbortReason(signal) {
1005
+ return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
1006
+ }
953
1007
  /**
954
1008
  * Performs a double-knock request to the given URL. For the details of
955
1009
  * double-knocking, see
@@ -975,10 +1029,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
975
1029
  body
976
1030
  });
977
1031
  log?.(signedRequest);
978
- let response = await fetch(signedRequest, {
979
- redirect: "manual",
980
- signal
981
- });
1032
+ let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
982
1033
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
983
1034
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
984
1035
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -1005,10 +1056,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1005
1056
  body
1006
1057
  });
1007
1058
  log?.(signedRequest);
1008
- response = await fetch(signedRequest, {
1009
- redirect: "manual",
1010
- signal
1011
- });
1059
+ response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1012
1060
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1013
1061
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1014
1062
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -11,7 +11,7 @@ let byte_encodings_base64 = require("byte-encodings/base64");
11
11
  let structured_field_values = require("structured-field-values");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.0.15";
14
+ var version = "2.0.17-dev.1080+6cfb9a34";
15
15
  //#endregion
16
16
  //#region src/sig/key.ts
17
17
  /**
@@ -261,6 +261,7 @@ async function fetchKeyInternal(keyId, cls, { documentLoader, contextLoader, key
261
261
  //#endregion
262
262
  //#region src/sig/http.ts
263
263
  const DEFAULT_MAX_REDIRECTION = 20;
264
+ const DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS = 100;
264
265
  /**
265
266
  * Signs a request using the given private key.
266
267
  * @param request The request to sign.
@@ -951,6 +952,59 @@ function createRedirectRequest(request, location, body) {
951
952
  cache: request.cache
952
953
  });
953
954
  }
955
+ async function fetchDoubleKnockRequest(request, signedRequest, signal) {
956
+ const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
957
+ for (let attempt = 1;; attempt++) try {
958
+ return await fetch(signedRequest, {
959
+ redirect: "manual",
960
+ signal
961
+ });
962
+ } catch (error) {
963
+ const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
964
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
965
+ if (isAbortError(error)) throw error;
966
+ if (attempt >= maxAttempts) throw createFetchError(request.url, error);
967
+ await sleep(DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS, signal, request.signal, signedRequest.signal);
968
+ }
969
+ }
970
+ function createFetchError(url, cause) {
971
+ const error = new _fedify_vocab_runtime.FetchError(url, cause instanceof Error ? cause.message : String(cause));
972
+ error.cause = cause;
973
+ return error;
974
+ }
975
+ function isAbortError(error) {
976
+ return error instanceof Error && error.name === "AbortError";
977
+ }
978
+ async function sleep(ms, ...signals) {
979
+ const abortSignals = signals.filter((signal) => signal != null);
980
+ const abortedSignal = getAbortedSignal(...abortSignals);
981
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
982
+ if (abortSignals.length < 1) {
983
+ await new Promise((resolve) => setTimeout(resolve, ms));
984
+ return;
985
+ }
986
+ await new Promise((resolve, reject) => {
987
+ const removeAbortListeners = () => {
988
+ for (const signal of abortSignals) signal.removeEventListener("abort", handleAbort);
989
+ };
990
+ const timeout = setTimeout(() => {
991
+ removeAbortListeners();
992
+ resolve();
993
+ }, ms);
994
+ function handleAbort(event) {
995
+ clearTimeout(timeout);
996
+ removeAbortListeners();
997
+ reject(getAbortReason(event.currentTarget));
998
+ }
999
+ for (const signal of abortSignals) signal.addEventListener("abort", handleAbort, { once: true });
1000
+ });
1001
+ }
1002
+ function getAbortedSignal(...signals) {
1003
+ return signals.find((signal) => signal?.aborted);
1004
+ }
1005
+ function getAbortReason(signal) {
1006
+ return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
1007
+ }
954
1008
  /**
955
1009
  * Performs a double-knock request to the given URL. For the details of
956
1010
  * double-knocking, see
@@ -976,10 +1030,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
976
1030
  body
977
1031
  });
978
1032
  log?.(signedRequest);
979
- let response = await fetch(signedRequest, {
980
- redirect: "manual",
981
- signal
982
- });
1033
+ let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
983
1034
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
984
1035
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
985
1036
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -1006,10 +1057,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1006
1057
  body
1007
1058
  });
1008
1059
  log?.(signedRequest);
1009
- response = await fetch(signedRequest, {
1010
- redirect: "manual",
1011
- signal
1012
- });
1060
+ response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1013
1061
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1014
1062
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1015
1063
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -1,8 +1,8 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
5
- import { a as validateCryptoKey, n as fetchKey } from "./key-Cf_ZePpW.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
+ import { a as validateCryptoKey, n as fetchKey } from "./key-BIpsBirA.mjs";
6
6
  import { CryptographicKey } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { FetchError } from "@fedify/vocab-runtime";
@@ -13,6 +13,7 @@ import { encodeHex } from "byte-encodings/hex";
13
13
  import { Item, decodeDict, encodeItem } from "structured-field-values";
14
14
  //#region src/sig/http.ts
15
15
  const DEFAULT_MAX_REDIRECTION = 20;
16
+ const DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS = 100;
16
17
  /**
17
18
  * Signs a request using the given private key.
18
19
  * @param request The request to sign.
@@ -703,6 +704,59 @@ function createRedirectRequest(request, location, body) {
703
704
  cache: request.cache
704
705
  });
705
706
  }
707
+ async function fetchDoubleKnockRequest(request, signedRequest, signal) {
708
+ const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
709
+ for (let attempt = 1;; attempt++) try {
710
+ return await fetch(signedRequest, {
711
+ redirect: "manual",
712
+ signal
713
+ });
714
+ } catch (error) {
715
+ const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
716
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
717
+ if (isAbortError(error)) throw error;
718
+ if (attempt >= maxAttempts) throw createFetchError(request.url, error);
719
+ await sleep(DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS, signal, request.signal, signedRequest.signal);
720
+ }
721
+ }
722
+ function createFetchError(url, cause) {
723
+ const error = new FetchError(url, cause instanceof Error ? cause.message : String(cause));
724
+ error.cause = cause;
725
+ return error;
726
+ }
727
+ function isAbortError(error) {
728
+ return error instanceof Error && error.name === "AbortError";
729
+ }
730
+ async function sleep(ms, ...signals) {
731
+ const abortSignals = signals.filter((signal) => signal != null);
732
+ const abortedSignal = getAbortedSignal(...abortSignals);
733
+ if (abortedSignal != null) throw getAbortReason(abortedSignal);
734
+ if (abortSignals.length < 1) {
735
+ await new Promise((resolve) => setTimeout(resolve, ms));
736
+ return;
737
+ }
738
+ await new Promise((resolve, reject) => {
739
+ const removeAbortListeners = () => {
740
+ for (const signal of abortSignals) signal.removeEventListener("abort", handleAbort);
741
+ };
742
+ const timeout = setTimeout(() => {
743
+ removeAbortListeners();
744
+ resolve();
745
+ }, ms);
746
+ function handleAbort(event) {
747
+ clearTimeout(timeout);
748
+ removeAbortListeners();
749
+ reject(getAbortReason(event.currentTarget));
750
+ }
751
+ for (const signal of abortSignals) signal.addEventListener("abort", handleAbort, { once: true });
752
+ });
753
+ }
754
+ function getAbortedSignal(...signals) {
755
+ return signals.find((signal) => signal?.aborted);
756
+ }
757
+ function getAbortReason(signal) {
758
+ return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
759
+ }
706
760
  /**
707
761
  * Performs a double-knock request to the given URL. For the details of
708
762
  * double-knocking, see
@@ -728,10 +782,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
728
782
  body
729
783
  });
730
784
  log?.(signedRequest);
731
- let response = await fetch(signedRequest, {
732
- redirect: "manual",
733
- signal
734
- });
785
+ let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
735
786
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
736
787
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
737
788
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -758,10 +809,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
758
809
  body
759
810
  });
760
811
  log?.(signedRequest);
761
- response = await fetch(signedRequest, {
762
- redirect: "manual",
763
- signal
764
- });
812
+ response = await fetchDoubleKnockRequest(request, signedRequest, signal);
765
813
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
766
814
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
767
815
  const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
5
  import { Activity, getTypeId } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
@@ -1,7 +1,7 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
5
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { c as validateCryptoKey, t as doubleKnock } from "./http-jayDBg25.js";
3
+ import { c as validateCryptoKey, t as doubleKnock } from "./http-C19JWDY5.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-DB5aGn32.cjs");
4
+ const require_http = require("./http-DW1wS5OQ.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
5
- import { a as validateCryptoKey, n as fetchKey } from "./key-Cf_ZePpW.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
+ import { a as validateCryptoKey, n as fetchKey } from "./key-BIpsBirA.mjs";
6
6
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -2,23 +2,23 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
6
- import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key-Cf_ZePpW.mjs";
7
- import { l as verifyRequest } from "./http-CPD4PQw4.mjs";
8
- import { t as getAuthenticatedDocumentLoader } from "./docloader-EEa8l7rO.mjs";
5
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
6
+ import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key-BIpsBirA.mjs";
7
+ import { l as verifyRequest } from "./http-Dcu53K4y.mjs";
8
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-CvKTIDM7.mjs";
9
9
  import { n as kvCache } from "./kv-cache-OWmRLHir.mjs";
10
- import { a as signJsonLd, i as hasSignature, o as verifyJsonLd, r as detachSignature } from "./ld-Bo_rc82m.mjs";
11
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-dxnNrpf6.mjs";
12
- import { n as signObject, r as verifyObject } from "./proof-CxgjjxQX.mjs";
10
+ import { a as signJsonLd, i as hasSignature, o as verifyJsonLd, r as detachSignature } from "./ld-DIubdqww.mjs";
11
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-G_2WBguN.mjs";
12
+ import { n as signObject, r as verifyObject } from "./proof-DaNQaDFZ.mjs";
13
13
  import { t as getNodeInfo } from "./client-A1UrnX6I.mjs";
14
14
  import { t as nodeInfoToJson } from "./types-C37hquWI.mjs";
15
- import { n as routeActivity } from "./inbox-B9vUzjTt.mjs";
16
- import { t as FederationBuilderImpl } from "./builder-rsIMkx0e.mjs";
15
+ import { n as routeActivity } from "./inbox-CjBSPOkc.mjs";
16
+ import { t as FederationBuilderImpl } from "./builder-C_byVzVJ.mjs";
17
17
  import { t as buildCollectionSynchronizationHeader } from "./collection-ChgDTHLz.mjs";
18
18
  import { t as KvKeyCache } from "./keycache-DaQ3ndaJ.mjs";
19
19
  import { t as acceptsJsonLd } from "./negotiation-BehA2uul.mjs";
20
20
  import { t as createExponentialBackoffPolicy } from "./retry-Ddbq3AcK.mjs";
21
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CExoEh2q.mjs";
21
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-B74ipE6l.mjs";
22
22
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
23
23
  import { lookupWebFinger } from "@fedify/webfinger";
24
24
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
4
  const require_transformers = require("./transformers-NeAONrAq.cjs");
5
- const require_http = require("./http-DB5aGn32.cjs");
6
- const require_proof = require("./proof-CSJIYTru.cjs");
5
+ const require_http = require("./http-DW1wS5OQ.cjs");
6
+ const require_proof = require("./proof-D0WmM_BP.cjs");
7
7
  const require_types = require("./types-KC4QAoxe.cjs");
8
- const require_kv_cache = require("./kv-cache-CWn2N2gc.cjs");
8
+ const require_kv_cache = require("./kv-cache-DMuTztCK.cjs");
9
9
  let _logtape_logtape = require("@logtape/logtape");
10
10
  let _fedify_vocab = require("@fedify/vocab");
11
11
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -330,7 +330,7 @@ var FederationBuilderImpl = class {
330
330
  this.collectionTypeIds = {};
331
331
  }
332
332
  async build(options) {
333
- const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-_eeUkjGS.cjs"));
333
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-MNB__QV2.cjs"));
334
334
  const f = new FederationImpl(options);
335
335
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
336
336
  f.router = this.router.clone();
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./chunk-nlSIicah.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-ve6e2xcg.js";
5
- import { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-jayDBg25.js";
6
- import { a as doesActorOwnKey, d as signJsonLd, f as verifyJsonLd, l as detachSignature, n as signObject, o as getKeyOwner, r as verifyObject, u as hasSignature } from "./proof-DQRM6x31.js";
5
+ import { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-C19JWDY5.js";
6
+ import { a as doesActorOwnKey, d as signJsonLd, f as verifyJsonLd, l as detachSignature, n as signObject, o as getKeyOwner, r as verifyObject, u as hasSignature } from "./proof-BBaK9BGh.js";
7
7
  import { n as getNodeInfo, t as nodeInfoToJson } from "./types-hvL8ElAs.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CX7QaY_P.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CRCy-MKv.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
11
11
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -1,5 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as FederationImpl } from "./middleware-AofmfEvT.mjs";
4
+ import { n as FederationImpl } from "./middleware-0aOx7tFs.mjs";
5
5
  export { FederationImpl };
@@ -1,4 +1,4 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
- const require_middleware = require("./middleware-dpkHvN8F.cjs");
3
+ const require_middleware = require("./middleware-6_tXcikP.cjs");
4
4
  exports.FederationImpl = require_middleware.FederationImpl;
package/dist/mod.cjs CHANGED
@@ -4,11 +4,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
4
  require("./chunk-DDcVe30Y.cjs");
5
5
  const require_transformers = require("./transformers-NeAONrAq.cjs");
6
6
  require("./compat/mod.cjs");
7
- const require_http = require("./http-DB5aGn32.cjs");
8
- const require_middleware = require("./middleware-dpkHvN8F.cjs");
9
- const require_proof = require("./proof-CSJIYTru.cjs");
7
+ const require_http = require("./http-DW1wS5OQ.cjs");
8
+ const require_middleware = require("./middleware-6_tXcikP.cjs");
9
+ const require_proof = require("./proof-D0WmM_BP.cjs");
10
10
  const require_types = require("./types-KC4QAoxe.cjs");
11
- const require_kv_cache = require("./kv-cache-CWn2N2gc.cjs");
11
+ const require_kv_cache = require("./kv-cache-DMuTztCK.cjs");
12
12
  const require_federation_mod = require("./federation/mod.cjs");
13
13
  require("./nodeinfo/mod.cjs");
14
14
  require("./runtime/mod.cjs");
package/dist/mod.js CHANGED
@@ -3,11 +3,11 @@ import "urlpattern-polyfill";
3
3
  import "./chunk-nlSIicah.js";
4
4
  import { n as autoIdAssigner, r as getDefaultActivityTransformers, t as actorDehydrator } from "./transformers-ve6e2xcg.js";
5
5
  import "./compat/mod.js";
6
- import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "./http-jayDBg25.js";
7
- import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "./middleware-CTusQ_ge.js";
8
- import { a as doesActorOwnKey, c as createSignature, d as signJsonLd, f as verifyJsonLd, i as verifyProof, l as detachSignature, n as signObject, o as getKeyOwner, p as verifySignature, r as verifyObject, s as attachSignature, t as createProof } from "./proof-DQRM6x31.js";
6
+ import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "./http-C19JWDY5.js";
7
+ import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "./middleware-BGhaaIwq.js";
8
+ import { a as doesActorOwnKey, c as createSignature, d as signJsonLd, f as verifyJsonLd, i as verifyProof, l as detachSignature, n as signObject, o as getKeyOwner, p as verifySignature, r as verifyObject, s as attachSignature, t as createProof } from "./proof-BBaK9BGh.js";
9
9
  import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "./types-hvL8ElAs.js";
10
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CX7QaY_P.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CRCy-MKv.js";
11
11
  import { InProcessMessageQueue, MemoryKvStore, ParallelMessageQueue } from "./federation/mod.js";
12
12
  import "./nodeinfo/mod.js";
13
13
  import "./runtime/mod.js";
@@ -5,7 +5,7 @@ import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-Duiq_YC9.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-AofmfEvT.mjs";
8
+ import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-0aOx7tFs.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  //#region src/nodeinfo/handler.test.ts
11
11
  test("handleNodeInfo()", async () => {
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
5
- import "./key-Cf_ZePpW.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
+ import "./key-BIpsBirA.mjs";
6
6
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
7
7
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { a as fetchKey, c as validateCryptoKey, l as name, u as version } from "./http-jayDBg25.js";
3
+ import { a as fetchKey, c as validateCryptoKey, l as name, u as version } from "./http-C19JWDY5.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, getTypeId, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-DB5aGn32.cjs");
4
+ const require_http = require("./http-DW1wS5OQ.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let _fedify_vocab = require("@fedify/vocab");
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -1,8 +1,8 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
5
- import { a as validateCryptoKey, n as fetchKey } from "./key-Cf_ZePpW.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
+ import { a as validateCryptoKey, n as fetchKey } from "./key-BIpsBirA.mjs";
6
6
  import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getLogger } from "@logtape/logtape";
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-xSddAZaQ.mjs";
5
- import { n as doubleKnock } from "./http-CPD4PQw4.mjs";
4
+ import { n as version, t as name } from "./deno-D5gaJgRc.mjs";
5
+ import { n as doubleKnock } from "./http-Dcu53K4y.mjs";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  //#region src/federation/send.ts
@@ -7,11 +7,11 @@ import { a as assertExists, t as assertStringIncludes } from "../std__assert-Dui
7
7
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
9
9
  import { t as assert } from "../assert-ddO5KLpe.mjs";
10
- import { t as exportJwk } from "../key-Cf_ZePpW.mjs";
11
- import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase } from "../http-CPD4PQw4.mjs";
10
+ import { t as exportJwk } from "../key-BIpsBirA.mjs";
11
+ import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase } from "../http-Dcu53K4y.mjs";
12
12
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
13
13
  import { mockDocumentLoader, test } from "@fedify/fixture";
14
- import { exportSpki } from "@fedify/vocab-runtime";
14
+ import { FetchError, exportSpki } from "@fedify/vocab-runtime";
15
15
  import { encodeBase64 } from "byte-encodings/base64";
16
16
  //#region src/sig/http.test.ts
17
17
  test("signRequest() [draft-cavage]", async () => {
@@ -833,6 +833,124 @@ test("doubleKnock() detects redirect loops", async () => {
833
833
  assertEquals(requestCount, 2);
834
834
  esm_default.hardReset();
835
835
  });
836
+ test("doubleKnock() retries idempotent request transport errors", async () => {
837
+ esm_default.spyGlobal();
838
+ try {
839
+ let requestCount = 0;
840
+ esm_default.get("https://example.com/flaky-document", () => {
841
+ requestCount++;
842
+ if (requestCount === 1) throw new TypeError("temporary DNS failure");
843
+ return new Response("Success", { status: 200 });
844
+ });
845
+ const response = await doubleKnock(new Request("https://example.com/flaky-document"), {
846
+ keyId: rsaPublicKey2.id,
847
+ privateKey: rsaPrivateKey2
848
+ });
849
+ assertEquals(response.status, 200);
850
+ assertEquals(await response.text(), "Success");
851
+ assertEquals(requestCount, 2);
852
+ } finally {
853
+ esm_default.hardReset();
854
+ }
855
+ });
856
+ test("doubleKnock() wraps repeated transport errors", async () => {
857
+ esm_default.spyGlobal();
858
+ try {
859
+ let requestCount = 0;
860
+ const failure = /* @__PURE__ */ new TypeError("DNS lookup failed");
861
+ esm_default.get("https://example.com/unreachable-document", () => {
862
+ requestCount++;
863
+ throw failure;
864
+ });
865
+ const request = new Request("https://example.com/unreachable-document");
866
+ const error = await assertRejects(() => doubleKnock(request, {
867
+ keyId: rsaPublicKey2.id,
868
+ privateKey: rsaPrivateKey2
869
+ }), FetchError, "DNS lookup failed");
870
+ assertEquals(error.url.href, "https://example.com/unreachable-document");
871
+ assertEquals(error.cause, failure);
872
+ assertEquals(requestCount, 2);
873
+ } finally {
874
+ esm_default.hardReset();
875
+ }
876
+ });
877
+ test("doubleKnock() does not retry non-idempotent transport errors", async () => {
878
+ esm_default.spyGlobal();
879
+ try {
880
+ let requestCount = 0;
881
+ const failure = /* @__PURE__ */ new TypeError("connection reset");
882
+ esm_default.post("https://example.com/flaky-inbox", () => {
883
+ requestCount++;
884
+ throw failure;
885
+ });
886
+ const request = new Request("https://example.com/flaky-inbox", {
887
+ method: "POST",
888
+ body: "Test activity content",
889
+ headers: { "Content-Type": "application/activity+json" }
890
+ });
891
+ const error = await assertRejects(() => doubleKnock(request, {
892
+ keyId: rsaPublicKey2.id,
893
+ privateKey: rsaPrivateKey2
894
+ }), FetchError, "connection reset");
895
+ assertEquals(error.url.href, "https://example.com/flaky-inbox");
896
+ assertEquals(error.cause, failure);
897
+ assertEquals(requestCount, 1);
898
+ } finally {
899
+ esm_default.hardReset();
900
+ }
901
+ });
902
+ test("doubleKnock() preserves Request signal abort reasons", async () => {
903
+ const controller = new AbortController();
904
+ const abortReason = "request aborted";
905
+ controller.abort(abortReason);
906
+ const request = new Request("https://example.com/request-abort", { signal: controller.signal });
907
+ assertEquals(await assertRejects(() => doubleKnock(request, {
908
+ keyId: rsaPublicKey2.id,
909
+ privateKey: rsaPrivateKey2
910
+ })), abortReason);
911
+ });
912
+ test("doubleKnock() preserves Request signal aborts during retry delay", async () => {
913
+ esm_default.spyGlobal();
914
+ try {
915
+ let requestCount = 0;
916
+ const controller = new AbortController();
917
+ const abortReason = "retry aborted";
918
+ esm_default.get("https://example.com/aborted-retry", () => {
919
+ requestCount++;
920
+ setTimeout(() => controller.abort(abortReason));
921
+ throw new TypeError("temporary DNS failure");
922
+ });
923
+ const request = new Request("https://example.com/aborted-retry", { signal: controller.signal });
924
+ assertEquals(await assertRejects(() => doubleKnock(request, {
925
+ keyId: rsaPublicKey2.id,
926
+ privateKey: rsaPrivateKey2
927
+ })), abortReason);
928
+ assertEquals(requestCount, 1);
929
+ } finally {
930
+ esm_default.hardReset();
931
+ }
932
+ });
933
+ test("doubleKnock() prefers Request aborts over transport errors", async () => {
934
+ esm_default.spyGlobal();
935
+ try {
936
+ let requestCount = 0;
937
+ const controller = new AbortController();
938
+ const abortReason = "transport aborted";
939
+ esm_default.get("https://example.com/abort-with-transport-error", () => {
940
+ requestCount++;
941
+ controller.abort(abortReason);
942
+ throw new TypeError("temporary DNS failure");
943
+ });
944
+ const request = new Request("https://example.com/abort-with-transport-error", { signal: controller.signal });
945
+ assertEquals(await assertRejects(() => doubleKnock(request, {
946
+ keyId: rsaPublicKey2.id,
947
+ privateKey: rsaPrivateKey2
948
+ })), abortReason);
949
+ assertEquals(requestCount, 1);
950
+ } finally {
951
+ esm_default.hardReset();
952
+ }
953
+ });
836
954
  test("doubleKnock() async specDeterminer test", async () => {
837
955
  esm_default.spyGlobal();
838
956
  let requestCount = 0;
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
8
- import { a as validateCryptoKey, i as importJwk, n as fetchKey, r as generateCryptoKeyPair, t as exportJwk } from "../key-Cf_ZePpW.mjs";
8
+ import { a as validateCryptoKey, i as importJwk, n as fetchKey, r as generateCryptoKeyPair, t as exportJwk } from "../key-BIpsBirA.mjs";
9
9
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";
@@ -5,9 +5,9 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
7
7
  import { t as assert } from "../assert-ddO5KLpe.mjs";
8
- import { r as generateCryptoKeyPair } from "../key-Cf_ZePpW.mjs";
8
+ import { r as generateCryptoKeyPair } from "../key-BIpsBirA.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
10
- import { a as signJsonLd, n as createSignature, o as verifyJsonLd, r as detachSignature, s as verifySignature, t as attachSignature } from "../ld-Bo_rc82m.mjs";
10
+ import { a as signJsonLd, n as createSignature, o as verifyJsonLd, r as detachSignature, s as verifySignature, t as attachSignature } from "../ld-DIubdqww.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { CryptographicKey } from "@fedify/vocab";
13
13
  import { encodeBase64 } from "byte-encodings/base64";
package/dist/sig/mod.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const require_http = require("../http-DB5aGn32.cjs");
5
- const require_proof = require("../proof-CSJIYTru.cjs");
4
+ const require_http = require("../http-DW1wS5OQ.cjs");
5
+ const require_proof = require("../proof-D0WmM_BP.cjs");
6
6
  exports.attachSignature = require_proof.attachSignature;
7
7
  exports.createProof = require_proof.createProof;
8
8
  exports.createSignature = require_proof.createSignature;
package/dist/sig/mod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "../http-jayDBg25.js";
4
- import { a as doesActorOwnKey, c as createSignature, d as signJsonLd, f as verifyJsonLd, i as verifyProof, l as detachSignature, n as signObject, o as getKeyOwner, p as verifySignature, r as verifyObject, s as attachSignature, t as createProof } from "../proof-DQRM6x31.js";
3
+ import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "../http-C19JWDY5.js";
4
+ import { a as doesActorOwnKey, c as createSignature, d as signJsonLd, f as verifyJsonLd, i as verifyProof, l as detachSignature, n as signObject, o as getKeyOwner, p as verifySignature, r as verifyObject, s as attachSignature, t as createProof } from "../proof-BBaK9BGh.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, generateCryptoKeyPair, getKeyOwner, importJwk, signJsonLd, signObject, signRequest, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifySignature };
@@ -6,7 +6,7 @@ import "../std__assert-Duiq_YC9.mjs";
6
6
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assert } from "../assert-ddO5KLpe.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-dxnNrpf6.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-G_2WBguN.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
12
12
  //#region src/sig/owner.test.ts
@@ -6,7 +6,7 @@ import "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
8
8
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
9
- import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-CxgjjxQX.mjs";
9
+ import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-DaNQaDFZ.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, DataIntegrityProof, Multikey, Note, Place } from "@fedify/vocab";
12
12
  import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
@@ -5,9 +5,9 @@ import { t as esm_default } from "../esm-DVILvP5e.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-Duiq_YC9.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
- import { l as verifyRequest } from "../http-CPD4PQw4.mjs";
8
+ import { l as verifyRequest } from "../http-Dcu53K4y.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-CtZLJq76.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-EEa8l7rO.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-CvKTIDM7.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { UrlError } from "@fedify/vocab-runtime";
13
13
  //#region src/utils/docloader.test.ts
@@ -1,6 +1,6 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const require_kv_cache = require("../kv-cache-CWn2N2gc.cjs");
4
+ const require_kv_cache = require("../kv-cache-DMuTztCK.cjs");
5
5
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
6
6
  exports.kvCache = require_kv_cache.kvCache;
package/dist/utils/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-CX7QaY_P.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-CRCy-MKv.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.0.15",
3
+ "version": "2.0.17-dev.1080+6cfb9a34",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -144,9 +144,9 @@
144
144
  "uri-template-router": "^1.0.0",
145
145
  "url-template": "^3.1.1",
146
146
  "urlpattern-polyfill": "^10.1.0",
147
- "@fedify/vocab-runtime": "2.0.15",
148
- "@fedify/webfinger": "2.0.15",
149
- "@fedify/vocab": "2.0.15"
147
+ "@fedify/vocab": "2.0.17-dev.1080+6cfb9a34",
148
+ "@fedify/vocab-runtime": "2.0.17-dev.1080+6cfb9a34",
149
+ "@fedify/webfinger": "2.0.17-dev.1080+6cfb9a34"
150
150
  },
151
151
  "devDependencies": {
152
152
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -159,7 +159,7 @@
159
159
  "typescript": "^5.9.2",
160
160
  "wrangler": "^4.17.0",
161
161
  "@fedify/fixture": "2.0.0",
162
- "@fedify/vocab-tools": "^2.0.15"
162
+ "@fedify/vocab-tools": "^2.0.17-dev.1080+6cfb9a34"
163
163
  },
164
164
  "scripts": {
165
165
  "build:self": "tsdown",