@fedify/fedify 2.0.0-pr.412.1559 → 2.0.0-pr.412.1794

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 (204) hide show
  1. package/README.md +3 -0
  2. package/dist/{actor-Cc6B76eG.js → actor-BXHc5r-q.js} +1 -1
  3. package/dist/actor-Ba9Z1eNJ.cjs +42079 -0
  4. package/dist/{actor-C22bXuuC.d.ts → actor-DqFajh9s.d.ts} +2 -2
  5. package/dist/{actor-CTAuCsWy.js → actor-DzhunPC_.js} +7058 -2722
  6. package/dist/actor-f2NtjyCg.d.cts +128 -0
  7. package/dist/{assert_rejects-DiIiJbZn.js → assert_rejects-Ce45JcFg.js} +1 -1
  8. package/dist/{assert_is_error-BPGph1Jx.js → assert_throws-BNXdRGWP.js} +31 -1
  9. package/dist/{builder-BOEBObR8.js → builder-u7usRsT3.js} +13 -8
  10. package/dist/chunk-DqRYRqnO.cjs +34 -0
  11. package/dist/client-94iWEfQa.d.cts +222 -0
  12. package/dist/{client-DF8anIB5.d.ts → client-BsGzbnV-.d.ts} +3 -75
  13. package/dist/{client-De-z2UnN.js → client-pY7-3icS.js} +3 -22
  14. package/dist/compat/mod.cjs +10 -0
  15. package/dist/compat/mod.d.cts +12 -0
  16. package/dist/compat/mod.d.ts +11 -12
  17. package/dist/compat/mod.js +5 -5
  18. package/dist/compat/transformers.test.js +20 -20
  19. package/dist/compat-DmDDELst.cjs +4 -0
  20. package/dist/compat-nxUqe4Z-.js +4 -0
  21. package/dist/{context-9gCpIkiz.d.ts → context-DG0huGW-.d.ts} +184 -127
  22. package/dist/context-DJ8aSy2Q.d.cts +2312 -0
  23. package/dist/{authdocloader-CLgDGafZ.js → docloader-CrbAy9Oc.js} +17 -8
  24. package/dist/{esm-CHdxdkuH.js → esm-C-Qa1zEM.js} +11 -11
  25. package/dist/federation/builder.test.js +9 -12
  26. package/dist/federation/collection.test.js +7 -9
  27. package/dist/federation/handler.test.js +27 -148
  28. package/dist/federation/idempotency.test.js +201 -0
  29. package/dist/federation/inbox.test.js +4 -6
  30. package/dist/federation/keycache.test.js +3 -4
  31. package/dist/federation/kv.test.js +7 -8
  32. package/dist/federation/middleware.test.js +242 -64
  33. package/dist/federation/mod.cjs +27 -0
  34. package/dist/federation/mod.d.cts +12 -0
  35. package/dist/federation/mod.d.ts +12 -13
  36. package/dist/federation/mod.js +13 -15
  37. package/dist/federation/mq.test.js +8 -10
  38. package/dist/federation/negotiation.test.js +26 -0
  39. package/dist/federation/retry.test.js +4 -5
  40. package/dist/federation/router.test.js +6 -8
  41. package/dist/federation/send.test.js +13 -15
  42. package/dist/federation-CRpdnOMS.cjs +244 -0
  43. package/dist/{federation-CMX7WzeL.js → federation-jcR8-ZxP.js} +3 -3
  44. package/dist/fixtures/media.example.com/avatars/test-avatar.jpg.json +6 -0
  45. package/dist/{http-DqSNLFNY.d.ts → http-BbO0ejuk.d.ts} +2 -2
  46. package/dist/{http-l0TEupZK.js → http-CUVx-vzb.js} +260 -10
  47. package/dist/{http-CcdM1brU.js → http-D2kIm9la.js} +3 -3
  48. package/dist/http-Dofes42e.cjs +1106 -0
  49. package/dist/http-M8k5mKc0.d.cts +253 -0
  50. package/dist/{inbox-B6DZbGNf.js → inbox-HjG5peXY.js} +24 -7
  51. package/dist/{key-CzLv1phF.js → key-CxdLUFS6.js} +3 -2
  52. package/dist/{keycache-B8HdZJSt.js → keycache-bU7COwsh.js} +1 -1
  53. package/dist/{keys-zZwiKkfx.js → keys-DMHs8XNn.js} +2 -1
  54. package/dist/kv-Bxr0Q87_.d.cts +81 -0
  55. package/dist/kv-cache-CGXcDejL.js +122 -0
  56. package/dist/kv-cache-DN9pfMBe.js +94 -0
  57. package/dist/kv-cache-Dkvbn6rg.cjs +134 -0
  58. package/dist/{ld-CBcQdZ6N.js → ld-CIhvSCCr.js} +5 -4
  59. package/dist/lookup-CHkCVZTU.js +260 -0
  60. package/dist/lookup-CfFkONZD.cjs +272 -0
  61. package/dist/{type-SK-d7Tbw.js → lookup-DQRtjvb1.js} +7266 -7087
  62. package/dist/middleware-Bot7EEwV.js +26 -0
  63. package/dist/middleware-CFJgmUMW.cjs +15 -0
  64. package/dist/{middleware-BRgu1IH8.js → middleware-CJlj5Olw.js} +86 -181
  65. package/dist/middleware-CjHl2NHA.js +15 -0
  66. package/dist/middleware-D74TgW2E.cjs +4225 -0
  67. package/dist/{middleware-CxEkcFW0.js → middleware-DMk2Mdn9.js} +117 -127
  68. package/dist/mod-0noXw66R.d.cts +107 -0
  69. package/dist/mod-B-hUPT2N.d.cts +1 -0
  70. package/dist/{mod-Drmz72EK.d.ts → mod-B2iOw50L.d.ts} +3 -3
  71. package/dist/mod-B9M-8jm2.d.ts +109 -0
  72. package/dist/{mod-Cxt4Kpf6.d.ts → mod-BlVovdcy.d.ts} +20 -2
  73. package/dist/{mod-Bqxcp7eN.d.ts → mod-BoHnwOCs.d.ts} +2 -2
  74. package/dist/mod-BxRCHTz-.d.cts +307 -0
  75. package/dist/mod-C2tOeRkN.d.cts +1 -0
  76. package/dist/mod-C58MZ7Wx.d.cts +113 -0
  77. package/dist/mod-DJcZDvjA.d.cts +80 -0
  78. package/dist/mod-DgdBYYa0.d.cts +266 -0
  79. package/dist/{mod-DBzN0aCM.d.ts → mod-Ds0mpFZU.d.ts} +1 -1
  80. package/dist/mod.cjs +137 -0
  81. package/dist/mod.d.cts +16 -0
  82. package/dist/mod.d.ts +16 -17
  83. package/dist/mod.js +19 -21
  84. package/dist/mq-DcJPkXD5.d.cts +140 -0
  85. package/dist/negotiation-C4nFufNk.js +71 -0
  86. package/dist/nodeinfo/client.test.js +30 -111
  87. package/dist/nodeinfo/handler.test.js +25 -26
  88. package/dist/nodeinfo/mod.cjs +10 -0
  89. package/dist/nodeinfo/mod.d.cts +3 -0
  90. package/dist/nodeinfo/mod.d.ts +3 -5
  91. package/dist/nodeinfo/mod.js +6 -7
  92. package/dist/nodeinfo/types.test.js +8 -15
  93. package/dist/nodeinfo-BnthBobC.js +4 -0
  94. package/dist/nodeinfo-CdN0rEnZ.cjs +4 -0
  95. package/dist/owner-B4HbyP8s.d.cts +67 -0
  96. package/dist/{owner-VEIjmR8r.js → owner-Dvh7mBvr.js} +3 -2
  97. package/dist/{owner-CQPnQVtf.d.ts → owner-kQRGVXG1.d.ts} +3 -3
  98. package/dist/proof-D0uThUvD.cjs +674 -0
  99. package/dist/{proof-DoSQAGkE.js → proof-Dgy35fzc.js} +3 -3
  100. package/dist/{proof-tgUlT8hw.js → proof-fqzaMJ4g.js} +11 -10
  101. package/dist/{send-BzS7w-QF.js → send-Drp20VO9.js} +2 -2
  102. package/dist/sig/http.test.js +13 -14
  103. package/dist/sig/key.test.js +9 -11
  104. package/dist/sig/ld.test.js +8 -10
  105. package/dist/sig/mod.cjs +28 -0
  106. package/dist/sig/mod.d.cts +6 -0
  107. package/dist/sig/mod.d.ts +5 -7
  108. package/dist/sig/mod.js +8 -10
  109. package/dist/sig/owner.test.js +10 -12
  110. package/dist/sig/proof.test.js +13 -14
  111. package/dist/sig-C34-oHBl.js +4 -0
  112. package/dist/sig-YYj5tCnr.cjs +4 -0
  113. package/dist/testing/docloader.test.js +6 -8
  114. package/dist/testing/mod.d.ts +387 -224
  115. package/dist/testing/mod.js +2 -3
  116. package/dist/{testing-Z2omCvKy.js → testing-g4UC4liW.js} +1 -2
  117. package/dist/{transformers-Dna8Fg7k.js → transformers-BFT6d7J5.js} +3 -3
  118. package/dist/transformers-CoBS-oFG.cjs +116 -0
  119. package/dist/{types-DgPvoUWN.js → types-BtUjyi5y.js} +8 -169
  120. package/dist/{types-BIgY6c-l.js → types-C2XVl6gj.js} +1 -3
  121. package/dist/types-CWgzGaqk.cjs +315 -0
  122. package/dist/{runtime/authdocloader.test.js → utils/docloader.test.js} +14 -15
  123. package/dist/utils/kv-cache.test.js +209 -0
  124. package/dist/utils/mod.cjs +12 -0
  125. package/dist/utils/mod.d.cts +5 -0
  126. package/dist/utils/mod.d.ts +7 -0
  127. package/dist/utils/mod.js +11 -0
  128. package/dist/utils-D-Va7aXC.js +4 -0
  129. package/dist/utils-DyRU1gdZ.cjs +4 -0
  130. package/dist/vocab/actor.test.js +8 -10
  131. package/dist/vocab/lookup.test.js +257 -9
  132. package/dist/vocab/mod.cjs +86 -0
  133. package/dist/vocab/mod.d.cts +4 -0
  134. package/dist/vocab/mod.d.ts +3 -5
  135. package/dist/vocab/mod.js +6 -7
  136. package/dist/vocab/type.test.js +2 -3
  137. package/dist/vocab/vocab.test.js +438 -15
  138. package/dist/{vocab-SOE1ifCr.d.ts → vocab-BCWe1Ih5.d.ts} +292 -21
  139. package/dist/{vocab-CvD6Vbml.js → vocab-BnR3nIU9.js} +26 -17
  140. package/dist/vocab-CeDBzu-f.d.cts +14903 -0
  141. package/dist/{lookup-Bn_HEC_d.js → vocab-DFaWWYDn.cjs} +108 -139
  142. package/dist/webfinger/handler.test.js +24 -25
  143. package/dist/webfinger/lookup.test.js +7 -9
  144. package/dist/webfinger/mod.cjs +8 -0
  145. package/dist/webfinger/mod.d.cts +2 -0
  146. package/dist/webfinger/mod.d.ts +1 -3
  147. package/dist/webfinger/mod.js +5 -6
  148. package/dist/webfinger-C72Y8lrh.js +4 -0
  149. package/dist/webfinger-vAtLmxOF.cjs +4 -0
  150. package/dist/x/cfworkers.cjs +100 -0
  151. package/dist/x/cfworkers.d.cts +59 -0
  152. package/dist/x/cfworkers.d.ts +2 -2
  153. package/dist/x/cfworkers.js +3 -3
  154. package/dist/x/cfworkers.test.js +6 -8
  155. package/dist/x/hono.cjs +61 -0
  156. package/dist/x/hono.d.cts +53 -0
  157. package/dist/x/hono.d.ts +10 -11
  158. package/dist/x/hono.js +3 -3
  159. package/dist/x/sveltekit.cjs +69 -0
  160. package/dist/x/sveltekit.d.cts +45 -0
  161. package/dist/x/sveltekit.d.ts +10 -11
  162. package/dist/x/sveltekit.js +3 -3
  163. package/package.json +79 -23
  164. package/dist/assert_throws-BOO88avQ.js +0 -39
  165. package/dist/authdocloader-BFVqUbyo.js +0 -52
  166. package/dist/compat-Bb5myD13.js +0 -4
  167. package/dist/docloader-CxWcuWqQ.d.ts +0 -221
  168. package/dist/docloader-DEhniCVa.js +0 -4615
  169. package/dist/key-CUZQgVlf.js +0 -10
  170. package/dist/key-Deb0_wWL.js +0 -10
  171. package/dist/key-DxA6xRtZ.js +0 -260
  172. package/dist/lookup-dtdr2ftf.js +0 -131
  173. package/dist/middleware-BE_geSiJ.js +0 -17
  174. package/dist/middleware-BnU6hzVp.js +0 -26
  175. package/dist/mod-TFoH2Ql8.d.ts +0 -104
  176. package/dist/nodeinfo/semver.test.js +0 -143
  177. package/dist/nodeinfo-CyEbLjHs.js +0 -4
  178. package/dist/runtime/docloader.test.js +0 -522
  179. package/dist/runtime/key.test.js +0 -103
  180. package/dist/runtime/langstr.test.d.ts +0 -3
  181. package/dist/runtime/langstr.test.js +0 -39
  182. package/dist/runtime/mod.d.ts +0 -8
  183. package/dist/runtime/mod.js +0 -13
  184. package/dist/runtime/multibase/multibase.test.d.ts +0 -3
  185. package/dist/runtime/multibase/multibase.test.js +0 -358
  186. package/dist/runtime/url.test.d.ts +0 -3
  187. package/dist/runtime/url.test.js +0 -45
  188. package/dist/runtime-BSkOVUWM.js +0 -4
  189. package/dist/semver-dArNLkR9.js +0 -149
  190. package/dist/sig-BXJO--F9.js +0 -4
  191. package/dist/webfinger-C3GIyXIg.js +0 -4
  192. /package/dist/{assert_not_equals-f3m3epl3.js → assert_not_equals-C80BG-_5.js} +0 -0
  193. /package/dist/{collection-CSzG2j1P.js → collection-BzWsN9pB.js} +0 -0
  194. /package/dist/{denokv-Bv33Xxea.js → denokv-CCssOzMJ.js} +0 -0
  195. /package/dist/{nodeinfo/semver.test.d.ts → federation/idempotency.test.d.ts} +0 -0
  196. /package/dist/{runtime/authdocloader.test.d.ts → federation/negotiation.test.d.ts} +0 -0
  197. /package/dist/{kv-C7sopW2E.d.ts → kv-BKNZ-Tb-.d.ts} +0 -0
  198. /package/dist/{mod-1pDWKvUL.d.ts → mod-CVgZgliM.d.ts} +0 -0
  199. /package/dist/{mod-g0xFzAP9.d.ts → mod-xIj-IT58.d.ts} +0 -0
  200. /package/dist/{mq-CRGm1e_F.d.ts → mq-CUKlBw08.d.ts} +0 -0
  201. /package/dist/{retry-D4GJ670a.js → retry-CfF8Gn4d.js} +0 -0
  202. /package/dist/{std__assert-X-_kMxKM.js → std__assert-DWivtrGR.js} +0 -0
  203. /package/dist/{runtime → utils}/docloader.test.d.ts +0 -0
  204. /package/dist/{runtime/key.test.d.ts → utils/kv-cache.test.d.ts} +0 -0
@@ -1,23 +1,22 @@
1
1
 
2
- import { Temporal } from "@js-temporal/polyfill";
3
- import { URLPattern } from "urlpattern-polyfill";
4
-
5
- import { getDefaultActivityTransformers } from "./transformers-Dna8Fg7k.js";
6
- import { deno_default, getDocumentLoader, kvCache } from "./docloader-DEhniCVa.js";
7
- import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId } from "./actor-CTAuCsWy.js";
8
- import { lookupWebFinger } from "./lookup-dtdr2ftf.js";
9
- import { exportJwk, importJwk, validateCryptoKey } from "./key-DxA6xRtZ.js";
10
- import { doubleKnock, verifyRequest } from "./http-l0TEupZK.js";
11
- import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-tgUlT8hw.js";
12
- import { getNodeInfo, nodeInfoToJson } from "./types-DgPvoUWN.js";
13
- import { getAuthenticatedDocumentLoader } from "./authdocloader-BFVqUbyo.js";
14
- import { lookupObject, traverseCollection } from "./vocab-CvD6Vbml.js";
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+ import { URLPattern } from "urlpattern-polyfill";
4
+
5
+ import { getDefaultActivityTransformers } from "./transformers-BFT6d7J5.js";
6
+ import { deno_default, lookupWebFinger } from "./lookup-CHkCVZTU.js";
7
+ import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId } from "./actor-DzhunPC_.js";
8
+ import { doubleKnock, exportJwk, importJwk, validateCryptoKey, verifyRequest } from "./http-CUVx-vzb.js";
9
+ import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-fqzaMJ4g.js";
10
+ import { getNodeInfo, nodeInfoToJson } from "./types-BtUjyi5y.js";
11
+ import { getAuthenticatedDocumentLoader, kvCache } from "./kv-cache-CGXcDejL.js";
12
+ import { lookupObject, traverseCollection } from "./vocab-BnR3nIU9.js";
15
13
  import { getLogger, withContext } from "@logtape/logtape";
16
14
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
17
- import { encodeHex } from "byte-encodings/hex";
15
+ import { getDocumentLoader } from "@fedify/vocab-runtime";
18
16
  import { cloneDeep } from "es-toolkit";
19
17
  import { Router } from "uri-template-router";
20
18
  import { parseTemplate } from "url-template";
19
+ import { encodeHex } from "byte-encodings/hex";
21
20
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
22
21
  import { domainToASCII } from "node:url";
23
22
 
@@ -55,17 +54,34 @@ var InboxListenerSet = class InboxListenerSet {
55
54
  return this.dispatchWithClass(activity)?.listener ?? null;
56
55
  }
57
56
  };
58
- async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider }) {
57
+ async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
59
58
  const logger$1 = getLogger([
60
59
  "fedify",
61
60
  "federation",
62
61
  "inbox"
63
62
  ]);
64
- const cacheKey = activity.id == null ? null : [
65
- ...kvPrefixes.activityIdempotence,
66
- ctx.origin,
67
- activity.id.href
68
- ];
63
+ let cacheKey = null;
64
+ if (activity.id != null) {
65
+ const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
66
+ const strategy = idempotencyStrategy ?? "per-inbox";
67
+ let keyString;
68
+ if (typeof strategy === "function") {
69
+ const result = await strategy(inboxContext, activity);
70
+ keyString = result;
71
+ } else switch (strategy) {
72
+ case "global":
73
+ keyString = activity.id.href;
74
+ break;
75
+ case "per-origin":
76
+ keyString = `${ctx.origin}\n${activity.id.href}`;
77
+ break;
78
+ case "per-inbox":
79
+ keyString = `${ctx.origin}\n${activity.id.href}\n${recipient == null ? "sharedInbox" : `inbox\n${recipient}`}`;
80
+ break;
81
+ default: keyString = `${ctx.origin}\n${activity.id.href}`;
82
+ }
83
+ if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
84
+ }
69
85
  if (cacheKey != null) {
70
86
  const cached = await kv.get(cacheKey);
71
87
  if (cached === true) {
@@ -307,6 +323,7 @@ var FederationBuilderImpl = class {
307
323
  inboxListeners;
308
324
  inboxErrorHandler;
309
325
  sharedInboxKeyDispatcher;
326
+ idempotencyStrategy;
310
327
  collectionTypeIds;
311
328
  collectionCallbacks;
312
329
  /**
@@ -321,7 +338,7 @@ var FederationBuilderImpl = class {
321
338
  this.collectionTypeIds = {};
322
339
  }
323
340
  async build(options) {
324
- const { FederationImpl: FederationImpl$1 } = await import("./middleware-BE_geSiJ.js");
341
+ const { FederationImpl: FederationImpl$1 } = await import("./middleware-CjHl2NHA.js");
325
342
  const f = new FederationImpl$1(options);
326
343
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
327
344
  f.router = this.router.clone();
@@ -343,6 +360,7 @@ var FederationBuilderImpl = class {
343
360
  f.inboxListeners = this.inboxListeners?.clone();
344
361
  f.inboxErrorHandler = this.inboxErrorHandler;
345
362
  f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
363
+ f.idempotencyStrategy = this.idempotencyStrategy;
346
364
  return f;
347
365
  }
348
366
  _getTracer() {
@@ -765,15 +783,19 @@ var FederationBuilderImpl = class {
765
783
  setSharedKeyDispatcher: (dispatcher) => {
766
784
  this.sharedInboxKeyDispatcher = dispatcher;
767
785
  return setters;
786
+ },
787
+ withIdempotency: (strategy) => {
788
+ this.idempotencyStrategy = strategy;
789
+ return setters;
768
790
  }
769
791
  };
770
792
  return setters;
771
793
  }
772
- setCollectionDispatcher(name, ...args) {
773
- return this.#setCustomCollectionDispatcher(name, "collection", ...args);
794
+ setCollectionDispatcher(name, itemType, path, dispatcher) {
795
+ return this.#setCustomCollectionDispatcher(name, "collection", itemType, path, dispatcher);
774
796
  }
775
- setOrderedCollectionDispatcher(name, ...args) {
776
- return this.#setCustomCollectionDispatcher(name, "orderedCollection", ...args);
797
+ setOrderedCollectionDispatcher(name, itemType, path, dispatcher) {
798
+ return this.#setCustomCollectionDispatcher(name, "orderedCollection", itemType, path, dispatcher);
777
799
  }
778
800
  #setCustomCollectionDispatcher(name, collectionType, itemType, path, dispatcher) {
779
801
  const strName = String(name);
@@ -979,9 +1001,6 @@ function preferredMediaTypes(accept) {
979
1001
  const accepts = parseAccept(accept === void 0 ? "*/*" : accept ?? "");
980
1002
  return accepts.filter(isQuality).sort(compareSpecs).map(getFullType);
981
1003
  }
982
-
983
- //#endregion
984
- //#region src/federation/handler.ts
985
1004
  function acceptsJsonLd(request) {
986
1005
  const accept = request.headers.get("Accept");
987
1006
  const types = accept ? preferredMediaTypes(accept) : ["*/*"];
@@ -989,6 +1008,9 @@ function acceptsJsonLd(request) {
989
1008
  if (types[0] === "text/html" || types[0] === "application/xhtml+xml") return false;
990
1009
  return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
991
1010
  }
1011
+
1012
+ //#endregion
1013
+ //#region src/federation/handler.ts
992
1014
  /**
993
1015
  * Handles an actor request.
994
1016
  * @template TContextData The context data to pass to the context.
@@ -996,7 +1018,7 @@ function acceptsJsonLd(request) {
996
1018
  * @param parameters The parameters for handling the actor.
997
1019
  * @returns A promise that resolves to an HTTP response.
998
1020
  */
999
- async function handleActor(request, { identifier, context: context$1, actorDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized }) {
1021
+ async function handleActor(request, { identifier, context: context$1, actorDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
1000
1022
  const logger$1 = getLogger([
1001
1023
  "fedify",
1002
1024
  "federation",
@@ -1011,7 +1033,6 @@ async function handleActor(request, { identifier, context: context$1, actorDispa
1011
1033
  logger$1.debug("Actor {identifier} not found.", { identifier });
1012
1034
  return await onNotFound(request);
1013
1035
  }
1014
- if (!acceptsJsonLd(request)) return await onNotAcceptable(request);
1015
1036
  if (authorizePredicate != null) {
1016
1037
  let key = await context$1.getSignedKey();
1017
1038
  key = key?.clone({}, { $warning: {
@@ -1046,11 +1067,10 @@ async function handleActor(request, { identifier, context: context$1, actorDispa
1046
1067
  * @param parameters The parameters for handling the object.
1047
1068
  * @returns A promise that resolves to an HTTP response.
1048
1069
  */
1049
- async function handleObject(request, { values, context: context$1, objectDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized }) {
1070
+ async function handleObject(request, { values, context: context$1, objectDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
1050
1071
  if (objectDispatcher == null) return await onNotFound(request);
1051
1072
  const object = await objectDispatcher(context$1, values);
1052
1073
  if (object == null) return await onNotFound(request);
1053
- if (!acceptsJsonLd(request)) return await onNotAcceptable(request);
1054
1074
  if (authorizePredicate != null) {
1055
1075
  let key = await context$1.getSignedKey();
1056
1076
  key = key?.clone({}, { $warning: {
@@ -1088,7 +1108,7 @@ async function handleObject(request, { values, context: context$1, objectDispatc
1088
1108
  * @param parameters The parameters for handling the collection.
1089
1109
  * @returns A promise that resolves to an HTTP response.
1090
1110
  */
1091
- async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context: context$1, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound, onNotAcceptable }) {
1111
+ async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context: context$1, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound }) {
1092
1112
  const spanName = name.trim().replace(/\s+/g, "_");
1093
1113
  tracerProvider = tracerProvider ?? trace.getTracerProvider();
1094
1114
  const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
@@ -1201,7 +1221,6 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
1201
1221
  partOf
1202
1222
  });
1203
1223
  }
1204
- if (!acceptsJsonLd(request)) return await onNotAcceptable(request);
1205
1224
  if (collectionCallbacks.authorizePredicate != null) {
1206
1225
  let key = await context$1.getSignedKey();
1207
1226
  key = key?.clone({}, { $warning: {
@@ -1296,7 +1315,8 @@ async function handleInbox(request, options) {
1296
1315
  * @param span The OpenTelemetry span for tracing.
1297
1316
  * @returns A promise that resolves to an HTTP response.
1298
1317
  */
1299
- async function handleInboxInternal(request, { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider }, span) {
1318
+ async function handleInboxInternal(request, parameters, span) {
1319
+ const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider } = parameters;
1300
1320
  const logger$1 = getLogger([
1301
1321
  "fedify",
1302
1322
  "federation",
@@ -1498,7 +1518,8 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
1498
1518
  kvPrefixes,
1499
1519
  queue,
1500
1520
  span,
1501
- tracerProvider
1521
+ tracerProvider,
1522
+ idempotencyStrategy: parameters.idempotencyStrategy
1502
1523
  });
1503
1524
  if (routeResult === "alreadyProcessed") return new Response(`Activity <${activity.id}> has already been processed.`, {
1504
1525
  status: 202,
@@ -1528,7 +1549,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
1528
1549
  /**
1529
1550
  * Handles a custom collection request.
1530
1551
  * @template TItem The type of items in the collection.
1531
- * @template TParams The parameter names of the requested URL.
1552
+ * @template TParam The parameter names of the requested URL.
1532
1553
  * @template TContext The type of the context, extending {@link RequestContext}.
1533
1554
  * @template TContextData The context data to pass to the `TContext`.
1534
1555
  * @param request The HTTP request.
@@ -1539,7 +1560,6 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
1539
1560
  const handleCustomCollection = exceptWrapper(_handleCustomCollection);
1540
1561
  async function _handleCustomCollection(request, { name, values, context: context$1, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
1541
1562
  verifyDefined(callbacks);
1542
- verifyJsonLdRequest(request);
1543
1563
  await authIfNeeded(context$1, values, callbacks);
1544
1564
  const cursor = new URL(request.url).searchParams.get("cursor");
1545
1565
  return await new CustomCollectionHandler(name, values, context$1, callbacks, tracerProvider, Collection, CollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
@@ -1547,7 +1567,7 @@ async function _handleCustomCollection(request, { name, values, context: context
1547
1567
  /**
1548
1568
  * Handles an ordered collection request.
1549
1569
  * @template TItem The type of items in the collection.
1550
- * @template TParams The parameter names of the requested URL.
1570
+ * @template TParam The parameter names of the requested URL.
1551
1571
  * @template TContext The type of the context, extending {@link RequestContext}.
1552
1572
  * @template TContextData The context data to pass to the `TContext`.
1553
1573
  * @param request The HTTP request.
@@ -1558,7 +1578,6 @@ async function _handleCustomCollection(request, { name, values, context: context
1558
1578
  const handleOrderedCollection = exceptWrapper(_handleOrderedCollection);
1559
1579
  async function _handleOrderedCollection(request, { name, values, context: context$1, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
1560
1580
  verifyDefined(callbacks);
1561
- verifyJsonLdRequest(request);
1562
1581
  await authIfNeeded(context$1, values, callbacks);
1563
1582
  const cursor = new URL(request.url).searchParams.get("cursor");
1564
1583
  return await new CustomCollectionHandler(name, values, context$1, callbacks, tracerProvider, OrderedCollection, OrderedCollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
@@ -1568,7 +1587,7 @@ async function _handleOrderedCollection(request, { name, values, context: contex
1568
1587
  * The main flow is on `getCollection`, `dispatch`.
1569
1588
  *
1570
1589
  * @template TItem The type of items in the collection.
1571
- * @template TParams The parameter names of the requested URL.
1590
+ * @template TParam The parameter names of the requested URL.
1572
1591
  * @template TContext The type of the context. {@link Context} or {@link RequestContext}.
1573
1592
  * @template TContextData The context data to pass to the `TContext`.
1574
1593
  * @template TCollection The type of the collection, extending {@link Collection}.
@@ -1602,14 +1621,14 @@ var CustomCollectionHandler = class {
1602
1621
  #collection = null;
1603
1622
  /**
1604
1623
  * Creates a new CustomCollection instance.
1605
- * @param {string} name The name of the collection.
1606
- * @param {TParams} values The parameter values for the collection.
1607
- * @param {TContext} context The request context.
1608
- * @param {CustomCollectionCallbacks} callbacks The collection callbacks.
1609
- * @param {TracerProvider} tracerProvider The tracer provider for telemetry.
1610
- * @param {ConstructorWithTypeId<TCollection>} Collection The Collection constructor.
1611
- * @param {ConstructorWithTypeId<TCollectionPage>} CollectionPage The CollectionPage constructor.
1612
- * @param {(item: TItem) => boolean} filterPredicate Optional filter predicate for items.
1624
+ * @param name The name of the collection.
1625
+ * @param values The parameter values for the collection.
1626
+ * @param context The request context.
1627
+ * @param callbacks The collection callbacks.
1628
+ * @param tracerProvider The tracer provider for telemetry.
1629
+ * @param Collection The Collection constructor.
1630
+ * @param CollectionPage The CollectionPage constructor.
1631
+ * @param filterPredicate Optional filter predicate for items.
1613
1632
  */
1614
1633
  constructor(name, values, context$1, callbacks, tracerProvider = trace.getTracerProvider(), Collection$1, CollectionPage$1, filterPredicate) {
1615
1634
  this.name = name;
@@ -1734,7 +1753,7 @@ var CustomCollectionHandler = class {
1734
1753
  /**
1735
1754
  * Creates a function to wrap the dispatcher so tracing can be applied.
1736
1755
  * @param params Parameters including cursor and total items.
1737
- * @returns {(span: Span) => Promise<PageItems<TItem>>} A function that handles the span operation.
1756
+ * @returns A function that handles the span operation.
1738
1757
  */
1739
1758
  spanPages = ({ totalItems = null, cursor = null }) => async (span) => {
1740
1759
  try {
@@ -1755,23 +1774,23 @@ var CustomCollectionHandler = class {
1755
1774
  };
1756
1775
  /**
1757
1776
  * Dispatches the collection request to get items.
1758
- * @param {string | null} cursor The cursor for pagination, or null for the first page.
1759
- * @returns {Promise<PageItems<TItem>>} A promise that resolves to the page items.
1777
+ * @param cursor The cursor for pagination, or null for the first page.
1778
+ * @returns A promise that resolves to the page items.
1760
1779
  */
1761
1780
  async dispatch(cursor = null) {
1762
1781
  return await this.#dispatcher(this.context, this.values, cursor) ?? new ItemsNotFoundError().throw();
1763
1782
  }
1764
1783
  /**
1765
1784
  * Filters the items in the collection.
1766
- * @param {TItem[]} items The items to filter.
1767
- * @returns {(Object | Link | URL)[]} The filtered items.
1785
+ * @param items The items to filter.
1786
+ * @returns The filtered items.
1768
1787
  */
1769
1788
  filterItems(items) {
1770
1789
  return filterCollectionItems(items, this.name, this.filterPredicate);
1771
1790
  }
1772
1791
  /**
1773
1792
  * Appends a cursor to the URL if it exists.
1774
- * @param {string | null | undefined} cursor The cursor to append, or null/undefined.
1793
+ * @param cursor The cursor to append, or null/undefined.
1775
1794
  * @returns The URL with cursor appended, or null if cursor is null/undefined.
1776
1795
  */
1777
1796
  appendToUrl(cursor) {
@@ -1779,8 +1798,7 @@ var CustomCollectionHandler = class {
1779
1798
  }
1780
1799
  /**
1781
1800
  * Gets the stored collection or collection page.
1782
- * @returns {Promise<TCollection | TCollectionPage>} A promise that resolves to
1783
- the collection or collection page.
1801
+ * @returns A promise that resolves to the collection or collection page.
1784
1802
  */
1785
1803
  get collection() {
1786
1804
  if (this.#collection === null) this.#collection = this.getCollection();
@@ -1788,8 +1806,8 @@ var CustomCollectionHandler = class {
1788
1806
  }
1789
1807
  /**
1790
1808
  * Gets the total number of items in the collection.
1791
- * @returns {Promise<number | null>} A promise that
1792
- resolves to the total items count, or null if not available.
1809
+ * @returns A promise that resolves to the total items count,
1810
+ * or null if not available.
1793
1811
  */
1794
1812
  get totalItems() {
1795
1813
  if (this.#totalItems === void 0) this.totalItems = this.callbacks.counter?.(this.context, this.values);
@@ -1805,8 +1823,8 @@ var CustomCollectionHandler = class {
1805
1823
  }
1806
1824
  /**
1807
1825
  * Gets the first cursor for pagination.
1808
- * @returns {Promise<string | null>} A promise that resolves to the first cursor,
1809
- or null if not available.
1826
+ * @returns A promise that resolves to the first cursor,
1827
+ * or null if not available.
1810
1828
  */
1811
1829
  get firstCursor() {
1812
1830
  const cursor = this.callbacks.firstCursor?.(this.context, this.values);
@@ -1836,10 +1854,9 @@ function exceptWrapper(handler) {
1836
1854
  try {
1837
1855
  return await handler(request, handlerParams);
1838
1856
  } catch (error) {
1839
- const { onNotFound, onNotAcceptable, onUnauthorized } = handlerParams;
1857
+ const { onNotFound, onUnauthorized } = handlerParams;
1840
1858
  switch (error?.constructor) {
1841
1859
  case ItemsNotFoundError: return await onNotFound(request);
1842
- case NotAcceptableError: return await onNotAcceptable(request);
1843
1860
  case UnauthorizedError: return await onUnauthorized(request);
1844
1861
  default: throw error;
1845
1862
  }
@@ -1857,15 +1874,6 @@ const verifyDefined = (callbacks) => {
1857
1874
  if (callbacks === void 0) throw new ItemsNotFoundError();
1858
1875
  };
1859
1876
  /**
1860
- * Verifies that a request accepts JSON-LD content type.
1861
- * @param request The HTTP request to verify.
1862
- * @throws {NotAcceptableError} If the request doesn't accept JSON-LD.
1863
- * @since 1.8.0
1864
- */
1865
- const verifyJsonLdRequest = (request) => {
1866
- if (!acceptsJsonLd(request)) throw new NotAcceptableError();
1867
- };
1868
- /**
1869
1877
  * Performs authorization if needed based on the authorization predicate.
1870
1878
  * @template TContextData The context data type.
1871
1879
  * @param {RequestContext<TContextData>} context The request context.
@@ -1949,15 +1957,6 @@ var ItemsNotFoundError = class extends HandlerError {
1949
1957
  }
1950
1958
  };
1951
1959
  /**
1952
- * Error thrown when the request is not acceptable (e.g., wrong content type).
1953
- * @since 1.8.0
1954
- */
1955
- var NotAcceptableError = class extends HandlerError {
1956
- constructor() {
1957
- super("The request is not acceptable.");
1958
- }
1959
- };
1960
- /**
1961
1960
  * Error thrown when access to a collection is unauthorized.
1962
1961
  * @since 1.8.0
1963
1962
  */
@@ -2349,7 +2348,6 @@ var FederationImpl = class extends FederationBuilderImpl {
2349
2348
  firstKnock;
2350
2349
  constructor(options) {
2351
2350
  super();
2352
- const logger$1 = getLogger(["fedify", "federation"]);
2353
2351
  this.kv = options.kv;
2354
2352
  this.kvPrefixes = {
2355
2353
  activityIdempotence: ["_fedify", "activityIdempotence"],
@@ -2397,8 +2395,9 @@ var FederationImpl = class extends FederationBuilderImpl {
2397
2395
  this.router.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false;
2398
2396
  this._initializeRouter();
2399
2397
  if (options.allowPrivateAddress || options.userAgent != null) {
2400
- if (options.contextLoader != null) throw new TypeError("Cannot set contextLoader with allowPrivateAddress or userAgent options.");
2401
- else if (options.authenticatedDocumentLoaderFactory != null) throw new TypeError("Cannot set authenticatedDocumentLoaderFactory with allowPrivateAddress or userAgent options.");
2398
+ if (options.documentLoaderFactory != null) throw new TypeError("Cannot set documentLoaderFactory with allowPrivateAddress or userAgent options.");
2399
+ if (options.contextLoaderFactory != null) throw new TypeError("Cannot set contextLoaderFactory with allowPrivateAddress or userAgent options.");
2400
+ if (options.authenticatedDocumentLoaderFactory != null) throw new TypeError("Cannot set authenticatedDocumentLoaderFactory with allowPrivateAddress or userAgent options.");
2402
2401
  }
2403
2402
  const { allowPrivateAddress, userAgent } = options;
2404
2403
  this.allowPrivateAddress = allowPrivateAddress ?? false;
@@ -2412,11 +2411,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2412
2411
  prefix: this.kvPrefixes.remoteDocument
2413
2412
  });
2414
2413
  });
2415
- if (options.contextLoader != null) {
2416
- if (options.contextLoaderFactory != null) throw new TypeError("Cannot set both contextLoader and contextLoaderFactory options at a time; use contextLoaderFactory only.");
2417
- this.contextLoaderFactory = () => options.contextLoader;
2418
- logger$1.warn("The contextLoader option is deprecated; use contextLoaderFactory option instead.");
2419
- } else this.contextLoaderFactory = options.contextLoaderFactory ?? this.documentLoaderFactory;
2414
+ this.contextLoaderFactory = options.contextLoaderFactory ?? this.documentLoaderFactory;
2420
2415
  this.authenticatedDocumentLoaderFactory = options.authenticatedDocumentLoaderFactory ?? ((identity) => getAuthenticatedDocumentLoader(identity, {
2421
2416
  allowPrivateAddress,
2422
2417
  userAgent,
@@ -2955,6 +2950,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2955
2950
  span,
2956
2951
  tracer
2957
2952
  });
2953
+ if (acceptsJsonLd(request)) response.headers.set("Vary", "Accept");
2958
2954
  } catch (error) {
2959
2955
  span.setStatus({
2960
2956
  code: SpanStatusCode.ERROR,
@@ -3018,6 +3014,9 @@ var FederationImpl = class extends FederationBuilderImpl {
3018
3014
  context: context$1,
3019
3015
  nodeInfoDispatcher: this.nodeInfoDispatcher
3020
3016
  });
3017
+ }
3018
+ if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
3019
+ switch (routeName) {
3021
3020
  case "actor":
3022
3021
  context$1 = this.#createContext(request, contextData, { invokedFromActorDispatcher: { identifier: route.values.identifier ?? route.values.handle } });
3023
3022
  return await handleActor(request, {
@@ -3026,8 +3025,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3026
3025
  actorDispatcher: this.actorCallbacks?.dispatcher,
3027
3026
  authorizePredicate: this.actorCallbacks?.authorizePredicate,
3028
3027
  onUnauthorized,
3029
- onNotFound,
3030
- onNotAcceptable
3028
+ onNotFound
3031
3029
  });
3032
3030
  case "object": {
3033
3031
  const typeId = route.name.replace(/^object:/, "");
@@ -3043,8 +3041,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3043
3041
  objectDispatcher: callbacks?.dispatcher,
3044
3042
  authorizePredicate: callbacks?.authorizePredicate,
3045
3043
  onUnauthorized,
3046
- onNotFound,
3047
- onNotAcceptable
3044
+ onNotFound
3048
3045
  });
3049
3046
  }
3050
3047
  case "outbox": return await handleCollection(request, {
@@ -3055,8 +3052,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3055
3052
  collectionCallbacks: this.outboxCallbacks,
3056
3053
  tracerProvider: this.tracerProvider,
3057
3054
  onUnauthorized,
3058
- onNotFound,
3059
- onNotAcceptable
3055
+ onNotFound
3060
3056
  });
3061
3057
  case "inbox":
3062
3058
  if (request.method !== "POST") return await handleCollection(request, {
@@ -3067,8 +3063,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3067
3063
  collectionCallbacks: this.inboxCallbacks,
3068
3064
  tracerProvider: this.tracerProvider,
3069
3065
  onUnauthorized,
3070
- onNotFound,
3071
- onNotAcceptable
3066
+ onNotFound
3072
3067
  });
3073
3068
  context$1 = this.#createContext(request, contextData, { documentLoader: await context$1.getDocumentLoader({ identifier: route.values.identifier ?? route.values.handle }) });
3074
3069
  case "sharedInbox":
@@ -3090,7 +3085,8 @@ var FederationImpl = class extends FederationBuilderImpl {
3090
3085
  onNotFound,
3091
3086
  signatureTimeWindow: this.signatureTimeWindow,
3092
3087
  skipSignatureVerification: this.skipSignatureVerification,
3093
- tracerProvider: this.tracerProvider
3088
+ tracerProvider: this.tracerProvider,
3089
+ idempotencyStrategy: this.idempotencyStrategy
3094
3090
  });
3095
3091
  case "following": return await handleCollection(request, {
3096
3092
  name: "following",
@@ -3100,8 +3096,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3100
3096
  collectionCallbacks: this.followingCallbacks,
3101
3097
  tracerProvider: this.tracerProvider,
3102
3098
  onUnauthorized,
3103
- onNotFound,
3104
- onNotAcceptable
3099
+ onNotFound
3105
3100
  });
3106
3101
  case "followers": {
3107
3102
  let baseUrl = url.searchParams.get("base-url");
@@ -3124,8 +3119,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3124
3119
  collectionCallbacks: this.followersCallbacks,
3125
3120
  tracerProvider: this.tracerProvider,
3126
3121
  onUnauthorized,
3127
- onNotFound,
3128
- onNotAcceptable
3122
+ onNotFound
3129
3123
  });
3130
3124
  }
3131
3125
  case "liked": return await handleCollection(request, {
@@ -3136,8 +3130,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3136
3130
  collectionCallbacks: this.likedCallbacks,
3137
3131
  tracerProvider: this.tracerProvider,
3138
3132
  onUnauthorized,
3139
- onNotFound,
3140
- onNotAcceptable
3133
+ onNotFound
3141
3134
  });
3142
3135
  case "featured": return await handleCollection(request, {
3143
3136
  name: "featured",
@@ -3147,8 +3140,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3147
3140
  collectionCallbacks: this.featuredCallbacks,
3148
3141
  tracerProvider: this.tracerProvider,
3149
3142
  onUnauthorized,
3150
- onNotFound,
3151
- onNotAcceptable
3143
+ onNotFound
3152
3144
  });
3153
3145
  case "featuredTags": return await handleCollection(request, {
3154
3146
  name: "featured tags",
@@ -3158,8 +3150,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3158
3150
  collectionCallbacks: this.featuredTagsCallbacks,
3159
3151
  tracerProvider: this.tracerProvider,
3160
3152
  onUnauthorized,
3161
- onNotFound,
3162
- onNotAcceptable
3153
+ onNotFound
3163
3154
  });
3164
3155
  case "collection": {
3165
3156
  const name = route.name.replace(/^collection:/, "");
@@ -3171,8 +3162,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3171
3162
  collectionCallbacks: callbacks,
3172
3163
  tracerProvider: this.tracerProvider,
3173
3164
  onUnauthorized,
3174
- onNotFound,
3175
- onNotAcceptable
3165
+ onNotFound
3176
3166
  });
3177
3167
  }
3178
3168
  case "orderedCollection": {
@@ -3185,8 +3175,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3185
3175
  collectionCallbacks: callbacks,
3186
3176
  tracerProvider: this.tracerProvider,
3187
3177
  onUnauthorized,
3188
- onNotFound,
3189
- onNotAcceptable
3178
+ onNotFound
3190
3179
  });
3191
3180
  }
3192
3181
  default: {
@@ -3481,15 +3470,16 @@ var ContextImpl = class ContextImpl {
3481
3470
  "actor"
3482
3471
  ]);
3483
3472
  if (this.federation.actorCallbacks?.keyPairsDispatcher == null) throw new Error("No actor key pairs dispatcher registered.");
3484
- const path = this.federation.router.build("actor", {
3485
- identifier,
3486
- handle: identifier
3487
- });
3488
- if (path == null) {
3489
- logger$1.warn("No actor dispatcher registered.");
3490
- return [];
3473
+ let actorUri;
3474
+ try {
3475
+ actorUri = this.getActorUri(identifier);
3476
+ } catch (error) {
3477
+ if (error instanceof RouterError) {
3478
+ logger$1.warn(error.message);
3479
+ return [];
3480
+ }
3481
+ throw error;
3491
3482
  }
3492
- const actorUri = new URL(path, this.canonicalOrigin);
3493
3483
  const keyPairs = await this.federation.actorCallbacks?.keyPairsDispatcher(new ContextImpl({
3494
3484
  ...this,
3495
3485
  invokedFromActorKeyPairsDispatcher: { identifier }
@@ -3650,12 +3640,11 @@ var ContextImpl = class ContextImpl {
3650
3640
  if (identifier == null) throw new Error("If recipients is \"followers\", sender must be an actor identifier or username.");
3651
3641
  expandedRecipients = [];
3652
3642
  for await (const recipient of this.getFollowers(identifier)) expandedRecipients.push(recipient);
3653
- if (options.syncCollection) {
3654
- const collectionId = this.federation.router.build("followers", {
3655
- identifier,
3656
- handle: identifier
3657
- });
3658
- opts.collectionSync = collectionId == null ? void 0 : new URL(collectionId, this.canonicalOrigin).href;
3643
+ if (options.syncCollection) try {
3644
+ opts.collectionSync = this.getFollowersUri(identifier).href;
3645
+ } catch (error) {
3646
+ if (error instanceof RouterError) opts.collectionSync = void 0;
3647
+ else throw error;
3659
3648
  }
3660
3649
  } else expandedRecipients = [recipients];
3661
3650
  span.setAttribute("activitypub.inboxes", expandedRecipients.length);
@@ -3840,7 +3829,8 @@ var ContextImpl = class ContextImpl {
3840
3829
  kvPrefixes: this.federation.kvPrefixes,
3841
3830
  queue: this.federation.inboxQueue,
3842
3831
  span,
3843
- tracerProvider: options.tracerProvider ?? this.tracerProvider
3832
+ tracerProvider: options.tracerProvider ?? this.tracerProvider,
3833
+ idempotencyStrategy: this.federation.idempotencyStrategy
3844
3834
  });
3845
3835
  return routeResult === "alreadyProcessed" || routeResult === "enqueued" || routeResult === "unsupportedActivity" || routeResult === "success";
3846
3836
  }