@fedify/fedify 2.0.0-pr.435.1673 → 2.0.0-pr.449.1725

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 (138) hide show
  1. package/dist/{actor-m_ko-86v.js → actor-C0gLJq8I.js} +7263 -2440
  2. package/dist/{actor-CNUje03O.cjs → actor-CsRJa7wV.cjs} +7263 -2440
  3. package/dist/{actor-DMgu-ZjT.d.cts → actor-D6K058Tb.d.cts} +1 -1
  4. package/dist/{actor-C22bXuuC.d.ts → actor-T6RyhRgk.d.ts} +1 -1
  5. package/dist/{actor-BxAu0qet.js → actor-VrXd7EdX.js} +1 -1
  6. package/dist/{authdocloader-nRFL9luh.js → authdocloader-6F9IP-VO.js} +3 -3
  7. package/dist/{authdocloader-D_3mtAjX.cjs → authdocloader-BkuVo8LL.cjs} +3 -3
  8. package/dist/{authdocloader-Chl2nuOI.js → authdocloader-C8LXxsmU.js} +3 -3
  9. package/dist/{builder-C8Of4dPy.js → builder-JjsppXTK.js} +14 -8
  10. package/dist/{client-yGBH5stP.js → client-BS-GE3XI.js} +1 -1
  11. package/dist/compat/mod.d.cts +7 -7
  12. package/dist/compat/mod.d.ts +7 -7
  13. package/dist/compat/transformers.test.js +16 -16
  14. package/dist/{context-CQsAT7xk.d.ts → context-B1X8-X33.d.ts} +186 -98
  15. package/dist/{context-tVOQ76fi.d.cts → context-DYCJXr7J.d.cts} +186 -98
  16. package/dist/{docloader-_WdHTWQR.js → docloader-AMdJU291.js} +1 -1
  17. package/dist/{docloader-SZjTrl6Z.cjs → docloader-BdF5STdg.cjs} +1 -1
  18. package/dist/{esm-e_G_xo95.js → esm-CvUgdJZ_.js} +1 -1
  19. package/dist/federation/builder.test.js +5 -5
  20. package/dist/federation/collection.test.js +3 -3
  21. package/dist/federation/handler.test.js +17 -17
  22. package/dist/federation/idempotency.test.d.ts +3 -0
  23. package/dist/federation/idempotency.test.js +202 -0
  24. package/dist/federation/inbox.test.js +4 -4
  25. package/dist/federation/keycache.test.js +4 -4
  26. package/dist/federation/kv.test.js +3 -3
  27. package/dist/federation/middleware.test.js +24 -47
  28. package/dist/federation/mod.cjs +10 -10
  29. package/dist/federation/mod.d.cts +7 -7
  30. package/dist/federation/mod.d.ts +7 -7
  31. package/dist/federation/mod.js +10 -10
  32. package/dist/federation/mq.test.js +3 -3
  33. package/dist/federation/negotiation.test.js +3 -3
  34. package/dist/federation/retry.test.js +3 -3
  35. package/dist/federation/router.test.js +3 -3
  36. package/dist/federation/send.test.js +10 -10
  37. package/dist/fixtures/media.example.com/avatars/test-avatar.jpg.json +6 -0
  38. package/dist/{http-BS6766zs.d.cts → http-D-e6AFwR.d.cts} +1 -1
  39. package/dist/{http-DqSNLFNY.d.ts → http-D6Uj2x2y.d.ts} +1 -1
  40. package/dist/{http-BpoEurUR.js → http-DVQEn98K.js} +3 -3
  41. package/dist/{http-DREvFalF.cjs → http-D_BI5KHC.cjs} +3 -3
  42. package/dist/{http-BEo67UOx.js → http-DbyMqL2X.js} +2 -2
  43. package/dist/{inbox-D-B5xFtJ.js → inbox-DQlf_-Dz.js} +24 -7
  44. package/dist/{key-DJpcumqB.js → key-BBzfhQGE.js} +4 -4
  45. package/dist/key-BMz_uAnc.cjs +10 -0
  46. package/dist/{key-Cps8Sv3N.js → key-BSJX6n9o.js} +2 -2
  47. package/dist/{key-JqiQvcq1.cjs → key-D-RgWfcf.cjs} +2 -2
  48. package/dist/{key-Cf8KTg-A.js → key-DFefr8X2.js} +2 -2
  49. package/dist/{key-DqrTz8Xq.js → key-DW2DrPGl.js} +3 -3
  50. package/dist/{keycache-D_Q1fPV0.js → keycache-CcIfdj0m.js} +1 -1
  51. package/dist/{keys-F0jh2GNR.js → keys-DnSaJmvD.js} +1 -1
  52. package/dist/{ld-CXygHn_m.js → ld-CAJ6Q2od.js} +2 -2
  53. package/dist/{lookup-C-Y0Ep1a.cjs → lookup-B2Bsau2g.cjs} +1 -1
  54. package/dist/{lookup-C6WSLjPE.js → lookup-BGCuyJRy.js} +1 -1
  55. package/dist/{lookup-DuqY2_In.js → lookup-C3pnuyiD.js} +21 -12
  56. package/dist/{middleware-2qNNXYEE.js → middleware-1oxZY_0z.js} +78 -56
  57. package/dist/middleware-B8WWe8Q2.js +26 -0
  58. package/dist/{middleware-CMiUxZ6O.js → middleware-BDqkoMAQ.js} +48 -49
  59. package/dist/{middleware-BsFAFlnZ.cjs → middleware-D0XMPoN8.cjs} +78 -56
  60. package/dist/middleware-DipQbJmB.js +17 -0
  61. package/dist/middleware-mLaQeD_Z.cjs +17 -0
  62. package/dist/{mod-Drmz72EK.d.ts → mod-BhUKmBJD.d.ts} +2 -2
  63. package/dist/{mod-TFoH2Ql8.d.ts → mod-CerN_Sza.d.ts} +1 -1
  64. package/dist/{mod-Dc_-mf8s.d.cts → mod-Cj1tHXBR.d.cts} +1 -1
  65. package/dist/{mod-evzlRVZq.d.cts → mod-CxkWO3Mg.d.cts} +19 -1
  66. package/dist/{mod-B26zRlH1.d.ts → mod-DcKxhFQ8.d.ts} +2 -2
  67. package/dist/{mod-BClfg3ej.d.cts → mod-Djzcw2ry.d.cts} +2 -2
  68. package/dist/{mod-Cxt4Kpf6.d.ts → mod-DlU8ISoa.d.ts} +19 -1
  69. package/dist/{mod-DBQAI4v9.d.cts → mod-twdvV2hR.d.cts} +2 -2
  70. package/dist/mod.cjs +10 -10
  71. package/dist/mod.d.cts +10 -10
  72. package/dist/mod.d.ts +10 -10
  73. package/dist/mod.js +10 -10
  74. package/dist/nodeinfo/client.test.js +5 -5
  75. package/dist/nodeinfo/handler.test.js +16 -16
  76. package/dist/nodeinfo/mod.cjs +2 -2
  77. package/dist/nodeinfo/mod.js +2 -2
  78. package/dist/nodeinfo/types.test.js +3 -3
  79. package/dist/{owner-B-7Ptt_m.d.cts → owner-BN_tO3cY.d.cts} +2 -2
  80. package/dist/{owner-D2fTlp_x.js → owner-CaIfLBwg.js} +2 -2
  81. package/dist/{owner-CQPnQVtf.d.ts → owner-hd9lvQcP.d.ts} +2 -2
  82. package/dist/{proof-C4Y4gJcm.cjs → proof-AhyVJcNZ.cjs} +3 -3
  83. package/dist/{proof-kEUjWRNJ.js → proof-BQwXHakc.js} +2 -2
  84. package/dist/{proof-CHM9su4L.js → proof-CKXppjee.js} +3 -3
  85. package/dist/runtime/authdocloader.test.js +9 -9
  86. package/dist/runtime/docloader.test.js +4 -4
  87. package/dist/runtime/key.test.js +5 -5
  88. package/dist/runtime/langstr.test.js +3 -3
  89. package/dist/runtime/link.test.js +3 -3
  90. package/dist/runtime/mod.cjs +6 -6
  91. package/dist/runtime/mod.d.cts +3 -3
  92. package/dist/runtime/mod.d.ts +3 -3
  93. package/dist/runtime/mod.js +6 -6
  94. package/dist/runtime/multibase/multibase.test.js +3 -3
  95. package/dist/runtime/url.test.js +3 -3
  96. package/dist/{send-Utq2Jm0I.js → send-DQd3R1Oc.js} +2 -2
  97. package/dist/sig/http.test.js +8 -8
  98. package/dist/sig/key.test.js +6 -6
  99. package/dist/sig/ld.test.js +7 -7
  100. package/dist/sig/mod.cjs +6 -6
  101. package/dist/sig/mod.d.cts +5 -5
  102. package/dist/sig/mod.d.ts +5 -5
  103. package/dist/sig/mod.js +6 -6
  104. package/dist/sig/owner.test.js +7 -7
  105. package/dist/sig/proof.test.js +7 -7
  106. package/dist/testing/docloader.test.js +3 -3
  107. package/dist/testing/mod.d.ts +391 -86
  108. package/dist/testing/mod.js +3 -3
  109. package/dist/{testing-DUpTIvNE.js → testing-BljKU-GG.js} +2 -2
  110. package/dist/{type-BYN6Ax2M.js → type-COb6KNlm.js} +6943 -2120
  111. package/dist/{types-BXkh8ctL.js → types-CEn4wB51.js} +1 -1
  112. package/dist/{types-BBpQe860.cjs → types-DI0yutHB.cjs} +1 -1
  113. package/dist/vocab/actor.test.js +5 -5
  114. package/dist/vocab/lookup.test.js +255 -5
  115. package/dist/vocab/mod.cjs +4 -4
  116. package/dist/vocab/mod.d.cts +3 -3
  117. package/dist/vocab/mod.d.ts +3 -3
  118. package/dist/vocab/mod.js +4 -4
  119. package/dist/vocab/type.test.js +3 -3
  120. package/dist/vocab/vocab.test.js +397 -8
  121. package/dist/{vocab-SOE1ifCr.d.ts → vocab-BI0Ak5lL.d.ts} +290 -0
  122. package/dist/{vocab-PKJB4DyY.js → vocab-CkWH9P5l.js} +23 -14
  123. package/dist/{vocab-DJTYMqyU.d.cts → vocab-Dw1-yVGg.d.cts} +290 -0
  124. package/dist/{vocab-DWZQ7gVQ.cjs → vocab-NZXL5Pr-.cjs} +23 -14
  125. package/dist/webfinger/handler.test.js +16 -16
  126. package/dist/webfinger/lookup.test.js +4 -4
  127. package/dist/webfinger/mod.cjs +2 -2
  128. package/dist/webfinger/mod.js +2 -2
  129. package/dist/x/cfworkers.test.js +3 -3
  130. package/dist/x/hono.d.cts +6 -6
  131. package/dist/x/hono.d.ts +6 -6
  132. package/dist/x/sveltekit.d.cts +6 -6
  133. package/dist/x/sveltekit.d.ts +6 -6
  134. package/package.json +1 -1
  135. package/dist/key-BvvbahfP.cjs +0 -10
  136. package/dist/middleware-BD1IE5O5.js +0 -26
  137. package/dist/middleware-BuZrvrDv.js +0 -17
  138. package/dist/middleware-h_3nRr8m.cjs +0 -17
@@ -1,5 +1,5 @@
1
1
  import { DocumentLoader } from "./docloader-D-MrRyHl.cjs";
2
- import { CryptographicKey, Multikey } from "./vocab-DJTYMqyU.cjs";
2
+ import { CryptographicKey, Multikey } from "./vocab-Dw1-yVGg.cjs";
3
3
  import { TracerProvider } from "@opentelemetry/api";
4
4
 
5
5
  //#region src/sig/key.d.ts
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { DocumentLoader } from "./docloader-CxWcuWqQ.js";
4
- import { CryptographicKey, Multikey } from "./vocab-SOE1ifCr.js";
4
+ import { CryptographicKey, Multikey } from "./vocab-BI0Ak5lL.js";
5
5
  import { TracerProvider } from "@opentelemetry/api";
6
6
 
7
7
  //#region src/sig/key.d.ts
@@ -2,9 +2,9 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { deno_default } from "./docloader-_WdHTWQR.js";
6
- import { CryptographicKey } from "./actor-m_ko-86v.js";
7
- import { fetchKey, validateCryptoKey } from "./key-Cf8KTg-A.js";
5
+ import { deno_default } from "./docloader-AMdJU291.js";
6
+ import { CryptographicKey } from "./actor-C0gLJq8I.js";
7
+ import { fetchKey, validateCryptoKey } from "./key-DFefr8X2.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
10
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
@@ -3,9 +3,9 @@
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
5
  const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_docloader = require('./docloader-SZjTrl6Z.cjs');
7
- const require_actor = require('./actor-CNUje03O.cjs');
8
- const require_key = require('./key-JqiQvcq1.cjs');
6
+ const require_docloader = require('./docloader-BdF5STdg.cjs');
7
+ const require_actor = require('./actor-CsRJa7wV.cjs');
8
+ const require_key = require('./key-D-RgWfcf.cjs');
9
9
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
10
10
  const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
11
11
  const byte_encodings_base64 = require_chunk.__toESM(require("byte-encodings/base64"));
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { CryptographicKey, deno_default } from "./type-BYN6Ax2M.js";
7
- import { fetchKey, validateCryptoKey } from "./key-Cps8Sv3N.js";
6
+ import { CryptographicKey, deno_default } from "./type-COb6KNlm.js";
7
+ import { fetchKey, validateCryptoKey } from "./key-BSJX6n9o.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
10
10
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Activity, deno_default, getTypeId } from "./type-BYN6Ax2M.js";
6
+ import { Activity, deno_default, getTypeId } from "./type-COb6KNlm.js";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
9
9
 
@@ -41,17 +41,34 @@ var InboxListenerSet = class InboxListenerSet {
41
41
  return this.dispatchWithClass(activity)?.listener ?? null;
42
42
  }
43
43
  };
44
- async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider }) {
44
+ async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
45
45
  const logger = getLogger([
46
46
  "fedify",
47
47
  "federation",
48
48
  "inbox"
49
49
  ]);
50
- const cacheKey = activity.id == null ? null : [
51
- ...kvPrefixes.activityIdempotence,
52
- ctx.origin,
53
- activity.id.href
54
- ];
50
+ let cacheKey = null;
51
+ if (activity.id != null) {
52
+ const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
53
+ const strategy = idempotencyStrategy ?? "per-inbox";
54
+ let keyString;
55
+ if (typeof strategy === "function") {
56
+ const result = await strategy(inboxContext, activity);
57
+ keyString = result;
58
+ } else switch (strategy) {
59
+ case "global":
60
+ keyString = activity.id.href;
61
+ break;
62
+ case "per-origin":
63
+ keyString = `${ctx.origin}\n${activity.id.href}`;
64
+ break;
65
+ case "per-inbox":
66
+ keyString = `${ctx.origin}\n${activity.id.href}\n${recipient == null ? "sharedInbox" : `inbox\n${recipient}`}`;
67
+ break;
68
+ default: keyString = `${ctx.origin}\n${activity.id.href}`;
69
+ }
70
+ if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
71
+ }
55
72
  if (cacheKey != null) {
56
73
  const cached = await kv.get(cacheKey);
57
74
  if (cached === true) {
@@ -2,9 +2,9 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import "./docloader-_WdHTWQR.js";
6
- import "./actor-m_ko-86v.js";
7
- import "./lookup-C6WSLjPE.js";
8
- import { exportJwk, fetchKey, generateCryptoKeyPair, importJwk, validateCryptoKey } from "./key-Cf8KTg-A.js";
5
+ import "./docloader-AMdJU291.js";
6
+ import "./actor-C0gLJq8I.js";
7
+ import "./lookup-BGCuyJRy.js";
8
+ import { exportJwk, fetchKey, generateCryptoKeyPair, importJwk, validateCryptoKey } from "./key-DFefr8X2.js";
9
9
 
10
10
  export { validateCryptoKey };
@@ -0,0 +1,10 @@
1
+
2
+ const { Temporal } = require("@js-temporal/polyfill");
3
+ const { URLPattern } = require("urlpattern-polyfill");
4
+
5
+ require('./docloader-BdF5STdg.cjs');
6
+ require('./actor-CsRJa7wV.cjs');
7
+ require('./lookup-B2Bsau2g.cjs');
8
+ const require_key = require('./key-D-RgWfcf.cjs');
9
+
10
+ exports.validateCryptoKey = require_key.validateCryptoKey;
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { CryptographicKey, Object as Object$1, deno_default, getDocumentLoader } from "./type-BYN6Ax2M.js";
7
- import { isActor } from "./actor-BxAu0qet.js";
6
+ import { CryptographicKey, Object as Object$1, deno_default, getDocumentLoader } from "./type-COb6KNlm.js";
7
+ import { isActor } from "./actor-VrXd7EdX.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
10
10
 
@@ -3,8 +3,8 @@
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
5
  const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_docloader = require('./docloader-SZjTrl6Z.cjs');
7
- const require_actor = require('./actor-CNUje03O.cjs');
6
+ const require_docloader = require('./docloader-BdF5STdg.cjs');
7
+ const require_actor = require('./actor-CsRJa7wV.cjs');
8
8
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
9
9
  const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
10
10
 
@@ -2,8 +2,8 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { deno_default, getDocumentLoader } from "./docloader-_WdHTWQR.js";
6
- import { CryptographicKey, Object as Object$1, isActor } from "./actor-m_ko-86v.js";
5
+ import { deno_default, getDocumentLoader } from "./docloader-AMdJU291.js";
6
+ import { CryptographicKey, Object as Object$1, isActor } from "./actor-C0gLJq8I.js";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
9
9
 
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import "./type-BYN6Ax2M.js";
7
- import "./actor-BxAu0qet.js";
8
- import { exportJwk, fetchKey, generateCryptoKeyPair, importJwk, validateCryptoKey } from "./key-Cps8Sv3N.js";
6
+ import "./type-COb6KNlm.js";
7
+ import "./actor-VrXd7EdX.js";
8
+ import { exportJwk, fetchKey, generateCryptoKeyPair, importJwk, validateCryptoKey } from "./key-BSJX6n9o.js";
9
9
 
10
10
  export { validateCryptoKey };
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { CryptographicKey, Multikey } from "./type-BYN6Ax2M.js";
6
+ import { CryptographicKey, Multikey } from "./type-COb6KNlm.js";
7
7
 
8
8
  //#region src/federation/keycache.ts
9
9
  var KvKeyCache = class {
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { CryptographicKey, Multikey, importSpki } from "./type-BYN6Ax2M.js";
6
+ import { CryptographicKey, Multikey, importSpki } from "./type-COb6KNlm.js";
7
7
 
8
8
  //#region src/testing/keys.ts
9
9
  const rsaPublicKey1 = new CryptographicKey({
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Activity, CryptographicKey, Object as Object$1, deno_default, getDocumentLoader, getTypeId } from "./type-BYN6Ax2M.js";
7
- import { fetchKey, validateCryptoKey } from "./key-Cps8Sv3N.js";
6
+ import { Activity, CryptographicKey, Object as Object$1, deno_default, getDocumentLoader, getTypeId } from "./type-COb6KNlm.js";
7
+ import { fetchKey, validateCryptoKey } from "./key-BSJX6n9o.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
10
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
@@ -3,7 +3,7 @@
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
5
  const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_docloader = require('./docloader-SZjTrl6Z.cjs');
6
+ const require_docloader = require('./docloader-BdF5STdg.cjs');
7
7
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
8
8
  const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
9
9
 
@@ -2,7 +2,7 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { UrlError, deno_default, getUserAgent, validatePublicUrl } from "./docloader-_WdHTWQR.js";
5
+ import { UrlError, deno_default, getUserAgent, validatePublicUrl } from "./docloader-AMdJU291.js";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
8
8
 
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { Object as Object$1, deno_default, getDocumentLoader, getTypeId, lookupWebFinger } from "./type-BYN6Ax2M.js";
6
+ import { Object as Object$1, deno_default, getDocumentLoader, getTypeId, lookupWebFinger } from "./type-COb6KNlm.js";
7
7
  import { cloneDeep, delay } from "es-toolkit";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -240,14 +240,13 @@ async function lookupObject(identifier, options = {}) {
240
240
  async function lookupObjectInternal(identifier, options = {}) {
241
241
  const documentLoader = options.documentLoader ?? getDocumentLoader({ userAgent: options.userAgent });
242
242
  if (typeof identifier === "string") identifier = toAcctUrl(identifier) ?? new URL(identifier);
243
- let document = null;
243
+ let remoteDoc = null;
244
244
  if (identifier.protocol === "http:" || identifier.protocol === "https:") try {
245
- const remoteDoc = await documentLoader(identifier.href, { signal: options.signal });
246
- document = remoteDoc.document;
245
+ remoteDoc = await documentLoader(identifier.href, { signal: options.signal });
247
246
  } catch (error) {
248
247
  logger.debug("Failed to fetch remote document:\n{error}", { error });
249
248
  }
250
- if (document == null) {
249
+ if (remoteDoc == null) {
251
250
  const jrd = await lookupWebFinger(identifier, {
252
251
  userAgent: options.userAgent,
253
252
  tracerProvider: options.tracerProvider,
@@ -258,8 +257,7 @@ async function lookupObjectInternal(identifier, options = {}) {
258
257
  for (const l of jrd.links) {
259
258
  if (l.type !== "application/activity+json" && !l.type?.match(/application\/ld\+json;\s*profile="https:\/\/www.w3.org\/ns\/activitystreams"/) || l.rel !== "self" || l.href == null) continue;
260
259
  try {
261
- const remoteDoc = await documentLoader(l.href, { signal: options.signal });
262
- document = remoteDoc.document;
260
+ remoteDoc = await documentLoader(l.href, { signal: options.signal });
263
261
  break;
264
262
  } catch (error) {
265
263
  logger.debug("Failed to fetch remote document:\n{error}", { error });
@@ -267,23 +265,34 @@ async function lookupObjectInternal(identifier, options = {}) {
267
265
  }
268
266
  }
269
267
  }
270
- if (document == null) return null;
268
+ if (remoteDoc == null) return null;
269
+ let object;
271
270
  try {
272
- return await Object$1.fromJsonLd(document, {
271
+ object = await Object$1.fromJsonLd(remoteDoc.document, {
273
272
  documentLoader,
274
273
  contextLoader: options.contextLoader,
275
- tracerProvider: options.tracerProvider
274
+ tracerProvider: options.tracerProvider,
275
+ baseUrl: new URL(remoteDoc.documentUrl)
276
276
  });
277
277
  } catch (error) {
278
278
  if (error instanceof TypeError) {
279
279
  logger.debug("Failed to parse JSON-LD document: {error}\n{document}", {
280
- error,
281
- document
280
+ ...remoteDoc,
281
+ error
282
282
  });
283
283
  return null;
284
284
  }
285
285
  throw error;
286
286
  }
287
+ if (options.crossOrigin !== "trust" && object.id != null && object.id.origin !== new URL(remoteDoc.documentUrl).origin) {
288
+ if (options.crossOrigin === "throw") throw new Error(`The object's @id (${object.id.href}) has a different origin than the document URL (${remoteDoc.documentUrl}); refusing to return the object. If you want to bypass this check and are aware of the security implications, set the crossOrigin option to "trust".`);
289
+ logger.warn("The object's @id ({objectId}) has a different origin than the document URL ({documentUrl}); refusing to return the object. If you want to bypass this check and are aware of the security implications, set the crossOrigin option to \"trust\".", {
290
+ ...remoteDoc,
291
+ objectId: object.id.href
292
+ });
293
+ return null;
294
+ }
295
+ return object;
287
296
  }
288
297
  /**
289
298
  * Traverses a collection, yielding each item in the collection.
@@ -3,15 +3,15 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
5
  import { getDefaultActivityTransformers } from "./transformers-BFT6d7J5.js";
6
- import { deno_default, getDocumentLoader, kvCache } from "./docloader-_WdHTWQR.js";
7
- import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId } from "./actor-m_ko-86v.js";
8
- import { lookupWebFinger } from "./lookup-C6WSLjPE.js";
9
- import { exportJwk, importJwk, validateCryptoKey } from "./key-Cf8KTg-A.js";
10
- import { doubleKnock, verifyRequest } from "./http-BpoEurUR.js";
11
- import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-CHM9su4L.js";
12
- import { getNodeInfo, nodeInfoToJson } from "./types-BXkh8ctL.js";
13
- import { getAuthenticatedDocumentLoader } from "./authdocloader-nRFL9luh.js";
14
- import { lookupObject, traverseCollection } from "./vocab-PKJB4DyY.js";
6
+ import { deno_default, getDocumentLoader, kvCache } from "./docloader-AMdJU291.js";
7
+ import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId } from "./actor-C0gLJq8I.js";
8
+ import { lookupWebFinger } from "./lookup-BGCuyJRy.js";
9
+ import { exportJwk, importJwk, validateCryptoKey } from "./key-DFefr8X2.js";
10
+ import { doubleKnock, verifyRequest } from "./http-DVQEn98K.js";
11
+ import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-CKXppjee.js";
12
+ import { getNodeInfo, nodeInfoToJson } from "./types-CEn4wB51.js";
13
+ import { getAuthenticatedDocumentLoader } from "./authdocloader-6F9IP-VO.js";
14
+ import { lookupObject, traverseCollection } from "./vocab-CkWH9P5l.js";
15
15
  import { getLogger, withContext } from "@logtape/logtape";
16
16
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
17
17
  import { encodeHex } from "byte-encodings/hex";
@@ -55,17 +55,34 @@ var InboxListenerSet = class InboxListenerSet {
55
55
  return this.dispatchWithClass(activity)?.listener ?? null;
56
56
  }
57
57
  };
58
- async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider }) {
58
+ async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
59
59
  const logger$1 = getLogger([
60
60
  "fedify",
61
61
  "federation",
62
62
  "inbox"
63
63
  ]);
64
- const cacheKey = activity.id == null ? null : [
65
- ...kvPrefixes.activityIdempotence,
66
- ctx.origin,
67
- activity.id.href
68
- ];
64
+ let cacheKey = null;
65
+ if (activity.id != null) {
66
+ const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
67
+ const strategy = idempotencyStrategy ?? "per-inbox";
68
+ let keyString;
69
+ if (typeof strategy === "function") {
70
+ const result = await strategy(inboxContext, activity);
71
+ keyString = result;
72
+ } else switch (strategy) {
73
+ case "global":
74
+ keyString = activity.id.href;
75
+ break;
76
+ case "per-origin":
77
+ keyString = `${ctx.origin}\n${activity.id.href}`;
78
+ break;
79
+ case "per-inbox":
80
+ keyString = `${ctx.origin}\n${activity.id.href}\n${recipient == null ? "sharedInbox" : `inbox\n${recipient}`}`;
81
+ break;
82
+ default: keyString = `${ctx.origin}\n${activity.id.href}`;
83
+ }
84
+ if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
85
+ }
69
86
  if (cacheKey != null) {
70
87
  const cached = await kv.get(cacheKey);
71
88
  if (cached === true) {
@@ -307,6 +324,7 @@ var FederationBuilderImpl = class {
307
324
  inboxListeners;
308
325
  inboxErrorHandler;
309
326
  sharedInboxKeyDispatcher;
327
+ idempotencyStrategy;
310
328
  collectionTypeIds;
311
329
  collectionCallbacks;
312
330
  /**
@@ -321,7 +339,7 @@ var FederationBuilderImpl = class {
321
339
  this.collectionTypeIds = {};
322
340
  }
323
341
  async build(options) {
324
- const { FederationImpl: FederationImpl$1 } = await import("./middleware-BuZrvrDv.js");
342
+ const { FederationImpl: FederationImpl$1 } = await import("./middleware-DipQbJmB.js");
325
343
  const f = new FederationImpl$1(options);
326
344
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
327
345
  f.router = this.router.clone();
@@ -343,6 +361,7 @@ var FederationBuilderImpl = class {
343
361
  f.inboxListeners = this.inboxListeners?.clone();
344
362
  f.inboxErrorHandler = this.inboxErrorHandler;
345
363
  f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
364
+ f.idempotencyStrategy = this.idempotencyStrategy;
346
365
  return f;
347
366
  }
348
367
  _getTracer() {
@@ -765,15 +784,19 @@ var FederationBuilderImpl = class {
765
784
  setSharedKeyDispatcher: (dispatcher) => {
766
785
  this.sharedInboxKeyDispatcher = dispatcher;
767
786
  return setters;
787
+ },
788
+ withIdempotency: (strategy) => {
789
+ this.idempotencyStrategy = strategy;
790
+ return setters;
768
791
  }
769
792
  };
770
793
  return setters;
771
794
  }
772
- setCollectionDispatcher(name, ...args) {
773
- return this.#setCustomCollectionDispatcher(name, "collection", ...args);
795
+ setCollectionDispatcher(name, itemType, path, dispatcher) {
796
+ return this.#setCustomCollectionDispatcher(name, "collection", itemType, path, dispatcher);
774
797
  }
775
- setOrderedCollectionDispatcher(name, ...args) {
776
- return this.#setCustomCollectionDispatcher(name, "orderedCollection", ...args);
798
+ setOrderedCollectionDispatcher(name, itemType, path, dispatcher) {
799
+ return this.#setCustomCollectionDispatcher(name, "orderedCollection", itemType, path, dispatcher);
777
800
  }
778
801
  #setCustomCollectionDispatcher(name, collectionType, itemType, path, dispatcher) {
779
802
  const strName = String(name);
@@ -1293,7 +1316,8 @@ async function handleInbox(request, options) {
1293
1316
  * @param span The OpenTelemetry span for tracing.
1294
1317
  * @returns A promise that resolves to an HTTP response.
1295
1318
  */
1296
- async function handleInboxInternal(request, { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider }, span) {
1319
+ async function handleInboxInternal(request, parameters, span) {
1320
+ const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider } = parameters;
1297
1321
  const logger$1 = getLogger([
1298
1322
  "fedify",
1299
1323
  "federation",
@@ -1495,7 +1519,8 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
1495
1519
  kvPrefixes,
1496
1520
  queue,
1497
1521
  span,
1498
- tracerProvider
1522
+ tracerProvider,
1523
+ idempotencyStrategy: parameters.idempotencyStrategy
1499
1524
  });
1500
1525
  if (routeResult === "alreadyProcessed") return new Response(`Activity <${activity.id}> has already been processed.`, {
1501
1526
  status: 202,
@@ -1525,7 +1550,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
1525
1550
  /**
1526
1551
  * Handles a custom collection request.
1527
1552
  * @template TItem The type of items in the collection.
1528
- * @template TParams The parameter names of the requested URL.
1553
+ * @template TParam The parameter names of the requested URL.
1529
1554
  * @template TContext The type of the context, extending {@link RequestContext}.
1530
1555
  * @template TContextData The context data to pass to the `TContext`.
1531
1556
  * @param request The HTTP request.
@@ -1543,7 +1568,7 @@ async function _handleCustomCollection(request, { name, values, context: context
1543
1568
  /**
1544
1569
  * Handles an ordered collection request.
1545
1570
  * @template TItem The type of items in the collection.
1546
- * @template TParams The parameter names of the requested URL.
1571
+ * @template TParam The parameter names of the requested URL.
1547
1572
  * @template TContext The type of the context, extending {@link RequestContext}.
1548
1573
  * @template TContextData The context data to pass to the `TContext`.
1549
1574
  * @param request The HTTP request.
@@ -1563,7 +1588,7 @@ async function _handleOrderedCollection(request, { name, values, context: contex
1563
1588
  * The main flow is on `getCollection`, `dispatch`.
1564
1589
  *
1565
1590
  * @template TItem The type of items in the collection.
1566
- * @template TParams The parameter names of the requested URL.
1591
+ * @template TParam The parameter names of the requested URL.
1567
1592
  * @template TContext The type of the context. {@link Context} or {@link RequestContext}.
1568
1593
  * @template TContextData The context data to pass to the `TContext`.
1569
1594
  * @template TCollection The type of the collection, extending {@link Collection}.
@@ -1597,14 +1622,14 @@ var CustomCollectionHandler = class {
1597
1622
  #collection = null;
1598
1623
  /**
1599
1624
  * Creates a new CustomCollection instance.
1600
- * @param {string} name The name of the collection.
1601
- * @param {TParams} values The parameter values for the collection.
1602
- * @param {TContext} context The request context.
1603
- * @param {CustomCollectionCallbacks} callbacks The collection callbacks.
1604
- * @param {TracerProvider} tracerProvider The tracer provider for telemetry.
1605
- * @param {ConstructorWithTypeId<TCollection>} Collection The Collection constructor.
1606
- * @param {ConstructorWithTypeId<TCollectionPage>} CollectionPage The CollectionPage constructor.
1607
- * @param {(item: TItem) => boolean} filterPredicate Optional filter predicate for items.
1625
+ * @param name The name of the collection.
1626
+ * @param values The parameter values for the collection.
1627
+ * @param context The request context.
1628
+ * @param callbacks The collection callbacks.
1629
+ * @param tracerProvider The tracer provider for telemetry.
1630
+ * @param Collection The Collection constructor.
1631
+ * @param CollectionPage The CollectionPage constructor.
1632
+ * @param filterPredicate Optional filter predicate for items.
1608
1633
  */
1609
1634
  constructor(name, values, context$1, callbacks, tracerProvider = trace.getTracerProvider(), Collection$1, CollectionPage$1, filterPredicate) {
1610
1635
  this.name = name;
@@ -1729,7 +1754,7 @@ var CustomCollectionHandler = class {
1729
1754
  /**
1730
1755
  * Creates a function to wrap the dispatcher so tracing can be applied.
1731
1756
  * @param params Parameters including cursor and total items.
1732
- * @returns {(span: Span) => Promise<PageItems<TItem>>} A function that handles the span operation.
1757
+ * @returns A function that handles the span operation.
1733
1758
  */
1734
1759
  spanPages = ({ totalItems = null, cursor = null }) => async (span) => {
1735
1760
  try {
@@ -1750,23 +1775,23 @@ var CustomCollectionHandler = class {
1750
1775
  };
1751
1776
  /**
1752
1777
  * Dispatches the collection request to get items.
1753
- * @param {string | null} cursor The cursor for pagination, or null for the first page.
1754
- * @returns {Promise<PageItems<TItem>>} A promise that resolves to the page items.
1778
+ * @param cursor The cursor for pagination, or null for the first page.
1779
+ * @returns A promise that resolves to the page items.
1755
1780
  */
1756
1781
  async dispatch(cursor = null) {
1757
1782
  return await this.#dispatcher(this.context, this.values, cursor) ?? new ItemsNotFoundError().throw();
1758
1783
  }
1759
1784
  /**
1760
1785
  * Filters the items in the collection.
1761
- * @param {TItem[]} items The items to filter.
1762
- * @returns {(Object | Link | URL)[]} The filtered items.
1786
+ * @param items The items to filter.
1787
+ * @returns The filtered items.
1763
1788
  */
1764
1789
  filterItems(items) {
1765
1790
  return filterCollectionItems(items, this.name, this.filterPredicate);
1766
1791
  }
1767
1792
  /**
1768
1793
  * Appends a cursor to the URL if it exists.
1769
- * @param {string | null | undefined} cursor The cursor to append, or null/undefined.
1794
+ * @param cursor The cursor to append, or null/undefined.
1770
1795
  * @returns The URL with cursor appended, or null if cursor is null/undefined.
1771
1796
  */
1772
1797
  appendToUrl(cursor) {
@@ -1774,8 +1799,7 @@ var CustomCollectionHandler = class {
1774
1799
  }
1775
1800
  /**
1776
1801
  * Gets the stored collection or collection page.
1777
- * @returns {Promise<TCollection | TCollectionPage>} A promise that resolves to
1778
- the collection or collection page.
1802
+ * @returns A promise that resolves to the collection or collection page.
1779
1803
  */
1780
1804
  get collection() {
1781
1805
  if (this.#collection === null) this.#collection = this.getCollection();
@@ -1783,8 +1807,8 @@ var CustomCollectionHandler = class {
1783
1807
  }
1784
1808
  /**
1785
1809
  * Gets the total number of items in the collection.
1786
- * @returns {Promise<number | null>} A promise that
1787
- resolves to the total items count, or null if not available.
1810
+ * @returns A promise that resolves to the total items count,
1811
+ * or null if not available.
1788
1812
  */
1789
1813
  get totalItems() {
1790
1814
  if (this.#totalItems === void 0) this.totalItems = this.callbacks.counter?.(this.context, this.values);
@@ -1800,8 +1824,8 @@ var CustomCollectionHandler = class {
1800
1824
  }
1801
1825
  /**
1802
1826
  * Gets the first cursor for pagination.
1803
- * @returns {Promise<string | null>} A promise that resolves to the first cursor,
1804
- or null if not available.
1827
+ * @returns A promise that resolves to the first cursor,
1828
+ * or null if not available.
1805
1829
  */
1806
1830
  get firstCursor() {
1807
1831
  const cursor = this.callbacks.firstCursor?.(this.context, this.values);
@@ -2325,7 +2349,6 @@ var FederationImpl = class extends FederationBuilderImpl {
2325
2349
  firstKnock;
2326
2350
  constructor(options) {
2327
2351
  super();
2328
- const logger$1 = getLogger(["fedify", "federation"]);
2329
2352
  this.kv = options.kv;
2330
2353
  this.kvPrefixes = {
2331
2354
  activityIdempotence: ["_fedify", "activityIdempotence"],
@@ -2373,8 +2396,9 @@ var FederationImpl = class extends FederationBuilderImpl {
2373
2396
  this.router.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false;
2374
2397
  this._initializeRouter();
2375
2398
  if (options.allowPrivateAddress || options.userAgent != null) {
2376
- if (options.contextLoader != null) throw new TypeError("Cannot set contextLoader with allowPrivateAddress or userAgent options.");
2377
- else if (options.authenticatedDocumentLoaderFactory != null) throw new TypeError("Cannot set authenticatedDocumentLoaderFactory with allowPrivateAddress or userAgent options.");
2399
+ if (options.documentLoaderFactory != null) throw new TypeError("Cannot set documentLoaderFactory with allowPrivateAddress or userAgent options.");
2400
+ if (options.contextLoaderFactory != null) throw new TypeError("Cannot set contextLoaderFactory with allowPrivateAddress or userAgent options.");
2401
+ if (options.authenticatedDocumentLoaderFactory != null) throw new TypeError("Cannot set authenticatedDocumentLoaderFactory with allowPrivateAddress or userAgent options.");
2378
2402
  }
2379
2403
  const { allowPrivateAddress, userAgent } = options;
2380
2404
  this.allowPrivateAddress = allowPrivateAddress ?? false;
@@ -2388,11 +2412,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2388
2412
  prefix: this.kvPrefixes.remoteDocument
2389
2413
  });
2390
2414
  });
2391
- if (options.contextLoader != null) {
2392
- if (options.contextLoaderFactory != null) throw new TypeError("Cannot set both contextLoader and contextLoaderFactory options at a time; use contextLoaderFactory only.");
2393
- this.contextLoaderFactory = () => options.contextLoader;
2394
- logger$1.warn("The contextLoader option is deprecated; use contextLoaderFactory option instead.");
2395
- } else this.contextLoaderFactory = options.contextLoaderFactory ?? this.documentLoaderFactory;
2415
+ this.contextLoaderFactory = options.contextLoaderFactory ?? this.documentLoaderFactory;
2396
2416
  this.authenticatedDocumentLoaderFactory = options.authenticatedDocumentLoaderFactory ?? ((identity) => getAuthenticatedDocumentLoader(identity, {
2397
2417
  allowPrivateAddress,
2398
2418
  userAgent,
@@ -2996,7 +3016,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2996
3016
  nodeInfoDispatcher: this.nodeInfoDispatcher
2997
3017
  });
2998
3018
  }
2999
- if (!acceptsJsonLd(request)) return await onNotAcceptable(request);
3019
+ if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
3000
3020
  switch (routeName) {
3001
3021
  case "actor":
3002
3022
  context$1 = this.#createContext(request, contextData, { invokedFromActorDispatcher: { identifier: route.values.identifier ?? route.values.handle } });
@@ -3066,7 +3086,8 @@ var FederationImpl = class extends FederationBuilderImpl {
3066
3086
  onNotFound,
3067
3087
  signatureTimeWindow: this.signatureTimeWindow,
3068
3088
  skipSignatureVerification: this.skipSignatureVerification,
3069
- tracerProvider: this.tracerProvider
3089
+ tracerProvider: this.tracerProvider,
3090
+ idempotencyStrategy: this.idempotencyStrategy
3070
3091
  });
3071
3092
  case "following": return await handleCollection(request, {
3072
3093
  name: "following",
@@ -3809,7 +3830,8 @@ var ContextImpl = class ContextImpl {
3809
3830
  kvPrefixes: this.federation.kvPrefixes,
3810
3831
  queue: this.federation.inboxQueue,
3811
3832
  span,
3812
- tracerProvider: options.tracerProvider ?? this.tracerProvider
3833
+ tracerProvider: options.tracerProvider ?? this.tracerProvider,
3834
+ idempotencyStrategy: this.federation.idempotencyStrategy
3813
3835
  });
3814
3836
  return routeResult === "alreadyProcessed" || routeResult === "enqueued" || routeResult === "unsupportedActivity" || routeResult === "success";
3815
3837
  }