@fedify/fedify 2.4.0-pr.936.41 → 2.5.0-dev.2271

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 (244) hide show
  1. package/README.md +50 -39
  2. package/dist/{assert-CJ1KXcvv.mjs → assert-D1Eafmd_.mjs} +1 -1
  3. package/dist/{assert_equals-BV7oLMxm.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
  4. package/dist/assert_exists-cffSpJ7X.mjs +28 -0
  5. package/dist/assert_false-CPdRnc3E.mjs +23 -0
  6. package/dist/assert_greater_or_equal-BlafOF4-.mjs +31 -0
  7. package/dist/{assert_instance_of-Q9KTBnrf.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
  8. package/dist/{assert_not_equals-EPJPoxuf.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
  9. package/dist/assert_rejects-CTptdYck.mjs +39 -0
  10. package/dist/{assert_strict_equals-Ec20AUwa.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
  11. package/dist/{assert_throws-NiFfqbnH.mjs → assert_throws-BYITOvPO.mjs} +2 -1
  12. package/dist/assertion_error-B-cx0fFA.mjs +31 -0
  13. package/dist/audience-CHQ-FlLD.mjs +95 -0
  14. package/dist/{builder-DonuxRl_.mjs → builder-Bda6LK7A.mjs} +169 -14
  15. package/dist/{circuit-breaker-CBGyz5F7.mjs → circuit-breaker-XJ53md4S.mjs} +224 -17
  16. package/dist/circuit-breaker-test-utils-DW6YC_Pe.mjs +14 -0
  17. package/dist/{client-CjF5IYQS.mjs → client-CEnNz8O7.mjs} +144 -8
  18. package/dist/{codec-BBga-FWI.mjs → codec-C6rTrpIp.mjs} +26 -3
  19. package/dist/{collection-BIhlldqK.mjs → collection-CnnP1UAv.mjs} +1 -1
  20. package/dist/compat/mod.cjs +1 -1
  21. package/dist/compat/mod.d.cts +1 -1
  22. package/dist/compat/mod.d.ts +1 -1
  23. package/dist/compat/mod.js +1 -1
  24. package/dist/compat/outgoing-jsonld.test.mjs +71 -3
  25. package/dist/compat/public-audience.test.mjs +14 -5
  26. package/dist/compat/secured-document.test.d.mts +2 -0
  27. package/dist/compat/secured-document.test.mjs +58 -0
  28. package/dist/compat/transformers.test.mjs +5 -5
  29. package/dist/compound-proof-B-9mXxFW.mjs +989 -0
  30. package/dist/{context-Zii1f5xS.d.ts → context-7NyiqIcg.d.ts} +1600 -25
  31. package/dist/{context-BJXxPElm.mjs → context-8Tu9kea0.mjs} +21 -63
  32. package/dist/{context-lxX6I7as.d.cts → context-tsYPJ2Ew.d.cts} +1600 -25
  33. package/dist/{deno-BHzKn9Ig.mjs → deno-oR5aJKpU.mjs} +1 -1
  34. package/dist/dist-DJQM4u7i.mjs +189 -0
  35. package/dist/docloader-DBoYbvYW.mjs +87 -0
  36. package/dist/{esm-yYQfPhIY.mjs → esm-BHXXx4Wx.mjs} +13 -6
  37. package/dist/federation/audience.test.d.mts +2 -0
  38. package/dist/federation/audience.test.mjs +130 -0
  39. package/dist/federation/builder.test.mjs +54 -5
  40. package/dist/federation/circuit-breaker.test.mjs +838 -7
  41. package/dist/federation/collection.test.mjs +3 -3
  42. package/dist/federation/compound-fanout.test.d.mts +2 -0
  43. package/dist/federation/compound-fanout.test.mjs +228 -0
  44. package/dist/federation/handler-compound-proof.test.d.mts +2 -0
  45. package/dist/federation/handler-compound-proof.test.mjs +384 -0
  46. package/dist/federation/handler.test.mjs +385 -15
  47. package/dist/federation/hashlink-media.test.d.mts +2 -0
  48. package/dist/federation/hashlink-media.test.mjs +422 -0
  49. package/dist/federation/idempotency.test.mjs +6 -6
  50. package/dist/federation/inbox-report.test.d.mts +2 -0
  51. package/dist/federation/inbox-report.test.mjs +475 -0
  52. package/dist/federation/inbox.test.mjs +3 -3
  53. package/dist/federation/keycache.test.mjs +215 -14
  54. package/dist/federation/kv.test.mjs +3 -3
  55. package/dist/federation/metrics.test.mjs +5 -5
  56. package/dist/federation/middleware.test.mjs +967 -35
  57. package/dist/federation/mod.cjs +18 -261
  58. package/dist/federation/mod.d.cts +5 -5
  59. package/dist/federation/mod.d.ts +5 -5
  60. package/dist/federation/mod.js +279 -1
  61. package/dist/federation/mq.test.mjs +123 -47
  62. package/dist/federation/negotiation.test.mjs +4 -4
  63. package/dist/federation/outgoing-proof.test.d.mts +2 -0
  64. package/dist/federation/outgoing-proof.test.mjs +931 -0
  65. package/dist/federation/portable-actor.test.d.mts +2 -0
  66. package/dist/federation/portable-actor.test.mjs +496 -0
  67. package/dist/federation/portable-chain.test.d.mts +2 -0
  68. package/dist/federation/portable-chain.test.mjs +370 -0
  69. package/dist/federation/portable-collection.test.d.mts +2 -0
  70. package/dist/federation/portable-collection.test.mjs +832 -0
  71. package/dist/federation/portable-delivery.test.d.mts +2 -0
  72. package/dist/federation/portable-delivery.test.mjs +746 -0
  73. package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
  74. package/dist/federation/portable-gateway-keys.test.mjs +686 -0
  75. package/dist/federation/portable-inbox.test.d.mts +2 -0
  76. package/dist/federation/portable-inbox.test.mjs +1535 -0
  77. package/dist/federation/portable-parse-uri.test.d.mts +2 -0
  78. package/dist/federation/portable-parse-uri.test.mjs +348 -0
  79. package/dist/federation/portable-route-activity.test.d.mts +2 -0
  80. package/dist/federation/portable-route-activity.test.mjs +259 -0
  81. package/dist/federation/portable.test.d.mts +2 -0
  82. package/dist/federation/portable.test.mjs +1072 -0
  83. package/dist/federation/retry.test.mjs +4 -3
  84. package/dist/federation/router.test.mjs +9 -159
  85. package/dist/federation/send.test.mjs +245 -27
  86. package/dist/federation/tasks/codec.test.mjs +4 -4
  87. package/dist/federation/tasks/enqueue.test.mjs +42 -4
  88. package/dist/federation/tasks/tasks.test.mjs +7 -6
  89. package/dist/federation/temporal.test.mjs +4 -4
  90. package/dist/federation/webfinger.test.mjs +275 -12
  91. package/dist/{middleware-FrSMAYEx.cjs → federation-CkZiAcWY.cjs} +8640 -3722
  92. package/dist/http-B5JT115n.cjs +10630 -0
  93. package/dist/http-DydWCB7R.js +6527 -0
  94. package/dist/{http-CPVMUgsW.mjs → http-siciWkmx.mjs} +397 -168
  95. package/dist/key-BspPiXqn.mjs +951 -0
  96. package/dist/key-C1nv7_jD.d.ts +1125 -0
  97. package/dist/key-DYxuyd-s.d.cts +1125 -0
  98. package/dist/key-owner-evidence-APB6NpSk.mjs +108 -0
  99. package/dist/keycache-Da8A8mZa.mjs +200 -0
  100. package/dist/{kv-D6hNiMTK.d.ts → kv-B2mzK5tl.d.cts} +3 -2
  101. package/dist/{kv-gJ8LYbxX.d.cts → kv-B2mzK5tl.d.ts} +3 -2
  102. package/dist/kv-DBRWVx3Q.mjs +104 -0
  103. package/dist/{kv-cache-KyGqJqSp.mjs → kv-cache-BF1hnW65.mjs} +1 -1
  104. package/dist/{kv-cache-5bnX3-Jq.js → kv-cache-CTQr1tbn.js} +54 -16
  105. package/dist/{kv-cache-DQ29C4XL.cjs → kv-cache-DCac1nEU.cjs} +55 -19
  106. package/dist/{ld-Cj9F_5AP.mjs → ld-CzaP-hJl.mjs} +44 -12
  107. package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
  108. package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
  109. package/dist/{metrics-DMk-nTxI.mjs → metrics-CYg9yxBL.mjs} +3 -2
  110. package/dist/metrics-DVKYY6K1.d.cts +36 -0
  111. package/dist/metrics-DoRtI0qU.d.ts +36 -0
  112. package/dist/{middleware-Y-kpsp6S.js → middleware-CsDDXKuL.js} +5493 -1103
  113. package/dist/{middleware-CvwTUgnP.mjs → middleware-D7_LO-Vs.mjs} +3157 -272
  114. package/dist/{middleware-CEctxBN6.mjs → middleware-DWjrfpcz.mjs} +1 -1
  115. package/dist/{mod-gOlPDuT8.d.cts → mod-BojP2Bw3.d.cts} +1 -1
  116. package/dist/mod-CavhAgLw.d.cts +320 -0
  117. package/dist/mod-CtpF2BU5.d.ts +320 -0
  118. package/dist/{mod-BtEaIEcD.d.cts → mod-DEZXwV6J.d.ts} +10 -4
  119. package/dist/{mod-UMmveiO0.d.ts → mod-Dw-nPxQh.d.cts} +10 -4
  120. package/dist/{mod-DLc2Ot6f.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
  121. package/dist/mod.cjs +40 -39
  122. package/dist/mod.d.cts +10 -11
  123. package/dist/mod.d.ts +10 -11
  124. package/dist/mod.js +9 -9
  125. package/dist/{mq-llHKivST.mjs → mq-Dm1Wmtm-.mjs} +6 -0
  126. package/dist/nodeinfo/client.test.mjs +139 -4
  127. package/dist/nodeinfo/handler.test.mjs +5 -5
  128. package/dist/nodeinfo/mod.cjs +1 -1
  129. package/dist/nodeinfo/mod.d.cts +1 -1
  130. package/dist/nodeinfo/mod.d.ts +1 -1
  131. package/dist/nodeinfo/mod.js +1 -1
  132. package/dist/nodeinfo/types.test.mjs +4 -4
  133. package/dist/otel/exporter.test.mjs +3 -3
  134. package/dist/otel/mod.cjs +0 -1
  135. package/dist/otel/mod.d.cts +1 -1
  136. package/dist/otel/mod.d.ts +1 -1
  137. package/dist/{outgoing-jsonld-URuqsICz.mjs → outgoing-jsonld-4IJqPYos.mjs} +12 -10
  138. package/dist/{owner-DEvZuyOE.d.cts → owner-BF0L9cMt.d.cts} +11 -0
  139. package/dist/{owner-CnngXDNJ.d.ts → owner-BSzr5-I8.d.ts} +11 -0
  140. package/dist/owner-DYgfTFHy.mjs +267 -0
  141. package/dist/portable-collection-BpsVsRov.js +670 -0
  142. package/dist/portable-collection-C74P1vtC.mjs +418 -0
  143. package/dist/portable-collection-DZd2bm7M.cjs +686 -0
  144. package/dist/portable-key-BIMLrAP4.mjs +549 -0
  145. package/dist/portable-key-id-Ca30-hOa.mjs +248 -0
  146. package/dist/proof-Dxy6ByqI.mjs +1299 -0
  147. package/dist/{public-audience-Cr5MsnMq.mjs → public-audience--klBIOk1.mjs} +15 -10
  148. package/dist/router-u5O5KCQr.mjs +156 -0
  149. package/dist/runtime/mod.cjs +1 -1
  150. package/dist/runtime/mod.js +1 -1
  151. package/dist/secured-document-CxzZZ9nL.mjs +35 -0
  152. package/dist/send-C4dDpAxm.mjs +495 -0
  153. package/dist/sig/accept.test.mjs +1 -1
  154. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  155. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  156. package/dist/sig/compound-proof-producer.test.d.mts +2 -0
  157. package/dist/sig/compound-proof-producer.test.mjs +107 -0
  158. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  159. package/dist/sig/compound-proof-verification.test.mjs +833 -0
  160. package/dist/sig/compound-proof.test.d.mts +2 -0
  161. package/dist/sig/compound-proof.test.mjs +411 -0
  162. package/dist/sig/http.test.mjs +702 -31
  163. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  164. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  165. package/dist/sig/key.test.mjs +220 -8
  166. package/dist/sig/ld.test.mjs +65 -7
  167. package/dist/sig/mitra-receive-interop.test.d.mts +2 -0
  168. package/dist/sig/mitra-receive-interop.test.mjs +260 -0
  169. package/dist/sig/mitra-send-interop.test.d.mts +2 -0
  170. package/dist/sig/mitra-send-interop.test.mjs +461 -0
  171. package/dist/sig/mod.cjs +18 -16
  172. package/dist/sig/mod.d.cts +4 -4
  173. package/dist/sig/mod.d.ts +4 -4
  174. package/dist/sig/mod.js +3 -3
  175. package/dist/sig/owner.test.mjs +108 -9
  176. package/dist/sig/portable-collection.test.d.mts +2 -0
  177. package/dist/sig/portable-collection.test.mjs +697 -0
  178. package/dist/sig/portable-interop.test.d.mts +2 -0
  179. package/dist/sig/portable-interop.test.mjs +156 -0
  180. package/dist/sig/portable-key-id.test.d.mts +2 -0
  181. package/dist/sig/portable-key-id.test.mjs +67 -0
  182. package/dist/sig/portable-key.test.d.mts +2 -0
  183. package/dist/sig/portable-key.test.mjs +1439 -0
  184. package/dist/sig/proof.test.mjs +1753 -16
  185. package/dist/sig/tootik-request-interop.test.d.mts +2 -0
  186. package/dist/sig/tootik-request-interop.test.mjs +190 -0
  187. package/dist/sig/tootik-send-interop.test.d.mts +2 -0
  188. package/dist/sig/tootik-send-interop.test.mjs +331 -0
  189. package/dist/sig/verification.test.d.mts +2 -0
  190. package/dist/sig/verification.test.mjs +310 -0
  191. package/dist/std__assert-DvMDRPes.mjs +8 -0
  192. package/dist/{testing-CO7ftO8A.mjs → tasks-IG3pHfvZ.mjs} +2 -2
  193. package/dist/{temporal-fsXO5IvD.mjs → temporal-D0KJI4NF.mjs} +3 -3
  194. package/dist/testing/context.test.d.mts +2 -0
  195. package/dist/testing/context.test.mjs +19 -0
  196. package/dist/testing/kv.test.d.mts +2 -0
  197. package/dist/testing/kv.test.mjs +101 -0
  198. package/dist/testing/mod.d.mts +1617 -48
  199. package/dist/testing/mod.mjs +6 -3
  200. package/dist/testing-t8xDeJZ5.mjs +8 -0
  201. package/dist/{transformers-DGwl-hD1.cjs → transformers-BalCrSsr.cjs} +0 -1
  202. package/dist/{types-DC1pNgJA.js → types-_S2_MeLF.js} +144 -8
  203. package/dist/{types-CPym83zc.cjs → types-poIao40f.cjs} +160 -7
  204. package/dist/utils/docloader.test.mjs +530 -8
  205. package/dist/utils/kv-cache.test.mjs +2 -2
  206. package/dist/utils/mod.cjs +1 -1
  207. package/dist/utils/mod.d.cts +1 -1
  208. package/dist/utils/mod.d.ts +1 -1
  209. package/dist/utils/mod.js +1 -1
  210. package/dist/verification-C3954hQh.mjs +5 -0
  211. package/dist/verification-Dpfcw8ml.mjs +105 -0
  212. package/dist/vocab/cjs.test.mjs +1 -1
  213. package/package.json +8 -8
  214. package/dist/assert_rejects-EgstcQy5.mjs +0 -82
  215. package/dist/docloader-e1khNUKy.mjs +0 -49
  216. package/dist/http-CsmQ-BQ4.js +0 -2483
  217. package/dist/http-VyDTd4G3.d.cts +0 -553
  218. package/dist/http-hlIjmewS.cjs +0 -2694
  219. package/dist/http-lf8Hsd91.d.ts +0 -553
  220. package/dist/key-DfPsX8hv.mjs +0 -453
  221. package/dist/keycache-_DHqz5z_.mjs +0 -97
  222. package/dist/metrics-CoUJLQhZ.d.cts +0 -276
  223. package/dist/metrics-Dc4jR-IC.d.ts +0 -276
  224. package/dist/mod-B0hW12_O.d.cts +0 -307
  225. package/dist/mod-COIAjwRS.d.ts +0 -307
  226. package/dist/owner-Br9YYzn_.mjs +0 -120
  227. package/dist/proof-B4ngoaNQ.mjs +0 -316
  228. package/dist/proof-B6E0XUXJ.js +0 -1415
  229. package/dist/proof-NN4xCQGL.cjs +0 -1562
  230. package/dist/send-CxHKUNzv.mjs +0 -239
  231. package/dist/std__assert-B2NnY9bq.mjs +0 -79
  232. package/dist/temporal-polyfill-BCdTHexd.cjs +0 -3565
  233. /package/dist/{accept-8PiolDP7.mjs → accept-CPVqki78.mjs} +0 -0
  234. /package/dist/{activity-listener-BtTSxZWA.mjs → activity-listener-C-BSbKI7.mjs} +0 -0
  235. /package/dist/{client-CAM_bQXx.d.cts → client-D-XP_Ccb.d.cts} +0 -0
  236. /package/dist/{client-CSddvgWN.d.ts → client-D-XP_Ccb.d.ts} +0 -0
  237. /package/dist/{keys-Dbyd7bhl.mjs → keys-DIJNHW-Y.mjs} +0 -0
  238. /package/dist/{kv-CXBAok3k.mjs → kv-DCHkaJ9-.mjs} +0 -0
  239. /package/dist/{negotiation-RuwrPFqi.mjs → negotiation-CCocWT_N.mjs} +0 -0
  240. /package/dist/{retry-DgFqeS5k.mjs → retry-zX5xw5e0.mjs} +0 -0
  241. /package/dist/{chunk-D5IdezsZ.js → rolldown-runtime-BC-Eo5Mj.js} +0 -0
  242. /package/dist/{chunk-Czpeue4M.cjs → rolldown-runtime-Dmm3t92W.cjs} +0 -0
  243. /package/dist/{transformers-DXze6FUB.js → transformers-DAtXl_Kc.js} +0 -0
  244. /package/dist/{types-CrtdVuDP.mjs → types-DE_LV1JB.mjs} +0 -0
@@ -1,15 +1,113 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { o as JsonValue, s as NodeInfo, t as GetNodeInfoOptions } from "./client-CAM_bQXx.cjs";
3
- import { o as VerifyRequestFailureReason, t as HttpMessageSignaturesSpec } from "./http-VyDTd4G3.cjs";
4
- import { n as GetKeyOwnerOptions } from "./owner-DEvZuyOE.cjs";
5
- import { n as KvStore, t as KvKey } from "./kv-gJ8LYbxX.cjs";
6
- import { i as MessageQueue } from "./metrics-CoUJLQhZ.cjs";
2
+ import { o as JsonValue, s as NodeInfo, t as GetNodeInfoOptions } from "./client-D-XP_Ccb.cjs";
3
+ import { _ as InboxVerificationKey, d as InboxProofPolicyFailureReason, h as InboxVerificationAttempt, w as VerifyRequestFailureReason, y as HttpMessageSignaturesSpec } from "./key-DYxuyd-s.cjs";
4
+ import { n as GetKeyOwnerOptions } from "./owner-BF0L9cMt.cjs";
5
+ import { n as KvStore, t as KvKey } from "./kv-B2mzK5tl.cjs";
7
6
  import { Activity, Actor, Collection, CryptographicKey, Hashtag, Link, LookupObjectOptions, Multikey, Object as Object$1, Recipient, Tombstone, TraverseCollectionOptions } from "@fedify/vocab";
8
- import { AuthenticatedDocumentLoaderFactory, DocumentLoader, DocumentLoaderFactory, GetUserAgentOptions } from "@fedify/vocab-runtime";
7
+ import { AuthenticatedDocumentLoaderFactory, DocumentLoader, DocumentLoaderFactory, GetUserAgentOptions, PortableObjectVerifier } from "@fedify/vocab-runtime";
9
8
  import { Link as Link$1, LookupWebFingerOptions, ResourceDescriptor } from "@fedify/webfinger";
10
9
  import { MeterProvider, Span, Tracer, TracerProvider } from "@opentelemetry/api";
11
10
  import { StandardSchemaV1 } from "@standard-schema/spec";
12
11
 
12
+ //#region src/federation/inbox-report.d.ts
13
+ /**
14
+ * A JSON value retained from the incoming request.
15
+ * @since 2.4.0
16
+ */
17
+ type InboxJsonValue = null | boolean | number | string | readonly InboxJsonValue[] | {
18
+ readonly [key: string]: InboxJsonValue;
19
+ };
20
+ /**
21
+ * The final inbox authentication decision.
22
+ * @since 2.4.0
23
+ */
24
+ type InboxAuthentication = {
25
+ readonly status: "verified"; /** Direct references to the attempts that authenticated this delivery. */
26
+ readonly attempts: readonly Extract<InboxVerificationAttempt, {
27
+ status: "verified";
28
+ }>[];
29
+ } | {
30
+ readonly status: "rejected";
31
+ readonly reason: {
32
+ readonly type: "verificationFailed";
33
+ } | {
34
+ readonly type: "actorKeyMismatch";
35
+ readonly key: InboxVerificationKey;
36
+ readonly actorIds: readonly URL[];
37
+ } | {
38
+ readonly type: "proofPolicy";
39
+ readonly policy: "portableActor" | "portableActivity" | "compound";
40
+ readonly detail?: InboxProofPolicyFailureReason;
41
+ } | {
42
+ readonly type: "invalidNonce";
43
+ };
44
+ } | {
45
+ readonly status: "skipped";
46
+ } | {
47
+ readonly status: "notDetermined";
48
+ };
49
+ /**
50
+ * How an inbox request finished.
51
+ * @since 2.4.0
52
+ */
53
+ type InboxRequestOutcome = {
54
+ readonly type: "response";
55
+ readonly status: number;
56
+ readonly disposition: "processed" | "enqueued" | "duplicate" | "unhandled" | "customResponse";
57
+ } | {
58
+ readonly type: "response";
59
+ readonly status: number;
60
+ readonly disposition: "rejected";
61
+ readonly reason: "recipientNotFound" | "invalidJson" | "invalidJsonLd" | "invalidActivity" | "bodyTooLarge" | "missingActor" | "authentication";
62
+ } | {
63
+ readonly type: "response";
64
+ readonly status: number;
65
+ readonly disposition: "failed";
66
+ readonly reason: "bodyUnavailable" | "enqueueError" | "listenerError";
67
+ readonly error?: unknown;
68
+ } | {
69
+ readonly type: "exception";
70
+ readonly stage: "prepare" | "parse" | "verify" | "policy" | "dispatch" | "respond"; /** The original thrown value, including null/undefined. */
71
+ readonly error: unknown;
72
+ };
73
+ /**
74
+ * Observations of a single inbox delivery request.
75
+ * @since 2.4.0
76
+ */
77
+ interface InboxRequestReport {
78
+ /** The delivery route, including a portable gateway route. */
79
+ readonly inbox: {
80
+ readonly kind: "personal" | "shared" | "portable";
81
+ readonly recipient: string | null;
82
+ };
83
+ /** Unavailable differs from a successfully parsed JSON null. */
84
+ readonly payload: {
85
+ readonly status: "unavailable";
86
+ } | {
87
+ readonly status: "parsed";
88
+ readonly value: InboxJsonValue;
89
+ };
90
+ /** The Activity obtained by the normal processing flow, if any. */
91
+ readonly activity: Activity | null;
92
+ /** Logical evaluations, including unsuccessful fallback paths. */
93
+ readonly attempts: readonly InboxVerificationAttempt[];
94
+ /** Cryptographic success alone does not imply this decision is verified. */
95
+ readonly authentication: InboxAuthentication;
96
+ /** Response status snapshot or the original exception. */
97
+ readonly outcome: InboxRequestOutcome;
98
+ }
99
+ /**
100
+ * Observes an inbox delivery after processing, before fetch resolves/rethrows.
101
+ * The callback is awaited. Its errors are logged and swallowed, preserving
102
+ * the original response/exception. The last registered callback replaces the
103
+ * previous one. It excludes inbox collection GETs, unmatched routes,
104
+ * programmatic routing, and queue workers. This is not an atomic persistence
105
+ * guarantee. Keys/owner/controller declarations remain untrusted unless the
106
+ * final authentication decision verifies them.
107
+ * @since 2.4.0
108
+ */
109
+ type InboxRequestFinishedHandler<TContextData> = (context: RequestContext<TContextData>, report: InboxRequestReport) => void | Promise<void>;
110
+ //#endregion
13
111
  //#region src/compat/types.d.ts
14
112
  /**
15
113
  * A function that transforms an activity object.
@@ -143,6 +241,25 @@ type ActorKeyPairsDispatcher<TContextData> = (context: Context<TContextData>, id
143
241
  */
144
242
  type ActorHandleMapper<TContextData> = (context: Context<TContextData>, username: string) => string | null | Promise<string | null>;
145
243
  /**
244
+ * A callback that maps an actor's internal identifier to the ID of the
245
+ * [FEP-ef61] portable actor it dispatches, or `null` if the actor is not
246
+ * portable.
247
+ *
248
+ * The returned ID is an `ap:` or `ap+ef61:` URI, e.g.,
249
+ * `ap+ef61://did:key:z6Mk.../actors/alice`, or its compatible identifier.
250
+ * It must be the same ID that the actor dispatcher puts in the actor's `id`,
251
+ * and must not have a fragment.
252
+ *
253
+ * [FEP-ef61]: https://w3id.org/fep/ef61
254
+ *
255
+ * @template TContextData The context data to pass to the {@link Context}.
256
+ * @param context The context.
257
+ * @param identifier The actor's internal identifier.
258
+ * @returns The portable actor's ID, or `null` if the actor is not portable.
259
+ * @since 2.4.0
260
+ */
261
+ type PortableActorIdMapper<TContextData> = (context: Context<TContextData>, identifier: string) => URL | null | Promise<URL | null>;
262
+ /**
146
263
  * A callback that maps a WebFinger query to the corresponding actor's
147
264
  * internal identifier or username, or `null` if the query is not found.
148
265
  * @template TContextData The context data to pass to the {@link Context}.
@@ -162,14 +279,18 @@ type ActorAliasMapper<TContextData> = (context: RequestContext<TContextData>, re
162
279
  username: string;
163
280
  } | null>;
164
281
  /**
165
- * A callback that dispatches an object.
282
+ * A callback that dispatches an object or a {@link Tombstone}.
283
+ *
284
+ * Return a {@link Tombstone} if the object has been deleted; Fedify then
285
+ * responds with `410 Gone` and the serialized tombstone. Return `null` if
286
+ * the object is not found.
166
287
  *
167
288
  * @template TContextData The context data to pass to the {@link Context}.
168
289
  * @template TObject The type of object to dispatch.
169
290
  * @template TParam The parameter names of the requested URL.
170
291
  * @since 0.7.0
171
292
  */
172
- type ObjectDispatcher<TContextData, TObject extends Object$1, TParam extends string> = (context: RequestContext<TContextData>, values: Record<TParam, string>) => TObject | null | Promise<TObject | null>;
293
+ type ObjectDispatcher<TContextData, TObject extends Object$1, TParam extends string> = (context: RequestContext<TContextData>, values: Record<TParam, string>) => TObject | Tombstone | null | Promise<TObject | Tombstone | null>;
173
294
  /**
174
295
  * A callback that dispatches a collection.
175
296
  *
@@ -258,6 +379,60 @@ type OutboxListener<TContextData, TActivity extends Activity> = (context: Outbox
258
379
  */
259
380
  type MediaUploaderCallback<TContextData> = (context: RequestContext<TContextData>, identifier: string, file: File, object: Object$1) => Object$1 | URL | Promise<Object$1 | URL>;
260
381
  /**
382
+ * A request for a resource addressed by a hashlink, which an
383
+ * [FEP-ef61](https://w3id.org/fep/ef61) gateway serves at
384
+ * `/.well-known/apgateway/hl:<digestMultibase>`.
385
+ *
386
+ * Fedify validates the hashlink before creating this object, so the digest is
387
+ * always a well-formed SHA-256 multihash.
388
+ *
389
+ * @since 2.4.0
390
+ */
391
+ interface HashlinkMediaRequest {
392
+ /**
393
+ * The requested hashlink, i.e., `hl:` followed by
394
+ * {@link HashlinkMediaRequest.digestMultibase}, after percent-decoding and
395
+ * with its scheme lowercased.
396
+ */
397
+ readonly hashlink: `hl:${string}`;
398
+ /**
399
+ * The multibase-encoded multihash as requested, which is the value that
400
+ * publishers put in the `digestMultibase` property. The same digest can be
401
+ * encoded in several multibase encodings; use
402
+ * {@link HashlinkMediaRequest.digest} as a storage key to find a resource
403
+ * regardless of the encoding.
404
+ */
405
+ readonly digestMultibase: string;
406
+ /** The hash algorithm of the digest. */
407
+ readonly algorithm: "sha2-256";
408
+ /** The raw 32-byte SHA-256 digest of the resource. */
409
+ readonly digest: Uint8Array;
410
+ /**
411
+ * The multihash decoded from
412
+ * {@link HashlinkMediaRequest.digestMultibase}, i.e., the hash algorithm
413
+ * code and the digest length followed by the digest.
414
+ */
415
+ readonly multihash: Uint8Array;
416
+ }
417
+ /**
418
+ * A callback that serves a resource addressed by a hashlink through the
419
+ * [FEP-ef61](https://w3id.org/fep/ef61) gateway endpoint.
420
+ *
421
+ * The returned response is sent as is, so the callback can stream its body
422
+ * and set headers such as `Content-Type` and `Cache-Control`. Fedify does not
423
+ * verify the response body against the digest, so the complete
424
+ * representation must be the exact bytes that hash to the requested digest.
425
+ *
426
+ * @template TContextData The context data to pass to the {@link Context}.
427
+ * @param context The request context.
428
+ * @param media The requested hashlink and its digest.
429
+ * @returns The response to send, or `null` if the resource is not stored on
430
+ * this server, which results in `404 Not Found`. It may be returned
431
+ * synchronously or wrapped in a `Promise`.
432
+ * @since 2.4.0
433
+ */
434
+ type HashlinkMediaDispatcher<TContextData> = (context: RequestContext<TContextData>, media: HashlinkMediaRequest) => Response | null | Promise<Response | null>;
435
+ /**
261
436
  * The reason why an incoming activity could not be verified.
262
437
  *
263
438
  * Unlike inbox listeners registered through {@link InboxListenerSetters.on},
@@ -412,6 +587,28 @@ type ObjectAuthorizePredicate<TContextData, TParam extends string> = (context: R
412
587
  */
413
588
  type CustomCollectionDispatcher<TItem, TParam extends string, TContext extends Context<TContextData>, TContextData> = (context: TContext, values: Record<TParam, string>, cursor: string | null) => PageItems<TItem> | null | Promise<PageItems<TItem> | null>;
414
589
  /**
590
+ * A callback that maps a custom collection to the identifier of the actor
591
+ * that owns it, so that the collection can be served as an [FEP-ef61]
592
+ * portable collection through the gateway endpoint, e.g.,
593
+ * `GET /.well-known/apgateway/did:key:z6Mk.../users/alice/bookmarks`.
594
+ *
595
+ * Fedify serves such a request only if the returned actor is a portable actor
596
+ * whose ID is under the requested DID. The owner has to come from
597
+ * the application's data, not from the request, since the DID in the request
598
+ * path is not evidence that this server hosts collections for it.
599
+ *
600
+ * [FEP-ef61]: https://w3id.org/fep/ef61
601
+ *
602
+ * @template TContextData The context data to pass to the {@link Context}.
603
+ * @template TParam The parameter names of the requested URL.
604
+ * @param context The context.
605
+ * @param values The parameters of the requested URL.
606
+ * @returns The internal identifier of the actor that owns the collection, or
607
+ * `null` if the collection is not a portable collection.
608
+ * @since 2.4.0
609
+ */
610
+ type PortableCollectionOwnerMapper<TContextData, TParam extends string> = (context: Context<TContextData>, values: Record<TParam, string>) => string | null | Promise<string | null>;
611
+ /**
415
612
  * A callback that counts the number of items in a custom collection.
416
613
  *
417
614
  * @template TParams The parameter names of the requested URL.
@@ -507,6 +704,17 @@ type CircuitBreakerOptions = CircuitBreakerFailurePolicy & {
507
704
  */
508
705
  readonly releaseInterval?: Temporal.Duration | Temporal.DurationLike;
509
706
  /**
707
+ * How long Fedify keeps circuit breaker state in the configured key-value
708
+ * store.
709
+ *
710
+ * When omitted, Fedify derives this from `failureWindow`, `recoveryDelay`, and
711
+ * `heldActivityTtl` for the default numeric failure policy. Custom `failure`
712
+ * callbacks do not have an inspectable time window, so their state expires
713
+ * after `recoveryDelay` plus `heldActivityTtl` unless this option overrides
714
+ * it.
715
+ */
716
+ readonly stateTtl?: Temporal.Duration | Temporal.DurationLike;
717
+ /**
510
718
  * Called whenever the circuit state changes.
511
719
  */
512
720
  readonly onStateChange?: (remoteHost: string, previousState: CircuitBreakerState, newState: CircuitBreakerState) => void | Promise<void>;
@@ -525,6 +733,7 @@ interface NormalizedCircuitBreakerOptions {
525
733
  readonly recoveryDelay: Temporal.Duration;
526
734
  readonly heldActivityTtl: Temporal.Duration;
527
735
  readonly releaseInterval: Temporal.Duration;
736
+ readonly stateTtl: Temporal.Duration | undefined;
528
737
  readonly onStateChange?: CircuitBreakerOptions["onStateChange"];
529
738
  readonly onActivityDrop?: CircuitBreakerOptions["onActivityDrop"];
530
739
  }
@@ -585,6 +794,11 @@ declare class CircuitBreaker {
585
794
  recordFailure(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>;
586
795
  dropActivity(remoteHost: string, details: CircuitBreakerActivityDrop): Promise<void>;
587
796
  getState(remoteHost: string): Promise<CircuitBreakerKvState | undefined>;
797
+ /**
798
+ * The currently running background legacy sweep, if any.
799
+ * @internal
800
+ */
801
+ get pendingSweep(): Promise<void> | undefined;
588
802
  }
589
803
  /**
590
804
  * Normalizes user-provided circuit breaker options into the internal policy
@@ -593,7 +807,8 @@ declare class CircuitBreaker {
593
807
  * @param options The public circuit breaker options supplied to Fedify.
594
808
  * @returns The normalized failure predicate, failure pruning function,
595
809
  * duration values, and optional callbacks with defaults applied.
596
- * @throws {RangeError} If any configured duration is not positive.
810
+ * @throws {RangeError} If any configured duration is not positive, or if
811
+ * `stateTtl` is shorter than `recoveryDelay`.
597
812
  * @throws {TypeError} If `failureThreshold` is not a positive integer.
598
813
  */
599
814
  declare function normalizeCircuitBreakerOptions(options: CircuitBreakerOptions): NormalizedCircuitBreakerOptions;
@@ -606,6 +821,264 @@ declare function normalizeCircuitBreakerOptions(options: CircuitBreakerOptions):
606
821
  */
607
822
  declare function parseCircuitBreakerKvState(value: unknown): CircuitBreakerKvState | undefined;
608
823
  //#endregion
824
+ //#region src/federation/mq.d.ts
825
+ /**
826
+ * Additional options for enqueuing a message in a queue.
827
+ *
828
+ * @since 0.5.0
829
+ */
830
+ interface MessageQueueEnqueueOptions {
831
+ /**
832
+ * The delay before the message is enqueued. No delay by default.
833
+ *
834
+ * It must not be negative.
835
+ */
836
+ readonly delay?: Temporal.Duration;
837
+ /**
838
+ * An optional key that ensures messages with the same ordering key are
839
+ * processed sequentially (one at a time). Messages with different ordering
840
+ * keys (or no ordering key) may be processed in parallel.
841
+ *
842
+ * This is useful for ensuring that related messages are processed in order,
843
+ * such as ensuring that a `Delete` activity is processed after a `Create`
844
+ * activity for the same object.
845
+ *
846
+ * @since 2.0.0
847
+ */
848
+ readonly orderingKey?: string;
849
+ /**
850
+ * An optional key requesting at-most-once enqueue semantics for messages
851
+ * that share it. A backend that declares
852
+ * {@link MessageQueue.nativeDeduplication} `true` owns the check: a message
853
+ * whose `deduplicationKey` was already seen within the backend's
854
+ * deduplication window is dropped instead of enqueued. Backends without
855
+ * native deduplication ignore this field; Fedify performs its own
856
+ * best-effort deduplication before reaching them on the paths that support
857
+ * it.
858
+ *
859
+ * @since 2.4.0
860
+ */
861
+ readonly deduplicationKey?: string;
862
+ }
863
+ /**
864
+ * Additional options for listening to a message queue.
865
+ *
866
+ * @since 1.0.0
867
+ */
868
+ interface MessageQueueListenOptions {
869
+ /**
870
+ * The signal to abort listening to the message queue.
871
+ */
872
+ signal?: AbortSignal;
873
+ }
874
+ /**
875
+ * The number of messages waiting in a message queue.
876
+ *
877
+ * @since 2.3.0
878
+ */
879
+ interface MessageQueueDepth {
880
+ /**
881
+ * The total number of messages still waiting in the backend queue.
882
+ *
883
+ * This does not include messages that have already been handed to a worker
884
+ * for processing.
885
+ */
886
+ readonly queued: number;
887
+ /**
888
+ * The number of queued messages eligible for immediate processing.
889
+ *
890
+ * Queue backends that cannot cheaply distinguish ready and delayed messages
891
+ * may omit this field.
892
+ */
893
+ readonly ready?: number;
894
+ /**
895
+ * The number of queued messages scheduled for later delivery.
896
+ *
897
+ * Queue backends that cannot cheaply distinguish ready and delayed messages
898
+ * may omit this field.
899
+ */
900
+ readonly delayed?: number;
901
+ }
902
+ /**
903
+ * An abstract interface for a message queue.
904
+ *
905
+ * @since 0.5.0
906
+ */
907
+ interface MessageQueue {
908
+ /**
909
+ * Whether the message queue backend provides native retry mechanisms.
910
+ * When `true`, Fedify will skip its own retry logic and rely on the backend
911
+ * to handle retries. When `false` or omitted, Fedify will handle retries
912
+ * using its own retry policies.
913
+ *
914
+ * @default `false`
915
+ * @since 1.7.0
916
+ */
917
+ readonly nativeRetrial?: boolean;
918
+ /**
919
+ * Whether the message queue backend deduplicates messages that share a
920
+ * {@link MessageQueueEnqueueOptions.deduplicationKey} natively. When `true`,
921
+ * Fedify forwards the `deduplicationKey` and relies on the backend to drop
922
+ * duplicates; when `false` or omitted, Fedify applies its own best-effort
923
+ * key–value deduplication on the paths that request it.
924
+ *
925
+ * @default `false`
926
+ * @since 2.4.0
927
+ */
928
+ readonly nativeDeduplication?: boolean;
929
+ /**
930
+ * Whether {@link enqueueMany} accepts either every message or no messages.
931
+ * Backends that implement `enqueueMany()` by sending messages individually
932
+ * must set this to `false`, so Fedify does not use that method for a batch
933
+ * governed by one `deduplicationKey`. `true` by default when `enqueueMany`
934
+ * is implemented.
935
+ *
936
+ * @default `true`
937
+ * @since 2.4.0
938
+ */
939
+ readonly atomicEnqueueMany?: boolean;
940
+ /**
941
+ * Enqueues a message in the queue.
942
+ * @param message The message to enqueue.
943
+ * @param options Additional options for enqueuing the message.
944
+ */
945
+ enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
946
+ /**
947
+ * Enqueues multiple messages in the queue. This operation is optional,
948
+ * and may not be supported by all implementations. If not supported,
949
+ * Fedify will invoke {@link enqueue} for each message. An implementation
950
+ * that may accept only part of a batch before rejecting must declare
951
+ * {@link atomicEnqueueMany} `false`.
952
+ *
953
+ * @param messages The messages to enqueue.
954
+ * @param options Additional options for enqueuing the messages.
955
+ */
956
+ enqueueMany?: (messages: readonly any[], options?: MessageQueueEnqueueOptions) => Promise<void>;
957
+ /**
958
+ * Listens for messages in the queue.
959
+ * @param handler The handler for messages in the queue.
960
+ * @param options Additional options for listening to the message queue.
961
+ * @returns A promise that resolves when the listening is done. It never
962
+ * rejects, and is resolved when the signal is aborted. If no
963
+ * signal is provided, it never resolves.
964
+ */
965
+ listen(handler: (message: any) => Promise<void> | void, options?: MessageQueueListenOptions): Promise<void>;
966
+ /**
967
+ * Gets the number of messages waiting in the queue.
968
+ *
969
+ * This operation is optional, and may not be supported by all
970
+ * implementations. The returned counts exclude messages currently being
971
+ * handled by a worker.
972
+ *
973
+ * @since 2.3.0
974
+ */
975
+ getDepth?(): Promise<MessageQueueDepth>;
976
+ }
977
+ /**
978
+ * Additional options for {@link InProcessMessageQueue}.
979
+ * @since 1.0.0
980
+ */
981
+ interface InProcessMessageQueueOptions {
982
+ /**
983
+ * The interval to poll for messages in the queue. 5 seconds by default.
984
+ * @default `{ seconds: 5 }`
985
+ */
986
+ pollInterval?: Temporal.Duration | Temporal.DurationLike;
987
+ }
988
+ /**
989
+ * A message queue that processes messages in the same process.
990
+ * Do not use this in production as it does neither persist messages nor
991
+ * distribute them across multiple processes.
992
+ *
993
+ * @since 0.5.0
994
+ */
995
+ declare class InProcessMessageQueue implements MessageQueue {
996
+ #private;
997
+ /**
998
+ * In-process message queue does not provide native retry mechanisms.
999
+ * @since 1.7.0
1000
+ */
1001
+ readonly nativeRetrial = false;
1002
+ /**
1003
+ * In-process message queue does not deduplicate messages natively.
1004
+ * @since 2.4.0
1005
+ */
1006
+ readonly nativeDeduplication = false;
1007
+ /**
1008
+ * Constructs a new {@link InProcessMessageQueue} with the given options.
1009
+ * @param options Additional options for the in-process message queue.
1010
+ */
1011
+ constructor(options?: InProcessMessageQueueOptions);
1012
+ enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
1013
+ enqueueMany(messages: readonly any[], options?: MessageQueueEnqueueOptions): Promise<void>;
1014
+ listen(handler: (message: any) => Promise<void> | void, options?: MessageQueueListenOptions): Promise<void>;
1015
+ getDepth(): Promise<MessageQueueDepth>;
1016
+ }
1017
+ /**
1018
+ * A message queue that processes messages in parallel. It takes another
1019
+ * {@link MessageQueue}, and processes messages in parallel up to a certain
1020
+ * number of workers.
1021
+ *
1022
+ * Actually, it's rather a decorator than a queue itself.
1023
+ *
1024
+ * Note that the workers do not run in truly parallel, in the sense that they
1025
+ * are not running in separate threads or processes. They are running in the
1026
+ * same process, but are scheduled to run in parallel. Hence, this is useful
1027
+ * for I/O-bound tasks, but not for CPU-bound tasks, which is okay for Fedify's
1028
+ * workloads.
1029
+ *
1030
+ * When using `ParallelMessageQueue`, the ordering guarantee is preserved
1031
+ * *only if* the underlying queue implementation delivers messages in a wrapper
1032
+ * format that includes the `__fedify_ordering_key__` property. Currently,
1033
+ * only `DenoKvMessageQueue` and `WorkersMessageQueue` use this format.
1034
+ * For other queue implementations (e.g., `InProcessMessageQueue`,
1035
+ * `RedisMessageQueue`, `PostgresMessageQueue`, `SqliteMessageQueue`,
1036
+ * `AmqpMessageQueue`), the ordering key cannot be detected by
1037
+ * `ParallelMessageQueue`, so ordering guarantees are handled by those
1038
+ * implementations directly rather than at the `ParallelMessageQueue` level.
1039
+ *
1040
+ * Messages with the same ordering key will never be processed concurrently
1041
+ * by different workers, ensuring sequential processing within each key.
1042
+ * Messages with different ordering keys (or no ordering key) can still be
1043
+ * processed in parallel.
1044
+ *
1045
+ * @since 1.0.0
1046
+ */
1047
+ declare class ParallelMessageQueue implements MessageQueue {
1048
+ #private;
1049
+ readonly queue: MessageQueue;
1050
+ readonly workers: number;
1051
+ /**
1052
+ * Inherits the native retry capability from the wrapped queue.
1053
+ * @since 1.7.0
1054
+ */
1055
+ readonly nativeRetrial?: boolean;
1056
+ /**
1057
+ * Inherits the native deduplication capability from the wrapped queue.
1058
+ * @since 2.4.0
1059
+ */
1060
+ readonly nativeDeduplication?: boolean;
1061
+ /**
1062
+ * Inherits the atomic batch capability from the wrapped queue.
1063
+ * @since 2.4.0
1064
+ */
1065
+ readonly atomicEnqueueMany?: boolean;
1066
+ readonly getDepth?: () => Promise<MessageQueueDepth>;
1067
+ /**
1068
+ * Constructs a new {@link ParallelMessageQueue} with the given queue and
1069
+ * number of workers.
1070
+ * @param queue The message queue to use under the hood. Note that
1071
+ * {@link ParallelMessageQueue} cannot be nested.
1072
+ * @param workers The number of workers to process messages in parallel.
1073
+ * @throws {TypeError} If the given queue is an instance of
1074
+ * {@link ParallelMessageQueue}.
1075
+ */
1076
+ constructor(queue: MessageQueue, workers: number);
1077
+ enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
1078
+ enqueueMany(messages: readonly any[], options?: MessageQueueEnqueueOptions): Promise<void>;
1079
+ listen(handler: (message: any) => Promise<void> | void, options?: MessageQueueListenOptions): Promise<void>;
1080
+ }
1081
+ //#endregion
609
1082
  //#region src/federation/handler.d.ts
610
1083
  /**
611
1084
  * Options for the {@link respondWithObject} and
@@ -883,6 +1356,18 @@ interface FanoutMessage {
883
1356
  readonly inboxes: Readonly<Record<string, {
884
1357
  readonly actorIds: readonly string[];
885
1358
  readonly sharedInbox: boolean;
1359
+ /**
1360
+ * The canonical form of the FEP-ef61 portable inbox that the inbox
1361
+ * stands for.
1362
+ * @internal
1363
+ */
1364
+ readonly portableInbox?: string;
1365
+ /**
1366
+ * The compatible identifiers of the portable inbox on each gateway to
1367
+ * deliver through, in order.
1368
+ * @internal
1369
+ */
1370
+ readonly gatewayInboxes?: readonly string[];
886
1371
  }>>;
887
1372
  readonly activity: unknown;
888
1373
  readonly activityId?: string;
@@ -926,6 +1411,27 @@ interface OutboxMessage {
926
1411
  * @internal
927
1412
  */
928
1413
  readonly circuitHeldSince?: string;
1414
+ /**
1415
+ * The canonical form of the FEP-ef61 portable inbox that {@link inbox}, its
1416
+ * compatible identifier on a gateway, stands for.
1417
+ * @internal
1418
+ */
1419
+ readonly portableInbox?: string;
1420
+ /**
1421
+ * The compatible identifiers of the FEP-ef61 portable inbox on each gateway
1422
+ * that is still to be tried, in order. {@link inbox} is the first one.
1423
+ * If there is more than one, the activity is delivered through the first
1424
+ * gateway that accepts it.
1425
+ * @internal
1426
+ */
1427
+ readonly gatewayInboxes?: readonly string[];
1428
+ /**
1429
+ * The times before which each of {@link gatewayInboxes} must not be tried
1430
+ * again, as their responses' `Retry-After` headers requested, keyed by
1431
+ * the inbox URL, in ISO 8601.
1432
+ * @internal
1433
+ */
1434
+ readonly gatewayNotBefore?: Readonly<Record<string, string>>;
929
1435
  readonly traceContext: Readonly<Record<string, string>>;
930
1436
  }
931
1437
  /**
@@ -1074,6 +1580,16 @@ interface FederationKvPrefixes {
1074
1580
  * @since 2.4.0
1075
1581
  */
1076
1582
  readonly taskDeduplication: KvKey;
1583
+ /**
1584
+ * The key prefix used for remembering which activities received in
1585
+ * [FEP-ef61] portable inboxes have been forwarded to which gateways, so that
1586
+ * each activity is forwarded at most once.
1587
+ *
1588
+ * [FEP-ef61]: https://w3id.org/fep/ef61
1589
+ * @default `["_fedify", "portableInboxForwarding"]`
1590
+ * @since 2.4.0
1591
+ */
1592
+ readonly portableInboxForwarding: KvKey;
1077
1593
  }
1078
1594
  /**
1079
1595
  * Options for {@link FederationOptions.origin} when it is not a string.
@@ -1099,6 +1615,8 @@ interface FederationOrigin {
1099
1615
  * @returns A new {@link Federation} instance.
1100
1616
  * @throws {TypeError} If benchmark mode and `meterProvider` are both
1101
1617
  * specified.
1618
+ * @throws {RangeError} If {@link FederationOptions.maxHttpSignatures} is not
1619
+ * a positive integer or `Infinity`.
1102
1620
  * @since 0.10.0
1103
1621
  */
1104
1622
  declare function createFederation<TContextData>(options: FederationOptions<TContextData>): Federation<TContextData>;
@@ -1180,7 +1698,9 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1180
1698
  * based on URI Template
1181
1699
  * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
1182
1700
  * must have one or more variables.
1183
- * @param dispatcher An object dispatcher callback to register.
1701
+ * @param dispatcher An object dispatcher callback to register. It may
1702
+ * return an object, a `Tombstone` if the object has been
1703
+ * deleted, or `null` if the object is not found.
1184
1704
  */
1185
1705
  setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
1186
1706
  /**
@@ -1194,7 +1714,9 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1194
1714
  * based on URI Template
1195
1715
  * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
1196
1716
  * must have one or more variables.
1197
- * @param dispatcher An object dispatcher callback to register.
1717
+ * @param dispatcher An object dispatcher callback to register. It may
1718
+ * return an object, a `Tombstone` if the object has been
1719
+ * deleted, or `null` if the object is not found.
1198
1720
  */
1199
1721
  setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
1200
1722
  /**
@@ -1208,7 +1730,9 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1208
1730
  * based on URI Template
1209
1731
  * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
1210
1732
  * must have one or more variables.
1211
- * @param dispatcher An object dispatcher callback to register.
1733
+ * @param dispatcher An object dispatcher callback to register. It may
1734
+ * return an object, a `Tombstone` if the object has been
1735
+ * deleted, or `null` if the object is not found.
1212
1736
  */
1213
1737
  setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}{${TParam}}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
1214
1738
  /**
@@ -1222,7 +1746,9 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1222
1746
  * based on URI Template
1223
1747
  * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
1224
1748
  * must have one or more variables.
1225
- * @param dispatcher An object dispatcher callback to register.
1749
+ * @param dispatcher An object dispatcher callback to register. It may
1750
+ * return an object, a `Tombstone` if the object has been
1751
+ * deleted, or `null` if the object is not found.
1226
1752
  */
1227
1753
  setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}${Rfc6570Expression<TParam>}${string}${Rfc6570Expression<TParam>}${string}${Rfc6570Expression<TParam>}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
1228
1754
  /**
@@ -1236,7 +1762,9 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1236
1762
  * based on URI Template
1237
1763
  * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
1238
1764
  * must have one or more variables.
1239
- * @param dispatcher An object dispatcher callback to register.
1765
+ * @param dispatcher An object dispatcher callback to register. It may
1766
+ * return an object, a `Tombstone` if the object has been
1767
+ * deleted, or `null` if the object is not found.
1240
1768
  */
1241
1769
  setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}${Rfc6570Expression<TParam>}${string}${Rfc6570Expression<TParam>}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
1242
1770
  /**
@@ -1250,7 +1778,9 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1250
1778
  * based on URI Template
1251
1779
  * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). The path
1252
1780
  * must have one or more variables.
1253
- * @param dispatcher An object dispatcher callback to register.
1781
+ * @param dispatcher An object dispatcher callback to register. It may
1782
+ * return an object, a `Tombstone` if the object has been
1783
+ * deleted, or `null` if the object is not found.
1254
1784
  */
1255
1785
  setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: ConstructorWithTypeId<TObject>, path: `${string}${Rfc6570Expression<TParam>}${string}`, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
1256
1786
  /**
@@ -1358,6 +1888,53 @@ interface Federatable<TContextData> extends TaskRegistry<TContextData> {
1358
1888
  */
1359
1889
  setMediaUploader(path: `${string}${Rfc6570Expression<"identifier">}${string}`, callback: MediaUploaderCallback<TContextData>): MediaUploaderSetters<TContextData>;
1360
1890
  /**
1891
+ * Registers a dispatcher that serves resources addressed by hashlinks, such
1892
+ * as media attached to portable objects, through the
1893
+ * [FEP-ef61](https://w3id.org/fep/ef61) gateway endpoint, e.g.,
1894
+ * `GET /.well-known/apgateway/hl:zQmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n`.
1895
+ *
1896
+ * Fedify responds with `400 Bad Request` without calling the dispatcher if
1897
+ * the hashlink is malformed or its digest is not a SHA-256 multihash, and
1898
+ * with `404 Not Found` if the dispatcher returns `null`. Otherwise, the
1899
+ * response returned by the dispatcher is sent as is. Requests with methods
1900
+ * other than `GET` and `HEAD` get `405 Method Not Allowed`.
1901
+ *
1902
+ * Fedify does not verify the served bytes against the digest, as that would
1903
+ * require buffering the whole response body. The dispatcher must serve only
1904
+ * the resource whose complete representation hashes to the requested
1905
+ * digest, e.g., by using the digest as the storage key.
1906
+ *
1907
+ * This is not the upload API of the ActivityPub Media Upload extension,
1908
+ * which is registered through {@link Federatable.setMediaUploader}.
1909
+ *
1910
+ * @example
1911
+ * ``` typescript
1912
+ * federation.setHashlinkMediaDispatcher(async (ctx, media) => {
1913
+ * const file = await findPublicMedia(media.digest);
1914
+ * if (file == null) return null;
1915
+ * return new Response(
1916
+ * ctx.request.method === "HEAD" ? null : file.stream(),
1917
+ * {
1918
+ * headers: {
1919
+ * "Content-Type": file.mediaType,
1920
+ * "Content-Length": file.size.toString(),
1921
+ * "Cache-Control": "public, max-age=31536000, immutable",
1922
+ * "X-Content-Type-Options": "nosniff",
1923
+ * },
1924
+ * },
1925
+ * );
1926
+ * });
1927
+ * ```
1928
+ *
1929
+ * @param dispatcher A callback that returns the response serving the
1930
+ * requested resource, or `null` if it is not stored on
1931
+ * this server.
1932
+ * @throws {RouterError} Thrown if a hashlink media dispatcher is already
1933
+ * registered.
1934
+ * @since 2.4.0
1935
+ */
1936
+ setHashlinkMediaDispatcher(dispatcher: HashlinkMediaDispatcher<TContextData>): void;
1937
+ /**
1361
1938
  * Registers a following collection dispatcher.
1362
1939
  * @param path The URI path pattern for the following collection. The syntax
1363
1940
  * is based on URI Template
@@ -1633,6 +2210,47 @@ interface FederationBuilder<TContextData> extends Federatable<TContextData> {
1633
2210
  build(options: FederationOptions<TContextData>): Promise<Federation<TContextData>>;
1634
2211
  }
1635
2212
  /**
2213
+ * Options for forwarding activities received in [FEP-ef61] portable inboxes to
2214
+ * the other gateways of their actors. See
2215
+ * {@link FederationOptions.portableInboxForwarding}.
2216
+ *
2217
+ * [FEP-ef61]: https://w3id.org/fep/ef61
2218
+ * @since 2.4.0
2219
+ */
2220
+ interface PortableInboxForwardingOptions {
2221
+ /**
2222
+ * The maximum number of other gateways that a single delivery is forwarded
2223
+ * to. Gateways beyond it are skipped with a warning. `0` turns off
2224
+ * forwarding.
2225
+ * @default `10`
2226
+ */
2227
+ maxTargets?: number;
2228
+ /**
2229
+ * How long Fedify remembers that it has forwarded an activity from
2230
+ * a portable inbox to a gateway, under
2231
+ * {@link FederationKvPrefixes.portableInboxForwarding}. Within it, the same
2232
+ * activity is never forwarded to the same gateway again; once it expires,
2233
+ * a redelivery of the activity may be forwarded again. It cannot have
2234
+ * calendar units, i.e., weeks, months, or years.
2235
+ * @default `{ days: 30 }`
2236
+ */
2237
+ ttl?: Temporal.DurationLike;
2238
+ /**
2239
+ * How long a delivery waits for forwarding requests made immediately, i.e.,
2240
+ * when no outbox queue is configured, before Fedify responds to it.
2241
+ * Requests still running afterwards continue in the background. It also
2242
+ * bounds verifying the HTTP Signature that identifies the gateway which
2243
+ * forwarded the delivery, with or without an outbox queue; if the
2244
+ * verification does not finish in time, the activity is forwarded to that
2245
+ * gateway as well. It cannot have calendar units,
2246
+ * i.e., weeks, months, or years, and cannot be longer than
2247
+ * 2,147,483,647 milliseconds (about 24.8 days), the longest delay timers
2248
+ * support.
2249
+ * @default `{ seconds: 10 }`
2250
+ */
2251
+ deadline?: Temporal.DurationLike;
2252
+ }
2253
+ /**
1636
2254
  * Policy for emitting `Accept-Signature` challenges on inbox `401`
1637
2255
  * responses, as defined in
1638
2256
  * [RFC 9421 §5](https://www.rfc-editor.org/rfc/rfc9421#section-5).
@@ -1700,6 +2318,41 @@ interface FederationOptions<TContextData> {
1700
2318
  */
1701
2319
  kvPrefixes?: Partial<FederationKvPrefixes>;
1702
2320
  /**
2321
+ * The time-to-live for a remote actor's public key cached under
2322
+ * {@link FederationKvPrefixes.publicKey}. Once it expires, the next
2323
+ * signature verification that needs the key refetches it from the remote
2324
+ * server and caches it again.
2325
+ *
2326
+ * Shortening it bounds how long a revoked or rotated key stays in the cache,
2327
+ * at the cost of more requests to remote servers; refetching an expired key
2328
+ * fails while the peer is unavailable, so a very short value makes
2329
+ * verification depend on the peer being reachable.
2330
+ * @default `{ days: 30 }`
2331
+ * @since 2.4.0
2332
+ */
2333
+ publicKeyTtl?: Temporal.DurationLike;
2334
+ /**
2335
+ * The time-to-live for a remote origin's remembered HTTP Message Signatures
2336
+ * spec cached under {@link FederationKvPrefixes.httpMessageSignaturesSpec}.
2337
+ * Once it expires, the next delivery to that origin relearns the spec by
2338
+ * double-knocking and remembers it again.
2339
+ *
2340
+ * Shortening it makes Fedify notice a peer's spec upgrade sooner, at the
2341
+ * cost of an extra signed request per delivery whenever the first spec tried
2342
+ * is rejected.
2343
+ * @default `{ days: 90 }`
2344
+ * @since 2.4.0
2345
+ */
2346
+ httpMessageSignaturesSpecTtl?: Temporal.DurationLike;
2347
+ /**
2348
+ * Options for forwarding activities received in [FEP-ef61] portable inboxes
2349
+ * to the other gateways of their actors.
2350
+ *
2351
+ * [FEP-ef61]: https://w3id.org/fep/ef61
2352
+ * @since 2.4.0
2353
+ */
2354
+ portableInboxForwarding?: PortableInboxForwardingOptions;
2355
+ /**
1703
2356
  * The message queue for sending and receiving activities. If not provided,
1704
2357
  * activities will not be queued and will be processed immediately.
1705
2358
  *
@@ -1750,7 +2403,8 @@ interface FederationOptions<TContextData> {
1750
2403
  */
1751
2404
  authenticatedDocumentLoaderFactory?: AuthenticatedDocumentLoaderFactory;
1752
2405
  /**
1753
- * Whether to allow fetching private network addresses in the document loader.
2406
+ * Whether to allow private network addresses in the document loader and
2407
+ * outbound activity delivery, including redirects.
1754
2408
  *
1755
2409
  * If turned on, {@link FederationOptions.documentLoader},
1756
2410
  * {@link FederationOptions.contextLoader}, and
@@ -1787,6 +2441,35 @@ interface FederationOptions<TContextData> {
1787
2441
  */
1788
2442
  userAgent?: GetUserAgentOptions | string;
1789
2443
  /**
2444
+ * The timeout for each call of the built-in document loader, context
2445
+ * loader, and authenticated document loader, e.g., when Fedify fetches
2446
+ * a key to verify a signature. The timeout is shared by all the steps of
2447
+ * a call, including every redirect it follows, retries, and reading the
2448
+ * response body. It does not cover the time spent reading from or
2449
+ * writing to the cache.
2450
+ *
2451
+ * A timed-out call throws a `FetchError` without a response, whose
2452
+ * `cause` is a `DOMException` named `"TimeoutError"`, so that, e.g.,
2453
+ * a key fetch that times out is reported as a `keyFetchError` and cached
2454
+ * like other failures to fetch a key.
2455
+ *
2456
+ * It does not affect loaders made by
2457
+ * {@link FederationOptions.documentLoaderFactory},
2458
+ * {@link FederationOptions.contextLoaderFactory}, or
2459
+ * {@link FederationOptions.authenticatedDocumentLoaderFactory}.
2460
+ * Note that if only {@link FederationOptions.documentLoaderFactory} is
2461
+ * set, it also makes context loaders.
2462
+ *
2463
+ * Set it to `null` to turn off the timeout.
2464
+ *
2465
+ * 10 seconds by default.
2466
+ * @throws {RangeError} If the duration is not positive, is longer than
2467
+ * about 24.8 days, or is given in calendar units
2468
+ * such as months.
2469
+ * @since 2.4.0
2470
+ */
2471
+ documentLoaderTimeout?: Temporal.Duration | Temporal.DurationLike | null;
2472
+ /**
1790
2473
  * A callback that handles errors during outbox processing. Note that this
1791
2474
  * callback can be called multiple times for the same activity, because
1792
2475
  * the delivery is retried according to the backoff schedule until it
@@ -1815,6 +2498,29 @@ interface FederationOptions<TContextData> {
1815
2498
  */
1816
2499
  signatureTimeWindow?: Temporal.Duration | Temporal.DurationLike | false;
1817
2500
  /**
2501
+ * The maximum number of [RFC 9421] signatures of an incoming request to
2502
+ * verify, e.g., in the inbox and in
2503
+ * {@link RequestContext.getSignedKey}. A request can carry several
2504
+ * signatures, each of which may make Fedify fetch the key that it names,
2505
+ * so only the first ones in the order of the `Signature-Input` header are
2506
+ * verified, and the rest are ignored as if they were absent. Every
2507
+ * signature among the first ones counts, even if it fails before its key
2508
+ * is fetched. See also the `maxSignatures` option of `verifyRequest()`.
2509
+ *
2510
+ * It has to be a positive integer, or `Infinity` to verify every
2511
+ * signature, which lets a single request make Fedify fetch any number of
2512
+ * keys. Draft-cavage HTTP Signatures carry a single signature, so this
2513
+ * option does not affect them.
2514
+ *
2515
+ * Three by default.
2516
+ *
2517
+ * [RFC 9421]: https://www.rfc-editor.org/rfc/rfc9421
2518
+ * @throws {RangeError} Thrown when the federation is created if the value
2519
+ * is not a positive integer or `Infinity`.
2520
+ * @since 2.4.0
2521
+ */
2522
+ maxHttpSignatures?: number;
2523
+ /**
1818
2524
  * Whether to skip HTTP Signatures verification for incoming activities.
1819
2525
  * This is useful for testing purposes, but should not be used in production.
1820
2526
  *
@@ -1993,6 +2699,30 @@ interface ActorCallbackSetters<TContextData> {
1993
2699
  */
1994
2700
  mapAlias(mapper: ActorAliasMapper<TContextData>): ActorCallbackSetters<TContextData>;
1995
2701
  /**
2702
+ * Sets the callback function that maps an actor's identifier to the ID of
2703
+ * the [FEP-ef61] portable actor it dispatches. If the callback returns
2704
+ * a portable ID for an identifier, the key pairs of that actor are treated
2705
+ * as this server's *gateway keys* for the portable actor:
2706
+ * {@link Context.getActorKeyPairs} derives their key IDs from the actor's
2707
+ * compatible identifier on this server, e.g.,
2708
+ * `https://example.com/.well-known/apgateway/did:key:z6Mk.../actors/alice#main-key`,
2709
+ * and makes the portable actor their owner, so that requests this server
2710
+ * makes on behalf of the actor, such as activity deliveries and signed
2711
+ * fetches, are signed with them. Gateway keys are only used for HTTP
2712
+ * Signatures; they never make Object Integrity Proofs or Linked Data
2713
+ * Signatures.
2714
+ *
2715
+ * If it's omitted, or it returns `null`, the actor's keys are derived from
2716
+ * {@link Context.getActorUri} as usual.
2717
+ *
2718
+ * [FEP-ef61]: https://w3id.org/fep/ef61
2719
+ * @param mapper A callback that maps an actor's identifier to its portable
2720
+ * ID, or `null` if the actor is not portable.
2721
+ * @returns The setters object so that settings can be chained.
2722
+ * @since 2.4.0
2723
+ */
2724
+ mapPortableActorId(mapper: PortableActorIdMapper<TContextData>): ActorCallbackSetters<TContextData>;
2725
+ /**
1996
2726
  * Maps a fixed path to a sentinel identifier. It is useful for exposing
1997
2727
  * a single, instance-level actor at a fixed path, such as `/actor` for
1998
2728
  * a relay or `/bot` for a bot.
@@ -2157,6 +2887,16 @@ interface InboxListenerSetters<TContextData> {
2157
2887
  */
2158
2888
  onError(handler: InboxErrorHandler<TContextData>): InboxListenerSetters<TContextData>;
2159
2889
  /**
2890
+ * Observes each configured inbox delivery once, before fetch finishes.
2891
+ * The callback is awaited and its errors do not alter delivery processing.
2892
+ * Calling this again replaces the previous callback. Built federations
2893
+ * retain the callback registered at build time.
2894
+ * @param handler The request completion observer.
2895
+ * @returns This setter for chaining.
2896
+ * @since 2.4.0
2897
+ */
2898
+ onRequestFinished(handler: InboxRequestFinishedHandler<TContextData>): InboxListenerSetters<TContextData>;
2899
+ /**
2160
2900
  * Registers a callback for incoming activities whose HTTP signatures could
2161
2901
  * not be verified.
2162
2902
  *
@@ -2295,6 +3035,21 @@ interface CustomCollectionCallbackSetters<TParam extends string, TContext extend
2295
3035
  * @since 0.7.0
2296
3036
  */
2297
3037
  authorize(predicate: ObjectAuthorizePredicate<TContextData, string>): CustomCollectionCallbackSetters<TParam, TContext, TContextData>;
3038
+ /**
3039
+ * Maps the custom collection to the actor that owns it, so that it is also
3040
+ * served as an [FEP-ef61] portable collection through the gateway endpoint,
3041
+ * e.g., `GET /.well-known/apgateway/did:key:z6Mk.../users/alice/bookmarks`,
3042
+ * if the owner is a portable actor under the requested DID. Without it,
3043
+ * the custom collection is not served through the gateway endpoint.
3044
+ *
3045
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3046
+ * @param mapper A callback that returns the identifier of the actor that
3047
+ * owns the collection, or `null` if the collection is not
3048
+ * portable.
3049
+ * @returns The setters object so that settings can be chained.
3050
+ * @since 2.4.0
3051
+ */
3052
+ mapPortableOwner(mapper: PortableCollectionOwnerMapper<TContextData, TParam>): CustomCollectionCallbackSetters<TParam, TContext, TContextData>;
2298
3053
  }
2299
3054
  /**
2300
3055
  * Represents an object with a type ID, which is either a constructor or an
@@ -2391,6 +3146,28 @@ interface Context<TContextData> {
2391
3146
  */
2392
3147
  readonly contextLoader: DocumentLoader;
2393
3148
  /**
3149
+ * The [FEP-ef61] portable object policy that this context applies to
3150
+ * portable objects it dereferences. It is `verifyPortableObject()` with
3151
+ * this context's document loader, context loader, and tracer provider as
3152
+ * defaults, which the options passed to it override.
3153
+ *
3154
+ * Since its name is the same as the `verifyPortableObject` option of
3155
+ * property accessors, `lookupObject()`, and `traverseCollection()`, passing
3156
+ * a context as their options applies the policy, e.g.,
3157
+ * `await create.getObject(ctx)`. Objects parsed with a context as options,
3158
+ * such as activities that inboxes receive, and objects that accessors
3159
+ * fetch with a context as options also use it by default for their
3160
+ * property accessors. It never verifies an object by itself being
3161
+ * there: it only applies to objects that are dereferenced.
3162
+ *
3163
+ * It is optional only so that custom implementations of this interface
3164
+ * keep working; contexts that Fedify creates always have it.
3165
+ *
3166
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3167
+ * @since 2.4.0
3168
+ */
3169
+ readonly verifyPortableObject?: PortableObjectVerifier;
3170
+ /**
2394
3171
  * The federation object that this context belongs to.
2395
3172
  * @since 1.6.0
2396
3173
  */
@@ -2419,16 +3196,108 @@ interface Context<TContextData> {
2419
3196
  */
2420
3197
  getActorUri(identifier: string): URL;
2421
3198
  /**
2422
- * Builds the URI of an object with the given class and values.
2423
- * @param cls The class of the object.
2424
- * @param values The values to pass to the object dispatcher.
2425
- * @returns The object's URI.
3199
+ * Builds the [FEP-ef61] portable ID of an actor with the given identifier
3200
+ * under the given DID authority.
3201
+ *
3202
+ * The path is the same as the one {@link Context.getActorUri} builds, but
3203
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3204
+ * `ap+ef61://did:key:z6Mk.../users/alice`. Such an actor can be served
3205
+ * through the FEP-ef61 gateway endpoint,
3206
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice`, by the same actor
3207
+ * dispatcher.
3208
+ *
3209
+ * The returned `URL` keeps the DID authority percent-encoded, because
3210
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3211
+ * from `@fedify/vocab-runtime` to get the canonical string, e.g.,
3212
+ * `ap+ef61://did:key:z6Mk.../users/alice`.
3213
+ *
3214
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3215
+ *
3216
+ * @param identifier The actor's identifier.
3217
+ * @param authority The DID that controls the actor, e.g.,
3218
+ * `did:key:z6Mk...`. It must be a bare DID, without
3219
+ * a path, query, or fragment. A `did:key` DID must be
3220
+ * encoded in base58-btc, as FEP-ef61 requires; see
3221
+ * `exportDidKey()` from `@fedify/vocab-runtime`.
3222
+ * @returns The actor's portable ID.
3223
+ * @throws {RouterError} If no actor dispatcher is available.
3224
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3225
+ * DID that is not encoded in base58-btc.
3226
+ * @since 2.4.0
3227
+ */
3228
+ getPortableActorUri(identifier: string, authority: string): URL;
3229
+ /**
3230
+ * Builds the URI of an object with the given class and values.
3231
+ * @param cls The class of the object.
3232
+ * @param values The values to pass to the object dispatcher.
3233
+ * @returns The object's URI.
2426
3234
  * @throws {RouterError} If no object dispatcher is available for the class.
2427
3235
  * @throws {TypeError} If values are invalid.
2428
3236
  * @since 0.7.0
2429
3237
  */
2430
3238
  getObjectUri<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>): URL;
2431
3239
  /**
3240
+ * Builds the [FEP-ef61] portable ID of an object with the given class and
3241
+ * values under the given DID authority.
3242
+ *
3243
+ * The path is the same as the one {@link Context.getObjectUri} builds from
3244
+ * the object dispatcher's path, but the result is an `ap+ef61:` URI whose
3245
+ * authority is the DID, e.g., `ap+ef61://did:key:z6Mk.../notes/123`.
3246
+ * Such an object can be served through the FEP-ef61 gateway endpoint,
3247
+ * `/.well-known/apgateway/did:key:z6Mk.../notes/123`, by the same object
3248
+ * dispatcher.
3249
+ *
3250
+ * The returned `URL` keeps the DID authority percent-encoded, because
3251
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3252
+ * from `@fedify/vocab-runtime` to get the canonical string, e.g.,
3253
+ * `ap+ef61://did:key:z6Mk.../notes/123`.
3254
+ *
3255
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3256
+ *
3257
+ * @param cls The class of the object.
3258
+ * @param values The values to pass to the object dispatcher.
3259
+ * @param authority The DID that controls the object, e.g.,
3260
+ * `did:key:z6Mk...`. It must be a bare DID, without
3261
+ * a path, query, or fragment.
3262
+ * @returns The object's portable ID.
3263
+ * @throws {RouterError} If no object dispatcher is available for the class.
3264
+ * @throws {TypeError} If values are invalid, or the authority is not a DID
3265
+ * or is a `did:key` DID that is not encoded in
3266
+ * base58-btc.
3267
+ * @since 2.4.0
3268
+ */
3269
+ getPortableObjectUri<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>, authority: string): URL;
3270
+ /**
3271
+ * Builds the [FEP-ef61] portable ID of an actor's inbox with the given
3272
+ * identifier under the given DID authority.
3273
+ *
3274
+ * The path is the same as the one {@link Context.getInboxUri} builds from
3275
+ * the inbox path, but the result is an `ap+ef61:` URI whose authority is
3276
+ * the DID, e.g., `ap+ef61://did:key:z6Mk.../users/alice/inbox`. If
3277
+ * a portable actor has it as its `inbox` and lists this server in its
3278
+ * `gateways`, this server accepts deliveries to the inbox through
3279
+ * the FEP-ef61 gateway endpoint, e.g.,
3280
+ * `POST /.well-known/apgateway/did:key:z6Mk.../users/alice/inbox`, and
3281
+ * dispatches them to the inbox listeners.
3282
+ *
3283
+ * The returned `URL` keeps the DID authority percent-encoded, because
3284
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3285
+ * from `@fedify/vocab-runtime` to get the canonical string.
3286
+ *
3287
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3288
+ *
3289
+ * @param identifier The actor's identifier.
3290
+ * @param authority The DID that controls the actor, e.g.,
3291
+ * `did:key:z6Mk...`. It must be a bare DID, without
3292
+ * a path, query, or fragment.
3293
+ * @returns The inbox's portable ID.
3294
+ * @throws {RouterError} If no inbox path is registered.
3295
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3296
+ * DID that is not encoded in base58-btc.
3297
+ * @since 2.4.0
3298
+ */
3299
+ getPortableInboxUri(identifier: string, authority: string): URL;
3300
+ /**
2432
3301
  * Builds the URI of an actor's outbox with the given identifier.
2433
3302
  * @param identifier The actor's identifier.
2434
3303
  * @returns The actor's outbox URI.
@@ -2436,6 +3305,35 @@ interface Context<TContextData> {
2436
3305
  */
2437
3306
  getOutboxUri(identifier: string): URL;
2438
3307
  /**
3308
+ * Builds the [FEP-ef61] portable ID of an actor's outbox with the given
3309
+ * identifier under the given DID authority.
3310
+ *
3311
+ * The path is the same as the one {@link Context.getOutboxUri} builds, but
3312
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3313
+ * `ap+ef61://did:key:z6Mk.../users/alice/outbox`. If a portable actor has
3314
+ * it as its `outbox` and its ID is under the same DID, the collection is
3315
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3316
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/outbox`, by the same
3317
+ * collection dispatcher.
3318
+ *
3319
+ * The returned `URL` keeps the DID authority percent-encoded, because
3320
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3321
+ * from `@fedify/vocab-runtime` to get the canonical string.
3322
+ *
3323
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3324
+ *
3325
+ * @param identifier The actor's identifier.
3326
+ * @param authority The DID that controls the actor, e.g.,
3327
+ * `did:key:z6Mk...`. It must be a bare DID, without
3328
+ * a path, query, or fragment.
3329
+ * @returns The outbox's portable ID.
3330
+ * @throws {RouterError} If no outbox dispatcher is available.
3331
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3332
+ * DID that is not encoded in base58-btc.
3333
+ * @since 2.4.0
3334
+ */
3335
+ getPortableOutboxUri(identifier: string, authority: string): URL;
3336
+ /**
2439
3337
  * Builds the URI of an actor's media upload endpoint with the given
2440
3338
  * identifier. This is the endpoint advertised under `endpoints.uploadMedia`
2441
3339
  * in the actor document.
@@ -2467,6 +3365,35 @@ interface Context<TContextData> {
2467
3365
  */
2468
3366
  getFollowingUri(identifier: string): URL;
2469
3367
  /**
3368
+ * Builds the [FEP-ef61] portable ID of an actor's following collection with the given
3369
+ * identifier under the given DID authority.
3370
+ *
3371
+ * The path is the same as the one {@link Context.getFollowingUri} builds, but
3372
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3373
+ * `ap+ef61://did:key:z6Mk.../users/alice/following`. If a portable actor has
3374
+ * it as its `following` and its ID is under the same DID, the collection is
3375
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3376
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/following`, by the same
3377
+ * collection dispatcher.
3378
+ *
3379
+ * The returned `URL` keeps the DID authority percent-encoded, because
3380
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3381
+ * from `@fedify/vocab-runtime` to get the canonical string.
3382
+ *
3383
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3384
+ *
3385
+ * @param identifier The actor's identifier.
3386
+ * @param authority The DID that controls the actor, e.g.,
3387
+ * `did:key:z6Mk...`. It must be a bare DID, without
3388
+ * a path, query, or fragment.
3389
+ * @returns The following collection's portable ID.
3390
+ * @throws {RouterError} If no following collection is available.
3391
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3392
+ * DID that is not encoded in base58-btc.
3393
+ * @since 2.4.0
3394
+ */
3395
+ getPortableFollowingUri(identifier: string, authority: string): URL;
3396
+ /**
2470
3397
  * Builds the URI of an actor's followers collection with the given
2471
3398
  * identifier.
2472
3399
  * @param identifier The actor's identifier.
@@ -2475,6 +3402,35 @@ interface Context<TContextData> {
2475
3402
  */
2476
3403
  getFollowersUri(identifier: string): URL;
2477
3404
  /**
3405
+ * Builds the [FEP-ef61] portable ID of an actor's followers collection with the given
3406
+ * identifier under the given DID authority.
3407
+ *
3408
+ * The path is the same as the one {@link Context.getFollowersUri} builds, but
3409
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3410
+ * `ap+ef61://did:key:z6Mk.../users/alice/followers`. If a portable actor has
3411
+ * it as its `followers` and its ID is under the same DID, the collection is
3412
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3413
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/followers`, by the same
3414
+ * collection dispatcher.
3415
+ *
3416
+ * The returned `URL` keeps the DID authority percent-encoded, because
3417
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3418
+ * from `@fedify/vocab-runtime` to get the canonical string.
3419
+ *
3420
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3421
+ *
3422
+ * @param identifier The actor's identifier.
3423
+ * @param authority The DID that controls the actor, e.g.,
3424
+ * `did:key:z6Mk...`. It must be a bare DID, without
3425
+ * a path, query, or fragment.
3426
+ * @returns The followers collection's portable ID.
3427
+ * @throws {RouterError} If no followers collection is available.
3428
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3429
+ * DID that is not encoded in base58-btc.
3430
+ * @since 2.4.0
3431
+ */
3432
+ getPortableFollowersUri(identifier: string, authority: string): URL;
3433
+ /**
2478
3434
  * Builds the URI of an actor's liked collection with the given identifier.
2479
3435
  * @param identifier The actor's identifier.
2480
3436
  * @returns The actor's liked collection URI.
@@ -2483,6 +3439,35 @@ interface Context<TContextData> {
2483
3439
  */
2484
3440
  getLikedUri(identifier: string): URL;
2485
3441
  /**
3442
+ * Builds the [FEP-ef61] portable ID of an actor's liked collection with the given
3443
+ * identifier under the given DID authority.
3444
+ *
3445
+ * The path is the same as the one {@link Context.getLikedUri} builds, but
3446
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3447
+ * `ap+ef61://did:key:z6Mk.../users/alice/liked`. If a portable actor has
3448
+ * it as its `liked` and its ID is under the same DID, the collection is
3449
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3450
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/liked`, by the same
3451
+ * collection dispatcher.
3452
+ *
3453
+ * The returned `URL` keeps the DID authority percent-encoded, because
3454
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3455
+ * from `@fedify/vocab-runtime` to get the canonical string.
3456
+ *
3457
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3458
+ *
3459
+ * @param identifier The actor's identifier.
3460
+ * @param authority The DID that controls the actor, e.g.,
3461
+ * `did:key:z6Mk...`. It must be a bare DID, without
3462
+ * a path, query, or fragment.
3463
+ * @returns The liked collection's portable ID.
3464
+ * @throws {RouterError} If no liked collection is available.
3465
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3466
+ * DID that is not encoded in base58-btc.
3467
+ * @since 2.4.0
3468
+ */
3469
+ getPortableLikedUri(identifier: string, authority: string): URL;
3470
+ /**
2486
3471
  * Builds the URI of an actor's featured collection with the given identifier.
2487
3472
  * @param identifier The actor's identifier.
2488
3473
  * @returns The actor's featured collection URI.
@@ -2491,6 +3476,35 @@ interface Context<TContextData> {
2491
3476
  */
2492
3477
  getFeaturedUri(identifier: string): URL;
2493
3478
  /**
3479
+ * Builds the [FEP-ef61] portable ID of an actor's featured collection with the given
3480
+ * identifier under the given DID authority.
3481
+ *
3482
+ * The path is the same as the one {@link Context.getFeaturedUri} builds, but
3483
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3484
+ * `ap+ef61://did:key:z6Mk.../users/alice/featured`. If a portable actor has
3485
+ * it as its `featured` and its ID is under the same DID, the collection is
3486
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3487
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/featured`, by the same
3488
+ * collection dispatcher.
3489
+ *
3490
+ * The returned `URL` keeps the DID authority percent-encoded, because
3491
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3492
+ * from `@fedify/vocab-runtime` to get the canonical string.
3493
+ *
3494
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3495
+ *
3496
+ * @param identifier The actor's identifier.
3497
+ * @param authority The DID that controls the actor, e.g.,
3498
+ * `did:key:z6Mk...`. It must be a bare DID, without
3499
+ * a path, query, or fragment.
3500
+ * @returns The featured collection's portable ID.
3501
+ * @throws {RouterError} If no featured collection is available.
3502
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3503
+ * DID that is not encoded in base58-btc.
3504
+ * @since 2.4.0
3505
+ */
3506
+ getPortableFeaturedUri(identifier: string, authority: string): URL;
3507
+ /**
2494
3508
  * Builds the URI of an actor's featured tags collection with the given
2495
3509
  * identifier.
2496
3510
  * @param identifier The actor's identifier.
@@ -2500,13 +3514,68 @@ interface Context<TContextData> {
2500
3514
  */
2501
3515
  getFeaturedTagsUri(identifier: string): URL;
2502
3516
  /**
3517
+ * Builds the [FEP-ef61] portable ID of an actor's featured tags collection with the given
3518
+ * identifier under the given DID authority.
3519
+ *
3520
+ * The path is the same as the one {@link Context.getFeaturedTagsUri} builds, but
3521
+ * the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3522
+ * `ap+ef61://did:key:z6Mk.../users/alice/tags`. If a portable actor has
3523
+ * it as its `featuredTags` and its ID is under the same DID, the collection is
3524
+ * served through the FEP-ef61 gateway endpoint, e.g.,
3525
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/tags`, by the same
3526
+ * collection dispatcher.
3527
+ *
3528
+ * The returned `URL` keeps the DID authority percent-encoded, because
3529
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3530
+ * from `@fedify/vocab-runtime` to get the canonical string.
3531
+ *
3532
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3533
+ *
3534
+ * @param identifier The actor's identifier.
3535
+ * @param authority The DID that controls the actor, e.g.,
3536
+ * `did:key:z6Mk...`. It must be a bare DID, without
3537
+ * a path, query, or fragment.
3538
+ * @returns The featured tags collection's portable ID.
3539
+ * @throws {RouterError} If no featured tags collection is available.
3540
+ * @throws {TypeError} If the authority is not a DID, or it is a `did:key`
3541
+ * DID that is not encoded in base58-btc.
3542
+ * @since 2.4.0
3543
+ */
3544
+ getPortableFeaturedTagsUri(identifier: string, authority: string): URL;
3545
+ /**
2503
3546
  * Determines the type of the URI and extracts the associated data.
3547
+ *
3548
+ * By default, only URIs on this server's origin are recognized. With
3549
+ * the `portable` option, [FEP-ef61] portable IDs, e.g.,
3550
+ * `ap+ef61://did:key:z6Mk.../users/alice`, and their compatible
3551
+ * identifiers on any gateway, e.g.,
3552
+ * `https://example.com/.well-known/apgateway/did:key:z6Mk.../users/alice`,
3553
+ * are also recognized by the same paths that the gateway endpoint routes
3554
+ * to the dispatchers, and the result has the DID in its `authority`
3555
+ * property.
3556
+ *
3557
+ * The DID of a portable ID is anyone's to choose, so recognizing it does
3558
+ * not mean that this server hosts anything for the DID. Check that
3559
+ * `authority` is the DID that the application stores for the actor or
3560
+ * object before acting on it:
3561
+ *
3562
+ * ~~~~ typescript
3563
+ * const parsed = ctx.parseUri(follow.objectId, { portable: true });
3564
+ * if (parsed?.type !== "actor") return;
3565
+ * const user = await getUser(parsed.identifier);
3566
+ * if (user == null) return;
3567
+ * if (parsed.authority != null && parsed.authority !== user.did) return;
3568
+ * ~~~~
3569
+ *
3570
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3571
+ *
2504
3572
  * @param uri The URI to parse.
3573
+ * @param options Options for parsing the URI. Since 2.4.0.
2505
3574
  * @returns The result of parsing the URI. If `null` is given or
2506
3575
  * the URI is not recognized, `null` is returned.
2507
3576
  * @since 0.9.0
2508
3577
  */
2509
- parseUri(uri: URL | null): ParseUriResult | null;
3578
+ parseUri(uri: URL | null, options?: ParseUriOptions): ParseUriResult | null;
2510
3579
  /**
2511
3580
  * Gets the key pairs for an actor.
2512
3581
  * @param identifier The actor's identifier.
@@ -2574,7 +3643,16 @@ interface Context<TContextData> {
2574
3643
  * ```
2575
3644
  *
2576
3645
  * It's almost the same as the {@link lookupObject} function, but it uses
2577
- * the context's document loader and context loader by default.
3646
+ * the context's document loader and context loader by default. It also
3647
+ * uses {@link Context.verifyPortableObject} as the `verifyPortableObject`
3648
+ * option by default (since 2.4.0), so [FEP-ef61] portable objects,
3649
+ * including portable actors found through WebFinger, are looked up through
3650
+ * their gateways and returned only if they have valid proofs, or, for
3651
+ * collections without proofs, if they are served by gateways that their
3652
+ * owners list. The returned object uses the same policy by default for
3653
+ * its property accessors.
3654
+ *
3655
+ * [FEP-ef61]: https://w3id.org/fep/ef61
2578
3656
  *
2579
3657
  * @param identifier The URI or fediverse handle to look up.
2580
3658
  * @param options Lookup options.
@@ -2598,7 +3676,9 @@ interface Context<TContextData> {
2598
3676
  * ```
2599
3677
  *
2600
3678
  * It's almost the same as the {@link traverseCollection} function, but it
2601
- * uses the context's document loader and context loader by default.
3679
+ * uses the context's document loader and context loader by default. It
3680
+ * also uses {@link Context.verifyPortableObject} as the
3681
+ * `verifyPortableObject` option by default (since 2.4.0).
2602
3682
  * @param collection The collection to traverse.
2603
3683
  * @param options Options for traversing the collection.
2604
3684
  * @returns An async iterable of each item in the collection.
@@ -2747,6 +3827,61 @@ interface Context<TContextData> {
2747
3827
  * @since 1.8.0
2748
3828
  */
2749
3829
  getCollectionUri<TParam extends Record<string, string>>(name: string | symbol, values: TParam): URL;
3830
+ /**
3831
+ * Builds the [FEP-ef61] portable ID of a custom collection with the given
3832
+ * name and values under the given DID authority.
3833
+ *
3834
+ * The path is the same as the one {@link Context.getCollectionUri} builds,
3835
+ * but the result is an `ap+ef61:` URI whose authority is the DID, e.g.,
3836
+ * `ap+ef61://did:key:z6Mk.../users/alice/bookmarks`. If the collection
3837
+ * dispatcher maps the collection to a portable actor under the same DID
3838
+ * with `CustomCollectionCallbackSetters.mapPortableOwner()`, the
3839
+ * collection is served through the FEP-ef61 gateway endpoint, e.g.,
3840
+ * `/.well-known/apgateway/did:key:z6Mk.../users/alice/bookmarks`.
3841
+ *
3842
+ * The returned `URL` keeps the DID authority percent-encoded, because
3843
+ * the `URL` class cannot represent the canonical form. Use `formatIri()`
3844
+ * from `@fedify/vocab-runtime` to get the canonical string.
3845
+ *
3846
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3847
+ *
3848
+ * @param name The name of the collection, which can be a string or a symbol.
3849
+ * @param values The values of the URI parameters.
3850
+ * @param authority The DID that controls the collection, e.g.,
3851
+ * `did:key:z6Mk...`. It must be a bare DID, without
3852
+ * a path, query, or fragment.
3853
+ * @returns The collection's portable ID.
3854
+ * @throws {RouterError} If no collection dispatcher is available for
3855
+ * the name.
3856
+ * @throws {TypeError} If values are invalid, or the authority is not a DID
3857
+ * or is a `did:key` DID that is not encoded in
3858
+ * base58-btc.
3859
+ * @since 2.4.0
3860
+ */
3861
+ getPortableCollectionUri<TParam extends Record<string, string>>(name: string | symbol, values: TParam, authority: string): URL;
3862
+ }
3863
+ /**
3864
+ * Information about an [FEP-ef61] portable object requested through
3865
+ * the gateway endpoint. See {@link RequestContext.portableRequest}.
3866
+ *
3867
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3868
+ * @since 2.4.0
3869
+ */
3870
+ interface PortableRequest {
3871
+ /**
3872
+ * The DID authority of the requested portable object, e.g.,
3873
+ * `did:key:z6Mk...`. It comes from the request path, so it is not
3874
+ * evidence that this server hosts objects for the DID.
3875
+ */
3876
+ readonly authority: string;
3877
+ /**
3878
+ * The ID of the requested portable object or collection, e.g.,
3879
+ * `ap+ef61://did:key:z6Mk.../notes/123`, without a query. Like other
3880
+ * portable IDs, the `URL` keeps the DID authority percent-encoded; use
3881
+ * `formatIri()` from `@fedify/vocab-runtime` to get the canonical string.
3882
+ * Each access returns a new `URL` instance.
3883
+ */
3884
+ readonly id: URL;
2750
3885
  }
2751
3886
  /**
2752
3887
  * Options for {@link RequestContext.getActor}.
@@ -2762,6 +3897,23 @@ interface GetActorOptions {
2762
3897
  readonly tombstone?: "suppress" | "passthrough";
2763
3898
  }
2764
3899
  /**
3900
+ * Options for {@link RequestContext.getObject}.
3901
+ * @since 2.4.0
3902
+ */
3903
+ interface GetObjectOptions {
3904
+ /**
3905
+ * Controls how tombstoned objects are returned.
3906
+ *
3907
+ * By default, or if set to `"suppress"`, a {@link Tombstone} is returned as
3908
+ * `null`, unless it is an instance of the requested class, e.g., when
3909
+ * the requested class is `Object` or `Tombstone` itself. In that case,
3910
+ * the tombstone is returned as is, as it is an object of the requested
3911
+ * class. Set this to `"passthrough"` to always receive a {@link Tombstone}
3912
+ * result instead of `null`.
3913
+ */
3914
+ readonly tombstone?: "suppress" | "passthrough";
3915
+ }
3916
+ /**
2765
3917
  * A context for a request.
2766
3918
  */
2767
3919
  interface RequestContext<TContextData> extends Context<TContextData> {
@@ -2774,6 +3926,243 @@ interface RequestContext<TContextData> extends Context<TContextData> {
2774
3926
  */
2775
3927
  readonly url: URL;
2776
3928
  /**
3929
+ * Information about the [FEP-ef61] portable object requested through
3930
+ * the gateway endpoint, e.g.,
3931
+ * `GET /.well-known/apgateway/did:key:z6Mk.../notes/123`, which is served
3932
+ * by an object dispatcher, the actor dispatcher, or a collection
3933
+ * dispatcher. It is `undefined` for ordinary requests.
3934
+ *
3935
+ * The authority comes from the request path, so it is not evidence that
3936
+ * this server hosts objects for the DID. An object dispatcher or the actor
3937
+ * dispatcher has to check that by itself. A portable collection is served
3938
+ * only if its owner, which the actor dispatcher looks up without this
3939
+ * property, is a portable actor under the DID.
3940
+ *
3941
+ * It describes the incoming request, so it stays the same in contexts
3942
+ * derived from this one, e.g., by {@link RequestContext.getObject}.
3943
+ *
3944
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3945
+ * @since 2.4.0
3946
+ */
3947
+ readonly portableRequest?: PortableRequest;
3948
+ /**
3949
+ * Builds the [FEP-ef61] portable ID of an actor with the given identifier.
3950
+ * It works the same as {@link Context.getPortableActorUri}, except that
3951
+ * the authority can be omitted while handling a portable gateway request.
3952
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
3953
+ *
3954
+ * The DID in the request comes from the request path, so the default is
3955
+ * only a convenience for building IDs; it is not evidence that this server
3956
+ * hosts the actor for the DID.
3957
+ *
3958
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3959
+ *
3960
+ * @param identifier The actor's identifier.
3961
+ * @param authority The DID that controls the actor, e.g.,
3962
+ * `did:key:z6Mk...`. It must be a bare DID, without
3963
+ * a path, query, or fragment. Defaults to the DID of
3964
+ * the requested portable object.
3965
+ * @returns The actor's portable ID.
3966
+ * @throws {RouterError} If no actor dispatcher is available.
3967
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
3968
+ * that is not encoded in base58-btc, or the authority
3969
+ * is omitted outside a portable gateway request.
3970
+ * @since 2.4.0
3971
+ */
3972
+ getPortableActorUri(identifier: string, authority?: string): URL;
3973
+ /**
3974
+ * Builds the [FEP-ef61] portable ID of an object with the given class and
3975
+ * values. It works the same as {@link Context.getPortableObjectUri}, except
3976
+ * that the authority can be omitted while handling a portable gateway
3977
+ * request. In that case, the DID in {@link RequestContext.portableRequest}
3978
+ * is used.
3979
+ *
3980
+ * [FEP-ef61]: https://w3id.org/fep/ef61
3981
+ *
3982
+ * @param cls The class of the object.
3983
+ * @param values The values to pass to the object dispatcher.
3984
+ * @param authority The DID that controls the object, e.g.,
3985
+ * `did:key:z6Mk...`. It must be a bare DID, without
3986
+ * a path, query, or fragment. Defaults to the DID of
3987
+ * the requested portable object.
3988
+ * @returns The object's portable ID.
3989
+ * @throws {RouterError} If no object dispatcher is available for the class.
3990
+ * @throws {TypeError} If values are invalid, the authority is not a DID,
3991
+ * it is a `did:key` DID that is not encoded in
3992
+ * base58-btc, or the authority is omitted outside
3993
+ * a portable gateway request.
3994
+ * @since 2.4.0
3995
+ */
3996
+ getPortableObjectUri<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>, authority?: string): URL;
3997
+ /**
3998
+ * Builds the [FEP-ef61] portable ID of an actor's inbox with the given
3999
+ * identifier. It works the same as {@link Context.getPortableInboxUri},
4000
+ * except that the authority can be omitted while handling a portable object
4001
+ * request, i.e., when {@link RequestContext.portableRequest} is set. In
4002
+ * that case, its DID is used. Deliveries to portable inboxes do not set
4003
+ * {@link RequestContext.portableRequest}, so pass the authority explicitly
4004
+ * while handling them.
4005
+ *
4006
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4007
+ *
4008
+ * @param identifier The actor's identifier.
4009
+ * @param authority The DID that controls the actor, e.g.,
4010
+ * `did:key:z6Mk...`. It must be a bare DID, without
4011
+ * a path, query, or fragment. Defaults to the DID of
4012
+ * the requested portable object, if any.
4013
+ * @returns The inbox's portable ID.
4014
+ * @throws {RouterError} If no inbox path is registered.
4015
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4016
+ * that is not encoded in base58-btc, or the authority
4017
+ * is omitted outside a portable gateway request.
4018
+ * @since 2.4.0
4019
+ */
4020
+ getPortableInboxUri(identifier: string, authority?: string): URL;
4021
+ /**
4022
+ * Builds the [FEP-ef61] portable ID of an actor's outbox with the given
4023
+ * identifier. It works the same as {@link Context.getPortableOutboxUri}, except that
4024
+ * the authority can be omitted while handling a portable gateway request.
4025
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
4026
+ *
4027
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4028
+ *
4029
+ * @param identifier The actor's identifier.
4030
+ * @param authority The DID that controls the actor, e.g.,
4031
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4032
+ * portable object or collection.
4033
+ * @returns The outbox's portable ID.
4034
+ * @throws {RouterError} If no outbox dispatcher is available.
4035
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4036
+ * that is not encoded in base58-btc, or the authority
4037
+ * is omitted outside a portable gateway request.
4038
+ * @since 2.4.0
4039
+ */
4040
+ getPortableOutboxUri(identifier: string, authority?: string): URL;
4041
+ /**
4042
+ * Builds the [FEP-ef61] portable ID of an actor's following collection with the given
4043
+ * identifier. It works the same as {@link Context.getPortableFollowingUri}, except that
4044
+ * the authority can be omitted while handling a portable gateway request.
4045
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
4046
+ *
4047
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4048
+ *
4049
+ * @param identifier The actor's identifier.
4050
+ * @param authority The DID that controls the actor, e.g.,
4051
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4052
+ * portable object or collection.
4053
+ * @returns The following collection's portable ID.
4054
+ * @throws {RouterError} If no following collection is available.
4055
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4056
+ * that is not encoded in base58-btc, or the authority
4057
+ * is omitted outside a portable gateway request.
4058
+ * @since 2.4.0
4059
+ */
4060
+ getPortableFollowingUri(identifier: string, authority?: string): URL;
4061
+ /**
4062
+ * Builds the [FEP-ef61] portable ID of an actor's followers collection with the given
4063
+ * identifier. It works the same as {@link Context.getPortableFollowersUri}, except that
4064
+ * the authority can be omitted while handling a portable gateway request.
4065
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
4066
+ *
4067
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4068
+ *
4069
+ * @param identifier The actor's identifier.
4070
+ * @param authority The DID that controls the actor, e.g.,
4071
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4072
+ * portable object or collection.
4073
+ * @returns The followers collection's portable ID.
4074
+ * @throws {RouterError} If no followers collection is available.
4075
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4076
+ * that is not encoded in base58-btc, or the authority
4077
+ * is omitted outside a portable gateway request.
4078
+ * @since 2.4.0
4079
+ */
4080
+ getPortableFollowersUri(identifier: string, authority?: string): URL;
4081
+ /**
4082
+ * Builds the [FEP-ef61] portable ID of an actor's liked collection with the given
4083
+ * identifier. It works the same as {@link Context.getPortableLikedUri}, except that
4084
+ * the authority can be omitted while handling a portable gateway request.
4085
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
4086
+ *
4087
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4088
+ *
4089
+ * @param identifier The actor's identifier.
4090
+ * @param authority The DID that controls the actor, e.g.,
4091
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4092
+ * portable object or collection.
4093
+ * @returns The liked collection's portable ID.
4094
+ * @throws {RouterError} If no liked collection is available.
4095
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4096
+ * that is not encoded in base58-btc, or the authority
4097
+ * is omitted outside a portable gateway request.
4098
+ * @since 2.4.0
4099
+ */
4100
+ getPortableLikedUri(identifier: string, authority?: string): URL;
4101
+ /**
4102
+ * Builds the [FEP-ef61] portable ID of an actor's featured collection with the given
4103
+ * identifier. It works the same as {@link Context.getPortableFeaturedUri}, except that
4104
+ * the authority can be omitted while handling a portable gateway request.
4105
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
4106
+ *
4107
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4108
+ *
4109
+ * @param identifier The actor's identifier.
4110
+ * @param authority The DID that controls the actor, e.g.,
4111
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4112
+ * portable object or collection.
4113
+ * @returns The featured collection's portable ID.
4114
+ * @throws {RouterError} If no featured collection is available.
4115
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4116
+ * that is not encoded in base58-btc, or the authority
4117
+ * is omitted outside a portable gateway request.
4118
+ * @since 2.4.0
4119
+ */
4120
+ getPortableFeaturedUri(identifier: string, authority?: string): URL;
4121
+ /**
4122
+ * Builds the [FEP-ef61] portable ID of an actor's featured tags collection with the given
4123
+ * identifier. It works the same as {@link Context.getPortableFeaturedTagsUri}, except that
4124
+ * the authority can be omitted while handling a portable gateway request.
4125
+ * In that case, the DID in {@link RequestContext.portableRequest} is used.
4126
+ *
4127
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4128
+ *
4129
+ * @param identifier The actor's identifier.
4130
+ * @param authority The DID that controls the actor, e.g.,
4131
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4132
+ * portable object or collection.
4133
+ * @returns The featured tags collection's portable ID.
4134
+ * @throws {RouterError} If no featured tags collection is available.
4135
+ * @throws {TypeError} If the authority is not a DID, it is a `did:key` DID
4136
+ * that is not encoded in base58-btc, or the authority
4137
+ * is omitted outside a portable gateway request.
4138
+ * @since 2.4.0
4139
+ */
4140
+ getPortableFeaturedTagsUri(identifier: string, authority?: string): URL;
4141
+ /**
4142
+ * Builds the [FEP-ef61] portable ID of a custom collection with the given
4143
+ * name and values. It works the same as
4144
+ * {@link Context.getPortableCollectionUri}, except that the authority can
4145
+ * be omitted while handling a portable gateway request. In that case,
4146
+ * the DID in {@link RequestContext.portableRequest} is used.
4147
+ *
4148
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4149
+ *
4150
+ * @param name The name of the collection, which can be a string or a symbol.
4151
+ * @param values The values of the URI parameters.
4152
+ * @param authority The DID that controls the collection, e.g.,
4153
+ * `did:key:z6Mk...`. Defaults to the DID of the requested
4154
+ * portable object or collection.
4155
+ * @returns The collection's portable ID.
4156
+ * @throws {RouterError} If no collection dispatcher is available for
4157
+ * the name.
4158
+ * @throws {TypeError} If values are invalid, the authority is not a DID,
4159
+ * it is a `did:key` DID that is not encoded in
4160
+ * base58-btc, or the authority is omitted outside
4161
+ * a portable gateway request.
4162
+ * @since 2.4.0
4163
+ */
4164
+ getPortableCollectionUri<TParam extends Record<string, string>>(name: string | symbol, values: TParam, authority?: string): URL;
4165
+ /**
2777
4166
  * Creates a new context with the same properties as this one,
2778
4167
  * but with the given data.
2779
4168
  * @param data The new data to associate with the context.
@@ -2835,13 +4224,62 @@ interface RequestContext<TContextData> extends Context<TContextData> {
2835
4224
  * @param cls The class to instantiate.
2836
4225
  * @param values The values to pass to the object dispatcher.
2837
4226
  * @returns The object of the given class with the given values, or `null`
2838
- * if the object is not found.
4227
+ * if the object is not found. Tombstoned objects are suppressed
4228
+ * unless the tombstone is an instance of `cls`.
2839
4229
  * @throws {Error} If no object dispatcher is available for the class.
2840
4230
  * @throws {TypeError} If values are invalid.
2841
4231
  * @since 0.7.0
2842
4232
  */
2843
4233
  getObject<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>): Promise<TObject | null>;
2844
4234
  /**
4235
+ * Gets an object of the given class, or a {@link Tombstone}, with the given
4236
+ * values.
4237
+ * @param cls The class to instantiate.
4238
+ * @param values The values to pass to the object dispatcher.
4239
+ * @param options Options for getting the object. Set `options.tombstone`
4240
+ * to `"passthrough"` to receive tombstoned objects instead
4241
+ * of `null`.
4242
+ * @returns The object of the given class with the given values,
4243
+ * a tombstone, or `null` if the object is not found.
4244
+ * @throws {Error} If no object dispatcher is available for the class.
4245
+ * @throws {TypeError} If values are invalid.
4246
+ * @since 2.4.0
4247
+ */
4248
+ getObject<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>, options: GetObjectOptions & {
4249
+ readonly tombstone: "passthrough";
4250
+ }): Promise<TObject | Tombstone | null>;
4251
+ /**
4252
+ * Gets an object of the given class with the given values.
4253
+ * @param cls The class to instantiate.
4254
+ * @param values The values to pass to the object dispatcher.
4255
+ * @param options Options for getting the object.
4256
+ * @returns The object of the given class with the given values, or `null`
4257
+ * if the object is not found. Tombstoned objects are suppressed
4258
+ * unless `options.tombstone` is `"passthrough"` or the tombstone
4259
+ * is an instance of `cls`.
4260
+ * @throws {Error} If no object dispatcher is available for the class.
4261
+ * @throws {TypeError} If values are invalid.
4262
+ * @since 2.4.0
4263
+ */
4264
+ getObject<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>, options: GetObjectOptions & {
4265
+ readonly tombstone?: "suppress" | undefined;
4266
+ }): Promise<TObject | null>;
4267
+ /**
4268
+ * Gets an object of the given class, or a {@link Tombstone}, with the given
4269
+ * values.
4270
+ * @param cls The class to instantiate.
4271
+ * @param values The values to pass to the object dispatcher.
4272
+ * @param options Options for getting the object.
4273
+ * @returns The object of the given class with the given values,
4274
+ * a tombstone, or `null` if the object is not found. This broad
4275
+ * overload is used when the caller passes an options value whose
4276
+ * `tombstone` mode is not known statically.
4277
+ * @throws {Error} If no object dispatcher is available for the class.
4278
+ * @throws {TypeError} If values are invalid.
4279
+ * @since 2.4.0
4280
+ */
4281
+ getObject<TObject extends Object$1>(cls: ConstructorWithTypeId<TObject>, values: Record<string, string>, options: GetObjectOptions): Promise<TObject | Tombstone | null>;
4282
+ /**
2845
4283
  * Gets the public key of the sender, if any exists and it is verified.
2846
4284
  * Otherwise, `null` is returned.
2847
4285
  *
@@ -2907,6 +4345,52 @@ interface RequestContext<TContextData> extends Context<TContextData> {
2907
4345
  * [instance actor]: https://swicg.github.io/activitypub-http-signature/#instance-actor
2908
4346
  */
2909
4347
  getSignedKeyOwner(options: GetKeyOwnerOptions): Promise<Actor | null>;
4348
+ /**
4349
+ * Checks whether the request is signed by an actor who belongs to
4350
+ * the intended audience of an object, i.e., the owner of the signed key
4351
+ * (see {@link RequestContext.getSignedKeyOwner}) is one of the object's
4352
+ * `to`, `cc`, `bto`, `bcc`, and `audience`, or a member of one of them
4353
+ * according to the `isMember` option.
4354
+ *
4355
+ * Everyone belongs to the audience of a publicly addressed object, so it
4356
+ * returns `true` for such an object even if the request is not signed.
4357
+ *
4358
+ * This can be used in authorization predicates for serving non-public
4359
+ * objects, which [FEP-ef61] requires of gateways serving portable objects.
4360
+ * [FEP-ef61] portable IDs are compared by their canonical forms, so
4361
+ * an `ap:` URI, an `ap+ef61:` URI, and a compatible identifier on any
4362
+ * gateway refer to the same actor.
4363
+ *
4364
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4365
+ *
4366
+ * @param object The object whose audience is checked.
4367
+ * @param options Options for checking the audience.
4368
+ * @returns `true` if the object is publicly addressed, or the request is
4369
+ * signed by an actor who belongs to its audience.
4370
+ * @since 2.4.0
4371
+ */
4372
+ isSignedByAudience(object: Object$1, options?: IsSignedByAudienceOptions): Promise<boolean>;
4373
+ }
4374
+ /**
4375
+ * Options for {@link RequestContext.isSignedByAudience} method.
4376
+ * @since 2.4.0
4377
+ */
4378
+ interface IsSignedByAudienceOptions extends GetKeyOwnerOptions {
4379
+ /**
4380
+ * Checks whether the actor who signed the request is a member of
4381
+ * an addressee of the object that is not the actor itself, e.g.,
4382
+ * a followers collection. Fedify does not resolve collections by itself,
4383
+ * as only the application can tell their members reliably.
4384
+ *
4385
+ * It is called for each such addressee in order until it returns `true`.
4386
+ * If it is omitted, only the actors that the object addresses directly
4387
+ * belong to its audience.
4388
+ * @param addressee The ID of the addressee, e.g., the ID of a followers
4389
+ * collection.
4390
+ * @param actor The actor who signed the request.
4391
+ * @returns `true` if the actor is a member of the addressee.
4392
+ */
4393
+ isMember?: (addressee: URL, actor: Actor) => boolean | Promise<boolean>;
2910
4394
  }
2911
4395
  /**
2912
4396
  * A context for inbox listeners.
@@ -3036,52 +4520,143 @@ interface OutboxContext<TContextData> extends Context<TContextData> {
3036
4520
  clone(data: TContextData): OutboxContext<TContextData>;
3037
4521
  }
3038
4522
  /**
4523
+ * Options for {@link Context.parseUri}.
4524
+ * @since 2.4.0
4525
+ */
4526
+ interface ParseUriOptions {
4527
+ /**
4528
+ * Whether to also recognize [FEP-ef61] portable IDs, i.e., `ap:` and
4529
+ * `ap+ef61:` URIs, and their compatible identifiers on any gateway.
4530
+ * The result of a portable ID has its DID, without percent-encoding, in
4531
+ * the `authority` property, which the caller has to compare with the DID
4532
+ * that it stores for the actor or object, since anyone can make a portable
4533
+ * ID with the same path under another DID.
4534
+ *
4535
+ * Like URIs on this server's origin, a portable ID is recognized by its
4536
+ * path, and its query, e.g., location hints, and fragment are ignored.
4537
+ * A shared inbox is never recognized in a portable ID, and a portable ID
4538
+ * with a malformed DID, or with a `did:key` DID that is not encoded in
4539
+ * base58-btc, is not recognized either.
4540
+ *
4541
+ * [FEP-ef61]: https://w3id.org/fep/ef61
4542
+ * @default `false`
4543
+ */
4544
+ readonly portable?: boolean;
4545
+ }
4546
+ /**
3039
4547
  * A result of parsing an URI.
3040
4548
  */
3041
4549
  type ParseUriResult = {
3042
4550
  readonly type: "actor";
3043
4551
  readonly identifier: string;
4552
+ /**
4553
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4554
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4555
+ * @since 2.4.0
4556
+ */
4557
+ readonly authority?: string;
3044
4558
  } | {
3045
4559
  readonly type: "object";
3046
4560
  readonly class: ConstructorWithTypeId<Object$1>;
3047
4561
  readonly typeId: URL;
3048
4562
  readonly values: Record<string, string>;
4563
+ /**
4564
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4565
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4566
+ * @since 2.4.0
4567
+ */
4568
+ readonly authority?: string;
3049
4569
  } | {
3050
4570
  readonly type: "inbox";
3051
4571
  readonly identifier: undefined;
4572
+ readonly authority?: undefined;
3052
4573
  } | {
3053
4574
  readonly type: "inbox";
3054
4575
  readonly identifier: string;
4576
+ /**
4577
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4578
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4579
+ * @since 2.4.0
4580
+ */
4581
+ readonly authority?: string;
3055
4582
  } | {
3056
4583
  readonly type: "outbox";
3057
4584
  readonly identifier: string;
4585
+ /**
4586
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4587
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4588
+ * @since 2.4.0
4589
+ */
4590
+ readonly authority?: string;
3058
4591
  } | {
3059
4592
  readonly type: "following";
3060
4593
  readonly identifier: string;
4594
+ /**
4595
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4596
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4597
+ * @since 2.4.0
4598
+ */
4599
+ readonly authority?: string;
3061
4600
  } | {
3062
4601
  readonly type: "followers";
3063
4602
  readonly identifier: string;
4603
+ /**
4604
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4605
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4606
+ * @since 2.4.0
4607
+ */
4608
+ readonly authority?: string;
3064
4609
  } | {
3065
4610
  readonly type: "liked";
3066
4611
  readonly identifier: string;
4612
+ /**
4613
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4614
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4615
+ * @since 2.4.0
4616
+ */
4617
+ readonly authority?: string;
3067
4618
  } | {
3068
4619
  readonly type: "featured";
3069
4620
  readonly identifier: string;
4621
+ /**
4622
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4623
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4624
+ * @since 2.4.0
4625
+ */
4626
+ readonly authority?: string;
3070
4627
  } | {
3071
4628
  readonly type: "featuredTags";
3072
4629
  readonly identifier: string;
4630
+ /**
4631
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4632
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4633
+ * @since 2.4.0
4634
+ */
4635
+ readonly authority?: string;
3073
4636
  } | {
3074
4637
  readonly type: "collection";
3075
4638
  readonly name: string | symbol;
3076
4639
  readonly class: ConstructorWithTypeId<Object$1>;
3077
4640
  readonly typeId: URL;
3078
4641
  readonly values: Record<string, string>;
4642
+ /**
4643
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4644
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4645
+ * @since 2.4.0
4646
+ */
4647
+ readonly authority?: string;
3079
4648
  } | {
3080
4649
  readonly type: "orderedCollection";
3081
4650
  readonly name: string | symbol;
3082
4651
  readonly class: ConstructorWithTypeId<Object$1>;
3083
4652
  readonly typeId: URL;
3084
4653
  readonly values: Record<string, string>;
4654
+ /**
4655
+ * The DID of the portable ID, e.g., `did:key:z6Mk...`, or `undefined`
4656
+ * for a URI on this server's origin. See {@link ParseUriOptions.portable}.
4657
+ * @since 2.4.0
4658
+ */
4659
+ readonly authority?: string;
3085
4660
  };
3086
4661
  /**
3087
4662
  * Options for {@link Context.sendActivity} method.
@@ -3248,4 +4823,4 @@ interface ActorKeyPair extends CryptoKeyPair {
3248
4823
  readonly multikey: Multikey;
3249
4824
  }
3250
4825
  //#endregion
3251
- export { CircuitBreakerCreateOptions as $, OutboxListenerSetters as A, UnverifiedActivityHandler as At, TaskEnqueueOptions as B, FederationStartQueueOptions as C, ObjectAuthorizePredicate as Ct, InboxListenerSetters as D, OutboxListenerErrorHandler as Dt, InboxChallengePolicy as E, OutboxListener as Et, createFederation as F, PageItems as Ft, RetryPolicy as G, TaskRegistry as H, Message as I, buildCollectionSynchronizationHeader as It, respondWithObject as J, createExponentialBackoffPolicy as K, createFederationBuilder as L, digest as Lt, FederationKvPrefixes as M, WebFingerLinksDispatcher as Mt, FederationOrigin as N, SendActivityError as Nt, MediaUploaderSetters as O, OutboxPermanentFailureHandler as Ot, FederationQueueOptions as P, SenderKeyPair as Pt, CircuitBreakerBeforeSendDecision as Q, TaskDefinition as R, ActivityTransformer as Rt, FederationOptions as S, NodeInfoDispatcher as St, IdempotencyStrategy as T, OutboxErrorHandler as Tt, CreateExponentialBackoffPolicyOptions as U, TaskHandler as V, RetryContext as W, CircuitBreaker as X, respondWithObjectIfAcceptable as Y, CircuitBreakerActivityDrop as Z, Federatable as _, CustomCollectionCursor as _t, GetSignedKeyOptions as a, NormalizedCircuitBreakerOptions as at, FederationBuilder as b, InboxListener as bt, ParseUriResult as c, ActorAliasMapper as ct, SendActivityOptions as d, ActorKeyPairsDispatcher as dt, CircuitBreakerFailurePolicy as et, SendActivityOptionsForCollection as f, AuthorizePredicate as ft, CustomCollectionCallbackSetters as g, CustomCollectionCounter as gt, ConstructorWithTypeId as h, CollectionDispatcher as ht, GetActorOptions as i, CircuitBreakerStateChange as it, Rfc6570Expression as j, UnverifiedActivityReason as jt, ObjectCallbackSetters as k, SharedInboxKeyDispatcher as kt, RequestContext as l, ActorDispatcher as lt, CollectionCallbackSetters as m, CollectionCursor as mt, Context as n, CircuitBreakerOptions as nt, InboxContext as o, normalizeCircuitBreakerOptions as ot, ActorCallbackSetters as p, CollectionCounter as pt, RespondWithObjectOptions as q, ForwardActivityOptions as r, CircuitBreakerState as rt, OutboxContext as s, parseCircuitBreakerKvState as st, ActorKeyPair as t, CircuitBreakerKvState as tt, RouteActivityOptions as u, ActorHandleMapper as ut, Federation as v, CustomCollectionDispatcher as vt, IdempotencyKeyCallback as w, ObjectDispatcher as wt, FederationFetchOptions as x, MediaUploaderCallback as xt, FederationBenchmarkOptions as y, InboxErrorHandler as yt, TaskDefinitionOptions as z };
4826
+ export { respondWithObject as $, digest as $t, InboxChallengePolicy as A, CustomCollectionDispatcher as At, createFederation as B, OutboxListener as Bt, FederationBenchmarkOptions as C, ActorKeyPairsDispatcher as Ct, FederationStartQueueOptions as D, CollectionDispatcher as Dt, FederationOptions as E, CollectionCursor as Et, PortableInboxForwardingOptions as F, MediaUploaderCallback as Ft, TaskEnqueueOptions as G, SharedInboxKeyDispatcher as Gt, createFederationBuilder as H, OutboxPermanentFailureHandler as Ht, Rfc6570Expression as I, NodeInfoDispatcher as It, CreateExponentialBackoffPolicyOptions as J, WebFingerLinksDispatcher as Jt, TaskHandler as K, UnverifiedActivityHandler as Kt, FederationKvPrefixes as L, ObjectAuthorizePredicate as Lt, MediaUploaderSetters as M, HashlinkMediaRequest as Mt, ObjectCallbackSetters as N, InboxErrorHandler as Nt, IdempotencyKeyCallback as O, CustomCollectionCounter as Ot, OutboxListenerSetters as P, InboxListener as Pt, RespondWithObjectOptions as Q, buildCollectionSynchronizationHeader as Qt, FederationOrigin as R, ObjectDispatcher as Rt, Federation as S, ActorHandleMapper as St, FederationFetchOptions as T, CollectionCounter as Tt, TaskDefinition as U, PortableActorIdMapper as Ut, Message as V, OutboxListenerErrorHandler as Vt, TaskDefinitionOptions as W, PortableCollectionOwnerMapper as Wt, RetryPolicy as X, SenderKeyPair as Xt, RetryContext as Y, SendActivityError as Yt, createExponentialBackoffPolicy as Z, PageItems as Zt, ActorCallbackSetters as _, NormalizedCircuitBreakerOptions as _t, GetObjectOptions as a, InboxRequestReport as an, MessageQueueEnqueueOptions as at, CustomCollectionCallbackSetters as b, ActorAliasMapper as bt, IsSignedByAudienceOptions as c, CircuitBreaker as ct, ParseUriResult as d, CircuitBreakerCreateOptions as dt, ActivityTransformer as en, respondWithObjectIfAcceptable as et, PortableRequest as f, CircuitBreakerFailurePolicy as ft, SendActivityOptionsForCollection as g, CircuitBreakerStateChange as gt, SendActivityOptions as h, CircuitBreakerState as ht, GetActorOptions as i, InboxRequestOutcome as in, MessageQueueDepth as it, InboxListenerSetters as j, HashlinkMediaDispatcher as jt, IdempotencyStrategy as k, CustomCollectionCursor as kt, OutboxContext as l, CircuitBreakerActivityDrop as lt, RouteActivityOptions as m, CircuitBreakerOptions as mt, Context as n, InboxJsonValue as nn, InProcessMessageQueueOptions as nt, GetSignedKeyOptions as o, MessageQueueListenOptions as ot, RequestContext as p, CircuitBreakerKvState as pt, TaskRegistry as q, UnverifiedActivityReason as qt, ForwardActivityOptions as r, InboxRequestFinishedHandler as rn, MessageQueue as rt, InboxContext as s, ParallelMessageQueue as st, ActorKeyPair as t, InboxAuthentication as tn, InProcessMessageQueue as tt, ParseUriOptions as u, CircuitBreakerBeforeSendDecision as ut, CollectionCallbackSetters as v, normalizeCircuitBreakerOptions as vt, FederationBuilder as w, AuthorizePredicate as wt, Federatable as x, ActorDispatcher as xt, ConstructorWithTypeId as y, parseCircuitBreakerKvState as yt, FederationQueueOptions as z, OutboxErrorHandler as zt };