@fedify/fedify 2.1.24 → 2.1.26

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 (81) hide show
  1. package/dist/{builder-BatYe9a2.mjs → builder-9KbL1CoC.mjs} +11 -3
  2. package/dist/{client-DNiBssfx.mjs → client-DM72NZuk.mjs} +7 -3
  3. package/dist/compat/mod.d.cts +1 -1
  4. package/dist/compat/mod.d.ts +1 -1
  5. package/dist/compat/transformers.test.mjs +1 -1
  6. package/dist/{context-D4s0Wk3N.d.cts → context-BNwv9Q1v.d.cts} +1 -1
  7. package/dist/{context-BgU5UWTx.d.ts → context-DLLaDau8.d.ts} +1 -1
  8. package/dist/{deno-BXkm_rws.mjs → deno-ChmEXNOv.mjs} +1 -1
  9. package/dist/docloader-DEVImb5e.mjs +78 -0
  10. package/dist/federation/builder.test.mjs +37 -2
  11. package/dist/federation/collection.test.mjs +1 -1
  12. package/dist/federation/handler.test.mjs +7 -7
  13. package/dist/federation/idempotency.test.mjs +3 -3
  14. package/dist/federation/inbox.test.mjs +1 -1
  15. package/dist/federation/kv.test.mjs +1 -1
  16. package/dist/federation/middleware.test.mjs +249 -7
  17. package/dist/federation/mod.cjs +1 -1
  18. package/dist/federation/mod.d.cts +3 -3
  19. package/dist/federation/mod.d.ts +3 -3
  20. package/dist/federation/mod.js +1 -1
  21. package/dist/federation/mq.test.mjs +98 -43
  22. package/dist/federation/negotiation.test.mjs +1 -1
  23. package/dist/federation/router.test.mjs +1 -1
  24. package/dist/federation/send.test.mjs +68 -5
  25. package/dist/federation/temporal.test.mjs +2 -2
  26. package/dist/federation/webfinger.test.mjs +2 -2
  27. package/dist/{http-7FmLhLDv.cjs → http-BOH-uFLj.cjs} +6 -2
  28. package/dist/{http-UyebnM2c.mjs → http-B_M80hBW.mjs} +7 -3
  29. package/dist/{http-Chr54tTL.js → http-CeK9QmL_.js} +6 -2
  30. package/dist/{inbox-ByQ2iD14.mjs → inbox-B_O6TjZS.mjs} +1 -1
  31. package/dist/{key-A8SuFznD.mjs → key-BJcK-1Av.mjs} +1 -1
  32. package/dist/{kv-gJ8LYbxX.d.cts → kv-CZKl1IUS.d.cts} +3 -2
  33. package/dist/{kv-D6hNiMTK.d.ts → kv-CxaI4eGo.d.ts} +3 -2
  34. package/dist/{kv-cache-DJhBDA9T.cjs → kv-cache-BlOG31SS.cjs} +34 -8
  35. package/dist/{kv-cache-J6hmiAEd.js → kv-cache-CEJICY0R.js} +35 -9
  36. package/dist/{ld-BSvHU-S0.mjs → ld-YAXn6sG8.mjs} +3 -3
  37. package/dist/{middleware-Do50b12a.js → middleware-C-45wr85.js} +30 -10
  38. package/dist/{middleware-Dy18K1xP.mjs → middleware-Co_QOX9H.mjs} +21 -18
  39. package/dist/{middleware-CCYqHlzn.cjs → middleware-DHGVHIUj.cjs} +31 -11
  40. package/dist/{middleware-DvxNTKpl.mjs → middleware-DmTWC5VG.mjs} +1 -1
  41. package/dist/{middleware-Bddj287b.cjs → middleware-dGW2gSDG.cjs} +1 -1
  42. package/dist/{mod-Bx80LUTA.d.cts → mod-BmlfRBmU.d.cts} +1 -1
  43. package/dist/{mod-DcAiY74j.d.ts → mod-CWJNbyju.d.ts} +1 -1
  44. package/dist/{mod-DniKVJ_C.d.cts → mod-Cn9GJ5ex.d.cts} +3 -1
  45. package/dist/{mod-CMK_S-eX.d.ts → mod-DNEgTI8M.d.ts} +3 -1
  46. package/dist/mod.cjs +5 -5
  47. package/dist/mod.d.cts +4 -4
  48. package/dist/mod.d.ts +4 -4
  49. package/dist/mod.js +5 -5
  50. package/dist/nodeinfo/client.test.mjs +50 -2
  51. package/dist/nodeinfo/handler.test.mjs +2 -2
  52. package/dist/nodeinfo/mod.cjs +1 -1
  53. package/dist/nodeinfo/mod.js +1 -1
  54. package/dist/nodeinfo/types.test.mjs +1 -1
  55. package/dist/otel/exporter.test.mjs +1 -1
  56. package/dist/otel/mod.d.cts +1 -1
  57. package/dist/otel/mod.d.ts +1 -1
  58. package/dist/{owner-CaaCVHsG.mjs → owner-B3ZkY-Ov.mjs} +2 -2
  59. package/dist/{proof-BrOQrPQf.js → proof-BeGIkK97.js} +2 -2
  60. package/dist/{proof-_AyA4r7z.mjs → proof-DIGrz49z.mjs} +2 -2
  61. package/dist/{proof-CaCUMcvk.cjs → proof-DzOl2GlQ.cjs} +2 -2
  62. package/dist/{send-B1CRgb14.mjs → send-N2w1IwXT.mjs} +12 -3
  63. package/dist/sig/http.test.mjs +43 -3
  64. package/dist/sig/key.test.mjs +2 -2
  65. package/dist/sig/ld.test.mjs +5 -2
  66. package/dist/sig/mod.cjs +2 -2
  67. package/dist/sig/mod.js +2 -2
  68. package/dist/sig/owner.test.mjs +2 -2
  69. package/dist/sig/proof.test.mjs +2 -2
  70. package/dist/{std__assert-Duiq_YC9.mjs → std__assert-BUOJXi-Z.mjs} +1 -26
  71. package/dist/{temporal-Pmk5ouB1.mjs → temporal-CpT0u5Mx.mjs} +1 -1
  72. package/dist/{types-DWs-qZaY.cjs → types-DRPjmHVV.cjs} +7 -3
  73. package/dist/{types-sXITXcWa.js → types-miAYfiGO.js} +7 -3
  74. package/dist/utils/docloader.test.mjs +299 -3
  75. package/dist/utils/mod.cjs +1 -1
  76. package/dist/utils/mod.d.cts +1 -1
  77. package/dist/utils/mod.d.ts +1 -1
  78. package/dist/utils/mod.js +1 -1
  79. package/dist/vocab/cjs.test.mjs +1 -1
  80. package/package.json +7 -7
  81. package/dist/docloader-DdEK2tXP.mjs +0 -52
@@ -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-CCYqHlzn.cjs");
5
+ const require_middleware = require("../middleware-DHGVHIUj.cjs");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  //#region src/federation/kv.ts
8
8
  /**
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { $ as ActorKeyPairsDispatcher, A as createFederation, B as RouterRouteResult, C as InboxChallengePolicy, D as FederationKvPrefixes, E as Rfc6570Expression, F as Message, G as InProcessMessageQueueOptions, H as respondWithObject, I as createFederationBuilder, J as MessageQueueListenOptions, K as MessageQueue, L as Router, M as RetryContext, N as RetryPolicy, O as FederationOrigin, P as createExponentialBackoffPolicy, Q as ActorHandleMapper, R as RouterError, S as IdempotencyStrategy, St as digest, T as ObjectCallbackSetters, U as respondWithObjectIfAcceptable, V as RespondWithObjectOptions, W as InProcessMessageQueue, X as ActorAliasMapper, Y as ParallelMessageQueue, Z as ActorDispatcher, _ as FederationBuilder, _t as WebFingerLinksDispatcher, a as InboxContext, at as CustomCollectionCursor, b as FederationStartQueueOptions, bt as PageItems, c as RouteActivityOptions, ct as InboxListener, d as ActorCallbackSetters, dt as ObjectDispatcher, et as AuthorizePredicate, f as CollectionCallbackSetters, ft as OutboxErrorHandler, g as Federation, gt as UnverifiedActivityReason, h as Federatable, ht as UnverifiedActivityHandler, i as GetSignedKeyOptions, it as CustomCollectionCounter, j as CreateExponentialBackoffPolicyOptions, k as FederationQueueOptions, l as SendActivityOptions, lt as NodeInfoDispatcher, m as CustomCollectionCallbackSetters, mt as SharedInboxKeyDispatcher, n as Context, nt as CollectionCursor, o as ParseUriResult, ot as CustomCollectionDispatcher, p as ConstructorWithTypeId, pt as OutboxPermanentFailureHandler, q as MessageQueueEnqueueOptions, r as ForwardActivityOptions, rt as CollectionDispatcher, s as RequestContext, st as InboxErrorHandler, t as ActorKeyPair, tt as CollectionCounter, u as SendActivityOptionsForCollection, ut as ObjectAuthorizePredicate, v as FederationFetchOptions, vt as SendActivityError, w as InboxListenerSetters, x as IdempotencyKeyCallback, xt as buildCollectionSynchronizationHeader, y as FederationOptions, yt as SenderKeyPair, z as RouterOptions } from "../context-D4s0Wk3N.cjs";
3
- import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-gJ8LYbxX.cjs";
4
- import { n as handleWebFinger, t as WebFingerHandlerParameters } from "../mod-Bx80LUTA.cjs";
2
+ import { $ as ActorKeyPairsDispatcher, A as createFederation, B as RouterRouteResult, C as InboxChallengePolicy, D as FederationKvPrefixes, E as Rfc6570Expression, F as Message, G as InProcessMessageQueueOptions, H as respondWithObject, I as createFederationBuilder, J as MessageQueueListenOptions, K as MessageQueue, L as Router, M as RetryContext, N as RetryPolicy, O as FederationOrigin, P as createExponentialBackoffPolicy, Q as ActorHandleMapper, R as RouterError, S as IdempotencyStrategy, St as digest, T as ObjectCallbackSetters, U as respondWithObjectIfAcceptable, V as RespondWithObjectOptions, W as InProcessMessageQueue, X as ActorAliasMapper, Y as ParallelMessageQueue, Z as ActorDispatcher, _ as FederationBuilder, _t as WebFingerLinksDispatcher, a as InboxContext, at as CustomCollectionCursor, b as FederationStartQueueOptions, bt as PageItems, c as RouteActivityOptions, ct as InboxListener, d as ActorCallbackSetters, dt as ObjectDispatcher, et as AuthorizePredicate, f as CollectionCallbackSetters, ft as OutboxErrorHandler, g as Federation, gt as UnverifiedActivityReason, h as Federatable, ht as UnverifiedActivityHandler, i as GetSignedKeyOptions, it as CustomCollectionCounter, j as CreateExponentialBackoffPolicyOptions, k as FederationQueueOptions, l as SendActivityOptions, lt as NodeInfoDispatcher, m as CustomCollectionCallbackSetters, mt as SharedInboxKeyDispatcher, n as Context, nt as CollectionCursor, o as ParseUriResult, ot as CustomCollectionDispatcher, p as ConstructorWithTypeId, pt as OutboxPermanentFailureHandler, q as MessageQueueEnqueueOptions, r as ForwardActivityOptions, rt as CollectionDispatcher, s as RequestContext, st as InboxErrorHandler, t as ActorKeyPair, tt as CollectionCounter, u as SendActivityOptionsForCollection, ut as ObjectAuthorizePredicate, v as FederationFetchOptions, vt as SendActivityError, w as InboxListenerSetters, x as IdempotencyKeyCallback, xt as buildCollectionSynchronizationHeader, y as FederationOptions, yt as SenderKeyPair, z as RouterOptions } from "../context-BNwv9Q1v.cjs";
3
+ import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-CZKl1IUS.cjs";
4
+ import { n as handleWebFinger, t as WebFingerHandlerParameters } from "../mod-BmlfRBmU.cjs";
5
5
  export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MemoryKvStore, Message, MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxErrorHandler, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, respondWithObject, respondWithObjectIfAcceptable };
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { $ as ActorKeyPairsDispatcher, A as createFederation, B as RouterRouteResult, C as InboxChallengePolicy, D as FederationKvPrefixes, E as Rfc6570Expression, F as Message, G as InProcessMessageQueueOptions, H as respondWithObject, I as createFederationBuilder, J as MessageQueueListenOptions, K as MessageQueue, L as Router, M as RetryContext, N as RetryPolicy, O as FederationOrigin, P as createExponentialBackoffPolicy, Q as ActorHandleMapper, R as RouterError, S as IdempotencyStrategy, St as digest, T as ObjectCallbackSetters, U as respondWithObjectIfAcceptable, V as RespondWithObjectOptions, W as InProcessMessageQueue, X as ActorAliasMapper, Y as ParallelMessageQueue, Z as ActorDispatcher, _ as FederationBuilder, _t as WebFingerLinksDispatcher, a as InboxContext, at as CustomCollectionCursor, b as FederationStartQueueOptions, bt as PageItems, c as RouteActivityOptions, ct as InboxListener, d as ActorCallbackSetters, dt as ObjectDispatcher, et as AuthorizePredicate, f as CollectionCallbackSetters, ft as OutboxErrorHandler, g as Federation, gt as UnverifiedActivityReason, h as Federatable, ht as UnverifiedActivityHandler, i as GetSignedKeyOptions, it as CustomCollectionCounter, j as CreateExponentialBackoffPolicyOptions, k as FederationQueueOptions, l as SendActivityOptions, lt as NodeInfoDispatcher, m as CustomCollectionCallbackSetters, mt as SharedInboxKeyDispatcher, n as Context, nt as CollectionCursor, o as ParseUriResult, ot as CustomCollectionDispatcher, p as ConstructorWithTypeId, pt as OutboxPermanentFailureHandler, q as MessageQueueEnqueueOptions, r as ForwardActivityOptions, rt as CollectionDispatcher, s as RequestContext, st as InboxErrorHandler, t as ActorKeyPair, tt as CollectionCounter, u as SendActivityOptionsForCollection, ut as ObjectAuthorizePredicate, v as FederationFetchOptions, vt as SendActivityError, w as InboxListenerSetters, x as IdempotencyKeyCallback, xt as buildCollectionSynchronizationHeader, y as FederationOptions, yt as SenderKeyPair, z as RouterOptions } from "../context-BgU5UWTx.js";
3
- import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-D6hNiMTK.js";
4
- import { n as handleWebFinger, t as WebFingerHandlerParameters } from "../mod-DcAiY74j.js";
2
+ import { $ as ActorKeyPairsDispatcher, A as createFederation, B as RouterRouteResult, C as InboxChallengePolicy, D as FederationKvPrefixes, E as Rfc6570Expression, F as Message, G as InProcessMessageQueueOptions, H as respondWithObject, I as createFederationBuilder, J as MessageQueueListenOptions, K as MessageQueue, L as Router, M as RetryContext, N as RetryPolicy, O as FederationOrigin, P as createExponentialBackoffPolicy, Q as ActorHandleMapper, R as RouterError, S as IdempotencyStrategy, St as digest, T as ObjectCallbackSetters, U as respondWithObjectIfAcceptable, V as RespondWithObjectOptions, W as InProcessMessageQueue, X as ActorAliasMapper, Y as ParallelMessageQueue, Z as ActorDispatcher, _ as FederationBuilder, _t as WebFingerLinksDispatcher, a as InboxContext, at as CustomCollectionCursor, b as FederationStartQueueOptions, bt as PageItems, c as RouteActivityOptions, ct as InboxListener, d as ActorCallbackSetters, dt as ObjectDispatcher, et as AuthorizePredicate, f as CollectionCallbackSetters, ft as OutboxErrorHandler, g as Federation, gt as UnverifiedActivityReason, h as Federatable, ht as UnverifiedActivityHandler, i as GetSignedKeyOptions, it as CustomCollectionCounter, j as CreateExponentialBackoffPolicyOptions, k as FederationQueueOptions, l as SendActivityOptions, lt as NodeInfoDispatcher, m as CustomCollectionCallbackSetters, mt as SharedInboxKeyDispatcher, n as Context, nt as CollectionCursor, o as ParseUriResult, ot as CustomCollectionDispatcher, p as ConstructorWithTypeId, pt as OutboxPermanentFailureHandler, q as MessageQueueEnqueueOptions, r as ForwardActivityOptions, rt as CollectionDispatcher, s as RequestContext, st as InboxErrorHandler, t as ActorKeyPair, tt as CollectionCounter, u as SendActivityOptionsForCollection, ut as ObjectAuthorizePredicate, v as FederationFetchOptions, vt as SendActivityError, w as InboxListenerSetters, x as IdempotencyKeyCallback, xt as buildCollectionSynchronizationHeader, y as FederationOptions, yt as SenderKeyPair, z as RouterOptions } from "../context-DLLaDau8.js";
3
+ import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-CxaI4eGo.js";
4
+ import { n as handleWebFinger, t as WebFingerHandlerParameters } from "../mod-CWJNbyju.js";
5
5
  export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MemoryKvStore, Message, MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxErrorHandler, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, respondWithObject, respondWithObjectIfAcceptable };
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "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-Do50b12a.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-C-45wr85.js";
4
4
  import { isEqual } from "es-toolkit";
5
5
  //#region src/federation/kv.ts
6
6
  /**
@@ -2,7 +2,7 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
- import { i as assertGreaterOrEqual, r as assertGreater } from "../std__assert-Duiq_YC9.mjs";
5
+ import { r as assertGreaterOrEqual } from "../std__assert-BUOJXi-Z.mjs";
6
6
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assert } from "../assert-BhQd8QHP.mjs";
8
8
  import { test } from "@fedify/fixture";
@@ -248,50 +248,105 @@ test("InProcessMessageQueue", async (t) => {
248
248
  const listening = mq.listen((message) => {
249
249
  messages.push(message);
250
250
  }, controller);
251
- await t.step("enqueue()", async () => {
252
- await mq.enqueue("Hello, world!");
253
- });
254
- await waitFor(() => messages.length > 0, 15e3);
255
- await t.step("listen()", () => {
256
- assertEquals(messages, ["Hello, world!"]);
257
- });
258
- let started = 0;
259
- await t.step("enqueue() with delay", async () => {
260
- started = Date.now();
261
- await mq.enqueue("Delayed message", { delay: Temporal.Duration.from({ seconds: 3 }) });
262
- assertEquals(messages, ["Hello, world!"]);
263
- });
264
- await waitFor(() => messages.length > 1, 15e3);
265
- await t.step("listen() with delay", () => {
266
- assertEquals(messages, ["Hello, world!", "Delayed message"]);
267
- assertGreater(Date.now() - started, 3e3);
268
- });
269
- while (messages.length > 0) messages.pop();
270
- await t.step("enqueueMany()", async () => {
271
- const testMessages = Array.from({ length: 5 }, (_, i) => `Batch message ${i}!`);
272
- await mq.enqueueMany(testMessages);
273
- });
274
- await waitFor(() => messages.length >= 5, 15e3);
275
- await t.step("listen() [multiple]", () => {
276
- assertEquals(messages.length, 5);
277
- for (let i = 0; i < 5; i++) assertEquals(messages[i], `Batch message ${i}!`);
278
- });
279
- while (messages.length > 0) messages.pop();
280
- started = 0;
281
- await t.step("enqueueMany() with delay", async () => {
282
- started = Date.now();
283
- const testMessages = Array.from({ length: 3 }, (_, i) => `Delayed batch ${i}!`);
284
- await mq.enqueueMany(testMessages, { delay: Temporal.Duration.from({ seconds: 2 }) });
285
- assertEquals(messages.length, 0);
251
+ try {
252
+ await t.step("enqueue()", async () => {
253
+ await mq.enqueue("Hello, world!");
254
+ });
255
+ await waitFor(() => messages.length > 0, 15e3);
256
+ await t.step("listen()", () => {
257
+ assertEquals(messages, ["Hello, world!"]);
258
+ });
259
+ await t.step("enqueue() with delay", async () => {
260
+ const { timers, enqueued } = captureTimers(() => mq.enqueue("Delayed message", { delay: Temporal.Duration.from({ seconds: 3 }) }));
261
+ await enqueued;
262
+ assertEquals(timers.length, 1);
263
+ assertEquals(timers[0].delay, 3e3);
264
+ await mq.enqueue("Single delay marker");
265
+ await waitFor(() => messages.includes("Single delay marker"), 15e3);
266
+ assertEquals(messages, ["Hello, world!", "Single delay marker"]);
267
+ timers[0].callback();
268
+ });
269
+ await waitFor(() => messages.length >= 3, 15e3);
270
+ await t.step("listen() with delay", () => {
271
+ assertEquals(messages, [
272
+ "Hello, world!",
273
+ "Single delay marker",
274
+ "Delayed message"
275
+ ]);
276
+ });
277
+ while (messages.length > 0) messages.pop();
278
+ await t.step("enqueueMany()", async () => {
279
+ const testMessages = Array.from({ length: 5 }, (_, i) => `Batch message ${i}!`);
280
+ await mq.enqueueMany(testMessages);
281
+ });
282
+ await waitFor(() => messages.length >= 5, 15e3);
283
+ await t.step("listen() [multiple]", () => {
284
+ assertEquals(messages.length, 5);
285
+ for (let i = 0; i < 5; i++) assertEquals(messages[i], `Batch message ${i}!`);
286
+ });
287
+ while (messages.length > 0) messages.pop();
288
+ await t.step("enqueueMany() with delay", async () => {
289
+ const testMessages = Array.from({ length: 3 }, (_, i) => `Delayed batch ${i}!`);
290
+ const { timers, enqueued } = captureTimers(() => mq.enqueueMany(testMessages, { delay: Temporal.Duration.from({ seconds: 2 }) }));
291
+ await enqueued;
292
+ assertEquals(timers.length, 1);
293
+ assertEquals(timers[0].delay, 2e3);
294
+ await mq.enqueue("Batch delay marker");
295
+ await waitFor(() => messages.includes("Batch delay marker"), 15e3);
296
+ assertEquals(messages, ["Batch delay marker"]);
297
+ timers[0].callback();
298
+ });
299
+ await waitFor(() => messages.length >= 4, 15e3);
300
+ await t.step("listen() [delayed multiple]", () => {
301
+ assertEquals(messages.length, 4);
302
+ assertEquals(messages[0], "Batch delay marker");
303
+ for (let i = 0; i < 3; i++) assertEquals(messages[i + 1], `Delayed batch ${i}!`);
304
+ });
305
+ } finally {
306
+ controller.abort();
307
+ await listening;
308
+ }
309
+ });
310
+ function captureTimers(enqueue) {
311
+ const timers = [];
312
+ const original = globalThis.setTimeout;
313
+ globalThis.setTimeout = ((callback, delay) => {
314
+ timers.push({
315
+ callback,
316
+ delay
317
+ });
318
+ return 0;
286
319
  });
287
- await waitFor(() => messages.length >= 3, 15e3);
288
- await t.step("listen() [delayed multiple]", () => {
289
- assertEquals(messages.length, 3);
290
- assertGreater(Date.now() - started, 2e3);
291
- for (let i = 0; i < 3; i++) assertEquals(messages[i], `Delayed batch ${i}!`);
320
+ try {
321
+ return {
322
+ timers,
323
+ enqueued: enqueue()
324
+ };
325
+ } finally {
326
+ globalThis.setTimeout = original;
327
+ }
328
+ }
329
+ test("InProcessMessageQueue real delay", async (t) => {
330
+ for (const batch of [false, true]) await t.step(batch ? "enqueueMany()" : "enqueue()", async () => {
331
+ const mq = new InProcessMessageQueue();
332
+ const messages = [];
333
+ const controller = new AbortController();
334
+ const listening = mq.listen((message) => {
335
+ messages.push(message);
336
+ }, controller);
337
+ try {
338
+ const delayed = batch ? ["Delayed 1", "Delayed 2"] : ["Delayed"];
339
+ const options = { delay: Temporal.Duration.from({ milliseconds: 100 }) };
340
+ if (batch) await mq.enqueueMany(delayed, options);
341
+ else await mq.enqueue(delayed[0], options);
342
+ await mq.enqueue("Immediate");
343
+ await waitFor(() => messages.length >= delayed.length + 1, 15e3);
344
+ assertEquals(messages, ["Immediate", ...delayed]);
345
+ } finally {
346
+ controller.abort();
347
+ await listening;
348
+ }
292
349
  });
293
- controller.abort();
294
- await listening;
295
350
  });
296
351
  test("InProcessMessageQueue orderingKey", async (t) => {
297
352
  const mq = new InProcessMessageQueue();
@@ -1,7 +1,7 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import "../std__assert-Duiq_YC9.mjs";
4
+ import "../std__assert-BUOJXi-Z.mjs";
5
5
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assert } from "../assert-BhQd8QHP.mjs";
7
7
  import { t as acceptsJsonLd } from "../negotiation-BehA2uul.mjs";
@@ -3,7 +3,7 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError, t as Router } from "../router-CrMLXoOr.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
- import "../std__assert-Duiq_YC9.mjs";
6
+ import "../std__assert-BUOJXi-Z.mjs";
7
7
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { t as assert } from "../assert-BhQd8QHP.mjs";
9
9
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
@@ -3,17 +3,18 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as esm_default } from "../esm-DVILvP5e.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
- import "../std__assert-Duiq_YC9.mjs";
6
+ import "../std__assert-BUOJXi-Z.mjs";
7
7
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
9
9
  import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
10
- import { l as verifyRequest } from "../http-UyebnM2c.mjs";
10
+ import { l as verifyRequest } from "../http-B_M80hBW.mjs";
11
11
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
12
- import { t as doesActorOwnKey } from "../owner-CaaCVHsG.mjs";
13
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-B1CRgb14.mjs";
12
+ import { t as doesActorOwnKey } from "../owner-B3ZkY-Ov.mjs";
13
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-N2w1IwXT.mjs";
14
14
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
15
15
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
16
- import { UrlError } from "@fedify/vocab-runtime";
16
+ import { FetchError, UrlError } from "@fedify/vocab-runtime";
17
+ import dns from "node:dns/promises";
17
18
  //#region src/federation/send.test.ts
18
19
  test("extractInboxes()", () => {
19
20
  const recipients = [
@@ -547,5 +548,67 @@ for (const signed of [false, true]) {
547
548
  });
548
549
  });
549
550
  }
551
+ for (const signed of [false, true]) test({
552
+ name: `sendActivity() classifies DNS failures (signed: ${signed})`,
553
+ ignore: "Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted",
554
+ async fn(t) {
555
+ const activity = {
556
+ type: "Create",
557
+ id: "https://example.com/activity"
558
+ };
559
+ const destination = "https://delivery.invalid/inbox";
560
+ const publicInbox = "https://8.8.8.8/inbox";
561
+ const keys = signed ? [{
562
+ privateKey: rsaPrivateKey2,
563
+ keyId: rsaPublicKey2.id
564
+ }] : [];
565
+ for (const result of [
566
+ "throws",
567
+ "empty",
568
+ "cname",
569
+ "private"
570
+ ]) for (const redirected of [false, true]) await t.step(`${result}, redirected: ${redirected}`, async () => {
571
+ const originalLookup = dns.lookup;
572
+ const resolverError = /* @__PURE__ */ new Error("Resolver unavailable");
573
+ const lookups = [];
574
+ dns.lookup = ((hostname, options) => {
575
+ lookups.push(hostname);
576
+ assertEquals(hostname, "delivery.invalid");
577
+ assertEquals(options, { all: true });
578
+ if (result === "throws") return Promise.reject(resolverError);
579
+ return Promise.resolve(result === "empty" ? [] : [{
580
+ address: result === "private" ? "127.0.0.1" : "alias.invalid.",
581
+ family: 4
582
+ }]);
583
+ });
584
+ try {
585
+ esm_default.mockGlobal().catch(202);
586
+ if (redirected) esm_default.route(publicInbox, {
587
+ status: 307,
588
+ headers: { Location: destination }
589
+ });
590
+ const send = () => sendActivity({
591
+ activity,
592
+ keys,
593
+ inbox: new URL(redirected ? publicInbox : destination)
594
+ });
595
+ if (result === "private") assertEquals((await assertRejects(send, UrlError)).reason, "disallowed");
596
+ else {
597
+ const error = await assertRejects(send, FetchError);
598
+ assertEquals(error.url.href, destination);
599
+ assertInstanceOf(error.cause, UrlError);
600
+ assertEquals(error.cause.reason, "dns");
601
+ assertEquals(error.cause.cause, result === "throws" ? resolverError : void 0);
602
+ }
603
+ assertEquals(lookups, ["delivery.invalid"]);
604
+ assertEquals(esm_default.callHistory.calls(destination).length, 0);
605
+ assertEquals(esm_default.callHistory.calls().length, redirected ? 1 : 0);
606
+ } finally {
607
+ dns.lookup = originalLookup;
608
+ esm_default.hardReset();
609
+ }
610
+ });
611
+ }
612
+ });
550
613
  //#endregion
551
614
  export {};
@@ -1,10 +1,10 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import "../std__assert-Duiq_YC9.mjs";
4
+ import "../std__assert-BUOJXi-Z.mjs";
5
5
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assert } from "../assert-BhQd8QHP.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-Pmk5ouB1.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-CpT0u5Mx.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  //#region src/federation/temporal.test.ts
10
10
  test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
@@ -3,9 +3,9 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
- import "../std__assert-Duiq_YC9.mjs";
6
+ import "../std__assert-BUOJXi-Z.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { a as createFederation, o as handleWebFinger } from "../middleware-Dy18K1xP.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-Co_QOX9H.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
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
11
11
  let byte_encodings_base64 = require("byte-encodings/base64");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.1.24";
14
+ var version = "2.1.26";
15
15
  //#endregion
16
16
  //#region src/sig/accept.ts
17
17
  /**
@@ -1315,6 +1315,8 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1315
1315
  return invalidSignatureResult(null);
1316
1316
  }
1317
1317
  let failure = noSignatureResult();
1318
+ let body = null;
1319
+ let digestValid = null;
1318
1320
  for (const sigName of signatureNames) {
1319
1321
  if (!signatures[sigName]) {
1320
1322
  failure = invalidSignatureResult(parseKeyId(signatureInputs[sigName]?.keyId));
@@ -1366,7 +1368,9 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1366
1368
  failure = invalidSignatureResult(keyId);
1367
1369
  continue;
1368
1370
  }
1369
- if (!await verifyRfc9421ContentDigest(contentDigestHeader, await request.arrayBuffer())) {
1371
+ body ??= await request.arrayBuffer();
1372
+ digestValid ??= await verifyRfc9421ContentDigest(contentDigestHeader, body);
1373
+ if (!digestValid) {
1370
1374
  logger.debug("Failed to verify; Content-Digest verification failed.", { contentDigest: contentDigestHeader });
1371
1375
  failure = invalidSignatureResult(keyId);
1372
1376
  continue;
@@ -1,9 +1,9 @@
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-BXkm_rws.mjs";
4
+ import { n as version, t as name } from "./deno-ChmEXNOv.mjs";
5
5
  import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-BavzedPB.mjs";
6
- import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-A8SuFznD.mjs";
6
+ import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-BJcK-1Av.mjs";
7
7
  import { CryptographicKey } from "@fedify/vocab";
8
8
  import { SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { FetchError } from "@fedify/vocab-runtime";
@@ -674,6 +674,8 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
674
674
  return invalidSignatureResult(null);
675
675
  }
676
676
  let failure = noSignatureResult();
677
+ let body = null;
678
+ let digestValid = null;
677
679
  for (const sigName of signatureNames) {
678
680
  if (!signatures[sigName]) {
679
681
  failure = invalidSignatureResult(parseKeyId(signatureInputs[sigName]?.keyId));
@@ -725,7 +727,9 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
725
727
  failure = invalidSignatureResult(keyId);
726
728
  continue;
727
729
  }
728
- if (!await verifyRfc9421ContentDigest(contentDigestHeader, await request.arrayBuffer())) {
730
+ body ??= await request.arrayBuffer();
731
+ digestValid ??= await verifyRfc9421ContentDigest(contentDigestHeader, body);
732
+ if (!digestValid) {
729
733
  logger.debug("Failed to verify; Content-Digest verification failed.", { contentDigest: contentDigestHeader });
730
734
  failure = invalidSignatureResult(keyId);
731
735
  continue;
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
10
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.1.24";
13
+ var version = "2.1.26";
14
14
  //#endregion
15
15
  //#region src/sig/accept.ts
16
16
  /**
@@ -1314,6 +1314,8 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1314
1314
  return invalidSignatureResult(null);
1315
1315
  }
1316
1316
  let failure = noSignatureResult();
1317
+ let body = null;
1318
+ let digestValid = null;
1317
1319
  for (const sigName of signatureNames) {
1318
1320
  if (!signatures[sigName]) {
1319
1321
  failure = invalidSignatureResult(parseKeyId(signatureInputs[sigName]?.keyId));
@@ -1365,7 +1367,9 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1365
1367
  failure = invalidSignatureResult(keyId);
1366
1368
  continue;
1367
1369
  }
1368
- if (!await verifyRfc9421ContentDigest(contentDigestHeader, await request.arrayBuffer())) {
1370
+ body ??= await request.arrayBuffer();
1371
+ digestValid ??= await verifyRfc9421ContentDigest(contentDigestHeader, body);
1372
+ if (!digestValid) {
1369
1373
  logger.debug("Failed to verify; Content-Digest verification failed.", { contentDigest: contentDigestHeader });
1370
1374
  failure = invalidSignatureResult(keyId);
1371
1375
  continue;
@@ -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-BXkm_rws.mjs";
4
+ import { n as version, t as name } from "./deno-ChmEXNOv.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-BXkm_rws.mjs";
4
+ import { n as version, t as name } from "./deno-ChmEXNOv.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 { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
@@ -41,14 +41,15 @@ interface KvStore {
41
41
  /**
42
42
  * Gets the value for the given key.
43
43
  * @param key The key to get the value for.
44
- * @returns The value for the key, or `undefined` if the key does not exist.
44
+ * @returns The value for the key, including `null` if stored, or `undefined`
45
+ * if the key does not exist.
45
46
  * @template T The type of the value to get.
46
47
  */
47
48
  get<T = unknown>(key: KvKey): Promise<T | undefined>;
48
49
  /**
49
50
  * Sets the value for the given key.
50
51
  * @param key The key to set the value for.
51
- * @param value The value to set.
52
+ * @param value The value to set. `null` is a storable value.
52
53
  * @param options Additional options for setting the value.
53
54
  */
54
55
  set(key: KvKey, value: unknown, options?: KvStoreSetOptions): Promise<void>;
@@ -41,14 +41,15 @@ interface KvStore {
41
41
  /**
42
42
  * Gets the value for the given key.
43
43
  * @param key The key to get the value for.
44
- * @returns The value for the key, or `undefined` if the key does not exist.
44
+ * @returns The value for the key, including `null` if stored, or `undefined`
45
+ * if the key does not exist.
45
46
  * @template T The type of the value to get.
46
47
  */
47
48
  get<T = unknown>(key: KvKey): Promise<T | undefined>;
48
49
  /**
49
50
  * Sets the value for the given key.
50
51
  * @param key The key to set the value for.
51
- * @param value The value to set.
52
+ * @param value The value to set. `null` is a storable value.
52
53
  * @param options Additional options for setting the value.
53
54
  */
54
55
  set(key: KvKey, value: unknown, options?: KvStoreSetOptions): Promise<void>;
@@ -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-7FmLhLDv.cjs");
4
+ const require_http = require("./http-BOH-uFLj.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");
@@ -11,10 +11,13 @@ const logger$1 = (0, _logtape_logtape.getLogger)([
11
11
  "utils",
12
12
  "docloader"
13
13
  ]);
14
+ const DEFAULT_MAX_REDIRECTION = 20;
14
15
  /**
15
16
  * Gets an authenticated {@link DocumentLoader} for the given identity.
16
17
  * Note that an authenticated document loader intentionally does not cache
17
18
  * the fetched documents.
19
+ * At most 20 HTTP redirects and alternate document links are followed in total
20
+ * per call. Revisiting a URL within that chain throws a {@link FetchError}.
18
21
  * @param identity The identity to get the document loader for.
19
22
  * The actor's key pair.
20
23
  * @param options The options for the document loader.
@@ -24,28 +27,51 @@ const logger$1 = (0, _logtape_logtape.getLogger)([
24
27
  */
25
28
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAgent, specDeterminer, tracerProvider } = {}) {
26
29
  require_http.validateCryptoKey(identity.privateKey);
27
- async function load(url, options) {
28
- await validateUrl(url);
29
- return (0, _fedify_vocab_runtime.getRemoteDocument)(url, await require_http.doubleKnock((0, _fedify_vocab_runtime.createActivityPubRequest)(url, { userAgent }), identity, {
30
+ async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
31
+ options?.signal?.throwIfAborted();
32
+ let currentUrl = new URL(url).href;
33
+ await validateUrl(currentUrl);
34
+ visited.add(currentUrl);
35
+ const originalRequest = (0, _fedify_vocab_runtime.createActivityPubRequest)(currentUrl, { userAgent });
36
+ function follow(nextUrl) {
37
+ options?.signal?.throwIfAborted();
38
+ if (redirected >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
39
+ if (visited.has(nextUrl)) throw new _fedify_vocab_runtime.FetchError(currentUrl, `Redirect loop detected: ${nextUrl}`);
40
+ redirected++;
41
+ }
42
+ const response = await require_http.doubleKnock(originalRequest, identity, {
30
43
  specDeterminer,
31
44
  log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
32
45
  tracerProvider,
33
46
  signal: options?.signal,
34
- validateRedirect: validateUrl
35
- }), load);
47
+ validateRedirect: async (nextUrl) => {
48
+ follow(nextUrl);
49
+ await validateUrl(nextUrl);
50
+ visited.add(nextUrl);
51
+ currentUrl = nextUrl;
52
+ }
53
+ });
54
+ return (0, _fedify_vocab_runtime.getRemoteDocument)(currentUrl, response, (alternateUrl) => {
55
+ follow(alternateUrl);
56
+ return load(alternateUrl, options, redirected, visited);
57
+ });
36
58
  }
37
59
  async function validateUrl(url) {
38
60
  if (!allowPrivateAddress) try {
39
61
  await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
40
62
  } catch (error) {
41
- if (error instanceof _fedify_vocab_runtime.UrlError) logger$1.error("Disallowed private URL: {url}", {
63
+ if (error instanceof _fedify_vocab_runtime.UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
64
+ url,
65
+ error
66
+ });
67
+ else logger$1.error("Disallowed private URL: {url}", {
42
68
  url,
43
69
  error
44
70
  });
45
71
  throw error;
46
72
  }
47
73
  }
48
- return load;
74
+ return (url, options) => load(url, options);
49
75
  }
50
76
  //#endregion
51
77
  //#region src/utils/kv-cache.ts