@fedify/fedify 2.4.0-dev.2077 → 2.4.0-dev.2093

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 (75) hide show
  1. package/dist/{builder-i3jxVe9m.mjs → builder-Ld4Y9ymR.mjs} +34 -3
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{compound-proof-Cayy-ECj.mjs → compound-proof-CTx_lewQ.mjs} +191 -13
  4. package/dist/{deno-Djkzd-G_.mjs → deno-8t8k_6Yv.mjs} +1 -1
  5. package/dist/{docloader-dA0RswUV.mjs → docloader-DJKcsAiF.mjs} +2 -2
  6. package/dist/federation/builder.test.mjs +1 -1
  7. package/dist/federation/compound-fanout.test.mjs +3 -3
  8. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  9. package/dist/federation/handler.test.mjs +5 -5
  10. package/dist/federation/hashlink-media.test.mjs +2 -2
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/metrics.test.mjs +1 -1
  13. package/dist/federation/middleware.test.mjs +7 -7
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.js +1 -1
  16. package/dist/federation/outgoing-proof.test.mjs +254 -5
  17. package/dist/federation/portable-gateway-keys.test.mjs +72 -11
  18. package/dist/federation/portable-inbox.test.mjs +513 -6
  19. package/dist/federation/portable.test.mjs +182 -4
  20. package/dist/federation/send.test.mjs +3 -3
  21. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  22. package/dist/federation/tasks/tasks.test.mjs +2 -2
  23. package/dist/federation/temporal.test.mjs +1 -1
  24. package/dist/federation/webfinger.test.mjs +89 -1
  25. package/dist/{federation-CFd0Jhhv.cjs → federation-aSHO04ob.cjs} +472 -74
  26. package/dist/{http-CCJ97Jql.mjs → http-B2ftY0Ha.mjs} +4 -4
  27. package/dist/{http-Dvy_IwRa.cjs → http-DSaSAN7X.cjs} +1609 -1457
  28. package/dist/{http-aqh3yFdM.js → http-DyT7DP1Y.js} +1518 -1390
  29. package/dist/{key-IxTTC8Yf.mjs → key-Dwm4VswT.mjs} +39 -99
  30. package/dist/{kv-cache-BP69NV0P.cjs → kv-cache-BSJAlP4C.cjs} +1 -1
  31. package/dist/{kv-cache-Bwwbh-xR.mjs → kv-cache-D0yYukqk.mjs} +1 -1
  32. package/dist/{kv-cache-Y6SDRSX6.js → kv-cache-DmroAz3M.js} +1 -1
  33. package/dist/{ld-l0B9nREb.mjs → ld-BYZOoDzZ.mjs} +3 -3
  34. package/dist/{metrics-D1p6hv4z.mjs → metrics-B7YwKTFr.mjs} +1 -1
  35. package/dist/{middleware-BDjCUHMS.mjs → middleware-BNeqKSsL.mjs} +1 -1
  36. package/dist/{middleware-SSfryVzY.js → middleware-Blq0882d.js} +480 -82
  37. package/dist/{middleware-BMgzqBtr.mjs → middleware-E_0IH72m.mjs} +278 -80
  38. package/dist/{mod-HDSvS-ww.d.cts → mod-C8LieBzF.d.cts} +16 -3
  39. package/dist/{mod-C9WSpZWm.d.ts → mod-Coacostr.d.ts} +16 -3
  40. package/dist/mod.cjs +5 -5
  41. package/dist/mod.d.cts +1 -1
  42. package/dist/mod.d.ts +1 -1
  43. package/dist/mod.js +5 -5
  44. package/dist/nodeinfo/handler.test.mjs +1 -1
  45. package/dist/{owner-DGbYmXqU.mjs → owner-Cgx2Dc7I.mjs} +5 -4
  46. package/dist/{owner-jH1z_YfD.js → owner-DAGSC5gX.js} +2 -2
  47. package/dist/{owner-BpOxL5PG.cjs → owner-szIZl4qI.cjs} +2 -2
  48. package/dist/{portable-key-CCwJGSsU.mjs → portable-key-Cn1WJSN1.mjs} +60 -41
  49. package/dist/portable-key-id-Bva5iT3W.mjs +136 -0
  50. package/dist/{proof-CVL7JnZd.mjs → proof-DVXC6nYz.mjs} +59 -18
  51. package/dist/{send-Ejy1jOz9.mjs → send-D-hOvYKy.mjs} +3 -3
  52. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  53. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  54. package/dist/sig/compound-proof-verification.test.mjs +160 -3
  55. package/dist/sig/compound-proof.test.mjs +2 -2
  56. package/dist/sig/http.test.mjs +2 -2
  57. package/dist/sig/key.test.mjs +1 -1
  58. package/dist/sig/ld.test.mjs +2 -2
  59. package/dist/sig/mod.cjs +3 -3
  60. package/dist/sig/mod.d.cts +1 -1
  61. package/dist/sig/mod.d.ts +1 -1
  62. package/dist/sig/mod.js +3 -3
  63. package/dist/sig/owner.test.mjs +1 -1
  64. package/dist/sig/portable-collection.test.mjs +69 -5
  65. package/dist/sig/portable-key.test.mjs +176 -10
  66. package/dist/sig/proof.test.mjs +107 -4
  67. package/dist/{sig-Dpy1B1Ad.js → sig-B5Ell7pO.js} +19 -3
  68. package/dist/{sig-xoqy3ATq.cjs → sig-CXOKN4Br.cjs} +19 -3
  69. package/dist/{temporal-DNJ1cNpr.mjs → temporal-CqpKGEPk.mjs} +1 -1
  70. package/dist/testing/kv.test.mjs +1 -1
  71. package/dist/utils/docloader.test.mjs +2 -2
  72. package/dist/utils/kv-cache.test.mjs +1 -1
  73. package/dist/utils/mod.cjs +1 -1
  74. package/dist/utils/mod.js +1 -1
  75. package/package.json +7 -7
@@ -1,27 +1,28 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-Djkzd-G_.mjs";
5
- import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-D1p6hv4z.mjs";
4
+ import { n as version, t as name } from "./deno-8t8k_6Yv.mjs";
5
+ import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-B7YwKTFr.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-CPVqki78.mjs";
7
- import { d as hasPortableActor, f as isCompatibleKeyId, m as isPortableUri, o as importJwk, s as validateCryptoKey, t as exportJwk, u as getGatewayKeyBase } from "./key-IxTTC8Yf.mjs";
7
+ import { a as isCompatibleKeyId, c as isPortableUri, i as hasPortableActor, n as getGatewayKeyBase, r as getPortableDid, s as isPortableId, t as getCanonicalPortableId } from "./portable-key-id-Bva5iT3W.mjs";
8
+ import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-Dwm4VswT.mjs";
8
9
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
9
- import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-l0B9nREb.mjs";
10
- import { a as verifyObject, n as hasProofLike, o as verifyPortableObjectProof, r as signObject } from "./proof-CVL7JnZd.mjs";
11
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-CCJ97Jql.mjs";
12
- import { t as getAuthenticatedDocumentLoader } from "./docloader-dA0RswUV.mjs";
13
- import { n as kvCache } from "./kv-cache-Bwwbh-xR.mjs";
10
+ import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-BYZOoDzZ.mjs";
11
+ import { i as signObject, l as verifyPortableObjectProofWithRoot, o as verifyObject, r as hasProofLike, s as verifyPortableObjectProof, t as InvalidPortableObjectIdError } from "./proof-DVXC6nYz.mjs";
12
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-B2ftY0Ha.mjs";
13
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-DJKcsAiF.mjs";
14
+ import { n as kvCache } from "./kv-cache-D0yYukqk.mjs";
14
15
  import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-DpnpgjyX.mjs";
15
16
  import { t as nodeInfoToJson } from "./types-DE_LV1JB.mjs";
16
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DGbYmXqU.mjs";
17
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-Ejy1jOz9.mjs";
18
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-i3jxVe9m.mjs";
17
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-Cgx2Dc7I.mjs";
18
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-D-hOvYKy.mjs";
19
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-Ld4Y9ymR.mjs";
19
20
  import { t as CircuitBreaker } from "./circuit-breaker-C5NqoLBJ.mjs";
20
21
  import { t as buildCollectionSynchronizationHeader } from "./collection-CnnP1UAv.mjs";
21
- import { a as verifyCompoundPortableObjectProofs, i as inspectCompoundPortableObjectApplicability, r as findUnsupportedCompoundProofShape, t as containsCompoundPortableObject } from "./compound-proof-Cayy-ECj.mjs";
22
+ import { a as verifyCompoundPortableObjectProofs, i as inspectCompoundPortableObjectApplicability, r as findUnsupportedCompoundProofShape, t as containsCompoundPortableObject } from "./compound-proof-CTx_lewQ.mjs";
22
23
  import { t as KvKeyCache } from "./keycache-BUDHB5rY.mjs";
23
24
  import { t as acceptsJsonLd } from "./negotiation-CCocWT_N.mjs";
24
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-DNJ1cNpr.mjs";
25
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-CqpKGEPk.mjs";
25
26
  import { t as createExponentialBackoffPolicy } from "./retry-zX5xw5e0.mjs";
26
27
  import { t as TaskCodec } from "./codec-C6rTrpIp.mjs";
27
28
  import { getLogger, withContext } from "@logtape/logtape";
@@ -30,8 +31,9 @@ import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey,
30
31
  import { lookupWebFinger } from "@fedify/webfinger";
31
32
  import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "@opentelemetry/api";
32
33
  import { uniq } from "es-toolkit";
33
- import { FetchError, canonicalizePortableUri, decodeMultibase, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, haveSameFe34Origin, isGatewayUrl, parseDigestMultibase, parseHashlink, parseIri, toCompatibleEf61Id } from "@fedify/vocab-runtime";
34
+ import { FetchError, canonicalizePortableUri, decodeMultibase, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, isGatewayUrl, parseDigestMultibase, parseHashlink, parseIri, toCompatibleEf61Id } from "@fedify/vocab-runtime";
34
35
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
36
+ import { isCompatibleEf61Iri } from "@fedify/vocab-runtime/internal/portable-dereference";
35
37
  import jsonld from "@fedify/vocab-runtime/jsonld";
36
38
  import { DataPointType, MeterProvider as MeterProvider$1, MetricReader } from "@opentelemetry/sdk-metrics";
37
39
  import { domainToASCII } from "node:url";
@@ -789,14 +791,7 @@ async function handlePortableObject(request, { values, context, objectDispatcher
789
791
  } });
790
792
  }
791
793
  function isRequestedPortableObject(object, canonicalId) {
792
- if (object.id == null) return false;
793
- if (object.id.protocol !== "ap:" && object.id.protocol !== "ap+ef61:") return false;
794
- try {
795
- return canonicalizePortableUri(formatIri(object.id)) === canonicalId;
796
- } catch (error) {
797
- if (error instanceof TypeError) return false;
798
- throw error;
799
- }
794
+ return object.id != null && getCanonicalPortableId(object.id) === canonicalId;
800
795
  }
801
796
  async function getJsonLdRootId(jsonLd, contextLoader) {
802
797
  const expanded = await jsonld.expand(jsonLd, {
@@ -808,6 +803,7 @@ async function getJsonLdRootId(jsonLd, contextLoader) {
808
803
  return typeof id === "string" ? id : null;
809
804
  }
810
805
  function isRequestedPortableId(id, canonicalId) {
806
+ if (!/^ap(?:\+ef61)?:\/\//i.test(id)) return URL.canParse(id) && getCanonicalPortableId(new URL(id)) === canonicalId;
811
807
  try {
812
808
  return canonicalizePortableUri(id) === canonicalId;
813
809
  } catch (error) {
@@ -858,13 +854,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
858
854
  * @param parameters The parameters for handling the collection.
859
855
  * @returns A promise that resolves to an HTTP response.
860
856
  */
861
- async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
862
- const spanName = name$1.trim().replace(/\s+/g, "_");
857
+ async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
858
+ const spanName = name$2.trim().replace(/\s+/g, "_");
863
859
  tracerProvider = tracerProvider ?? trace.getTracerProvider();
864
860
  const tracer = tracerProvider.getTracer(name, version);
865
861
  const cursor = new URL(request.url).searchParams.get("cursor");
866
862
  const metricBase = {
867
- kind: getCollectionMetricKind(name$1),
863
+ kind: getCollectionMetricKind(name$2),
868
864
  page: cursor != null,
869
865
  dispatcher: "built_in"
870
866
  };
@@ -905,7 +901,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
905
901
  span.setStatus({ code: SpanStatusCode.ERROR });
906
902
  return await onNotFound(request);
907
903
  }
908
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
904
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
909
905
  itemCount = items.length;
910
906
  span.setAttribute("fedify.collection.items", itemCount);
911
907
  return items;
@@ -945,7 +941,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
945
941
  } else {
946
942
  const uri = new URL(baseUri);
947
943
  uri.searchParams.set("cursor", cursor);
948
- const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
944
+ const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
949
945
  kind: SpanKind.SERVER,
950
946
  attributes: {
951
947
  "activitypub.collection.id": uri.href,
@@ -961,7 +957,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
961
957
  span.setStatus({ code: SpanStatusCode.ERROR });
962
958
  return await onNotFound(request);
963
959
  }
964
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
960
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
965
961
  itemCount = items.length;
966
962
  span.setAttribute("fedify.collection.items", itemCount);
967
963
  return {
@@ -1670,7 +1666,7 @@ async function handleInboxInternal(request, parameters, span) {
1670
1666
  return await respondInvalidActivity(error);
1671
1667
  }
1672
1668
  activityVerified = true;
1673
- if (!skipSignatureVerification && hasPortableActor(activity)) try {
1669
+ if (!skipSignatureVerification && isPortableActivity(activity)) try {
1674
1670
  proofVerified = await verifyObject(Activity, jsonWithoutSig, {
1675
1671
  contextLoader: wrapContextLoaderForJsonLd(ctx.contextLoader),
1676
1672
  documentLoader: ctx.documentLoader,
@@ -1854,7 +1850,7 @@ async function handleInboxInternal(request, parameters, span) {
1854
1850
  "http_signatures.verified": httpSigKey != null,
1855
1851
  "http_signatures.key_id": httpSigKey?.id?.href ?? ""
1856
1852
  });
1857
- if (!skipSignatureVerification && !proofVerified && (hasPortableActor(activity) || isPortableGatewayKey(httpSigKey))) {
1853
+ if (!skipSignatureVerification && !proofVerified && (isPortableActivity(activity) || isPortableGatewayKey(httpSigKey))) {
1858
1854
  if (deferredLdSignatureError != null) throw deferredLdSignatureError;
1859
1855
  logger.error("The activity {activityId} of the portable actor {actorId} is not authenticated by a valid Object Integrity Proof.", {
1860
1856
  activity: json,
@@ -1872,6 +1868,32 @@ async function handleInboxInternal(request, parameters, span) {
1872
1868
  headers: { "Content-Type": "text/plain; charset=utf-8" }
1873
1869
  });
1874
1870
  }
1871
+ if (!skipSignatureVerification && activity.id != null && isPortableId(activity.id)) {
1872
+ const rejection = await verifyPortableActivityId(activity.id, jsonWithoutSig, {
1873
+ contextLoader: wrapContextLoaderForJsonLd(ctx.contextLoader),
1874
+ documentLoader: ctx.documentLoader,
1875
+ keyCache,
1876
+ meterProvider,
1877
+ tracerProvider
1878
+ });
1879
+ if (rejection != null) {
1880
+ if (deferredLdSignatureError != null) throw deferredLdSignatureError;
1881
+ logger.error("The portable activity {activityId} is not authenticated by an Object Integrity Proof of its own DID: {reason}", {
1882
+ activity: json,
1883
+ recipient,
1884
+ activityId: activity.id.href,
1885
+ reason: rejection
1886
+ });
1887
+ span.setStatus({
1888
+ code: SpanStatusCode.ERROR,
1889
+ message: `The portable activity (${activity.id.href}) is not authenticated by an Object Integrity Proof of its own DID.`
1890
+ });
1891
+ return new Response("Portable activities must have valid Object Integrity Proofs made by their own DIDs.", {
1892
+ status: 401,
1893
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
1894
+ });
1895
+ }
1896
+ }
1875
1897
  if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
1876
1898
  if (deferredLdSignatureError != null) throw deferredLdSignatureError;
1877
1899
  getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("actorKeyMismatch", httpSigKey.id == null ? void 0 : getRemoteHost(httpSigKey.id));
@@ -2109,8 +2131,8 @@ var CustomCollectionHandler = class {
2109
2131
  * @param CollectionPage The CollectionPage constructor.
2110
2132
  * @param filterPredicate Optional filter predicate for items.
2111
2133
  */
2112
- constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
2113
- this.name = name$2;
2134
+ constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
2135
+ this.name = name$1;
2114
2136
  this.values = values;
2115
2137
  this.context = context;
2116
2138
  this.callbacks = callbacks;
@@ -2601,7 +2623,41 @@ const MIN_COMPONENTS = [
2601
2623
  * establish.
2602
2624
  */
2603
2625
  function isPortableGatewayKey(key) {
2604
- return key?.id != null && isCompatibleKeyId(key.id) && key.ownerId != null && isPortableUri(key.ownerId);
2626
+ return key?.id != null && isCompatibleKeyId(key.id) && key.ownerId != null && isPortableId(key.ownerId);
2627
+ }
2628
+ /**
2629
+ * Checks whether an activity needs an Object Integrity Proof by its DID:
2630
+ * either it is performed by an [FEP-ef61] portable actor, or its own ID is
2631
+ * portable. Both `ap:` URIs and compatible identifiers count as portable.
2632
+ *
2633
+ * [FEP-ef61]: https://w3id.org/fep/ef61
2634
+ */
2635
+ function isPortableActivity(activity) {
2636
+ return hasPortableActor(activity) || activity.id != null && isPortableId(activity.id);
2637
+ }
2638
+ /**
2639
+ * Verifies that a portable activity's own ID belongs to the DID that signed
2640
+ * it, on the JSON-LD document received. The ID the proof policy checks has
2641
+ * to be the parsed activity's ID, so that a remote context that changes
2642
+ * between loads cannot make the two name different objects.
2643
+ * @returns `null` if the ID is verified, or the reason why it is not.
2644
+ */
2645
+ async function verifyPortableActivityId(activityId, jsonLd, options) {
2646
+ const expectedId = getCanonicalPortableId(activityId);
2647
+ if (expectedId == null) return "malformed portable ID";
2648
+ let verification;
2649
+ try {
2650
+ verification = await verifyPortableObjectProofWithRoot(jsonLd, options);
2651
+ } catch (error) {
2652
+ if (error instanceof InvalidPortableObjectIdError) return "malformed portable ID";
2653
+ if (!isPermanentActivityParseError(error)) throw error;
2654
+ return "malformed document";
2655
+ }
2656
+ const { result, root } = verification;
2657
+ if (!result.verified) return result.reason.type;
2658
+ const rootId = root?.["@id"];
2659
+ if (typeof rootId !== "string" || getCanonicalPortableId(parseIri(rootId)) !== expectedId) return "the verified document has another ID";
2660
+ return null;
2605
2661
  }
2606
2662
  //#endregion
2607
2663
  //#region src/federation/portable-inbox.ts
@@ -2649,16 +2705,17 @@ function resolvePortableInboxRecipient(actor, { authority, canonicalInboxId, loc
2649
2705
  reason: "notFound"
2650
2706
  };
2651
2707
  const id = actor.id;
2652
- if (id == null || id.protocol !== "ap:" && id.protocol !== "ap+ef61:") return {
2708
+ const did = id == null || !isPortableId(id) ? null : getPortableDid(id);
2709
+ if (id == null || did == null) return {
2653
2710
  status: "rejected",
2654
2711
  reason: "notPortable"
2655
2712
  };
2656
- if (!isSameAuthority(id, authority)) return {
2713
+ if (did !== authority) return {
2657
2714
  status: "rejected",
2658
2715
  reason: "authorityMismatch"
2659
2716
  };
2660
- const inboxId = actor.inboxId;
2661
- if (inboxId == null || canonicalize(inboxId) !== canonicalInboxId) return {
2717
+ const inboxId = actor.inboxId == null ? null : toPortableUri(actor.inboxId);
2718
+ if (inboxId == null || getCanonicalPortableId(inboxId) !== canonicalInboxId) return {
2662
2719
  status: "rejected",
2663
2720
  reason: "inboxMismatch"
2664
2721
  };
@@ -2670,23 +2727,22 @@ function resolvePortableInboxRecipient(actor, { authority, canonicalInboxId, loc
2670
2727
  return {
2671
2728
  status: "accepted",
2672
2729
  recipient: {
2730
+ actorId: id,
2673
2731
  inboxId,
2674
2732
  canonicalInboxId,
2675
2733
  gateways
2676
2734
  }
2677
2735
  };
2678
2736
  }
2679
- function isSameAuthority(id, authority) {
2680
- try {
2681
- return getFe34Origin(id) === authority;
2682
- } catch (error) {
2683
- if (error instanceof TypeError) return false;
2684
- throw error;
2685
- }
2686
- }
2687
- function canonicalize(iri) {
2737
+ /**
2738
+ * Gets the portable form of an `ap:` or `ap+ef61:` URI or a compatible
2739
+ * identifier, keeping its query.
2740
+ * @returns The portable URI, or `null` if the ID is neither, or is malformed.
2741
+ */
2742
+ function toPortableUri(id) {
2743
+ if (isPortableUri(id)) return id;
2688
2744
  try {
2689
- return canonicalizePortableUri(typeof iri === "string" ? iri : formatIri(iri));
2745
+ return fromCompatibleEf61Id(id);
2690
2746
  } catch (error) {
2691
2747
  if (error instanceof TypeError) return null;
2692
2748
  throw error;
@@ -2703,8 +2759,11 @@ function canonicalize(iri) {
2703
2759
  * Forwarding is therefore best effort. Without {@link KvStore.cas}, nothing is
2704
2760
  * forwarded.
2705
2761
  *
2706
- * Forwarded requests are not signed with HTTP Signatures; the receiving
2707
- * gateways authenticate the activity by its own proof.
2762
+ * Forwarded requests are signed with HTTP Signatures by the RSA key among
2763
+ * {@link ForwardPortableInboxActivityParameters.getKeys}, if any, so that
2764
+ * servers requiring HTTP Signatures accept them, and are sent unsigned
2765
+ * otherwise. Either way, the receiving gateways authenticate the activity by
2766
+ * its own proof.
2708
2767
  * @param parameters The parameters.
2709
2768
  * @returns The target inbox URLs that the activity was handed off to.
2710
2769
  */
@@ -2717,7 +2776,7 @@ async function forwardPortableInboxActivity(parameters) {
2717
2776
  const { recipient, activityId, excludedOrigins, kv, kvPrefix, outboxQueue } = parameters;
2718
2777
  const { maxTargets, ttl } = parameters.options ?? resolvePortableInboxForwardingOptions();
2719
2778
  if (kv.cas == null || maxTargets < 1) return [];
2720
- const canonicalActivityId = canonicalize(activityId) ?? activityId.href;
2779
+ const canonicalActivityId = getCanonicalPortableId(activityId) ?? activityId.href;
2721
2780
  const targets = getForwardingTargets(recipient, excludedOrigins);
2722
2781
  if (targets.length > maxTargets) {
2723
2782
  logger.warn("The portable actor that owns the inbox {inbox} has more than {max} other gateways; the activity {activityId} is forwarded only to the first {max} of them.", {
@@ -2776,20 +2835,59 @@ function getForwardingTargets(recipient, excludedOrigins) {
2776
2835
  }
2777
2836
  return targets;
2778
2837
  }
2779
- async function forwardImmediately({ activity, activityId, activityType, allowPrivateAddress, options, meterProvider, tracerProvider }, inboxes) {
2838
+ /**
2839
+ * Resolves the key that signs forwarded requests: the first RSASSA-PKCS1-v1_5
2840
+ * key, as {@link sendActivity} signs requests only with such a key. Since
2841
+ * the targets have already been claimed, the activity is forwarded unsigned
2842
+ * rather than not at all if the key cannot be resolved or used.
2843
+ */
2844
+ async function resolveForwardingKey({ getKeys, activityId }) {
2845
+ if (getKeys == null) return null;
2846
+ const logger = getLogger([
2847
+ "fedify",
2848
+ "federation",
2849
+ "inbox"
2850
+ ]);
2851
+ let key;
2852
+ try {
2853
+ key = (await getKeys()).find((k) => k.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5");
2854
+ } catch (error) {
2855
+ logger.error("Failed to get the gateway keys to sign forwarded requests with; forwarding activity {activityId} without HTTP Signatures:\n{error}", {
2856
+ activityId: activityId.href,
2857
+ error
2858
+ });
2859
+ return null;
2860
+ }
2861
+ if (key == null) return null;
2862
+ try {
2863
+ validateCryptoKey(key.privateKey, "private");
2864
+ } catch (error) {
2865
+ if (!(error instanceof TypeError)) throw error;
2866
+ logger.warn("The gateway key {keyId} cannot sign forwarded requests; forwarding activity {activityId} without HTTP Signatures:\n{error}", {
2867
+ keyId: key.keyId.href,
2868
+ activityId: activityId.href,
2869
+ error
2870
+ });
2871
+ return null;
2872
+ }
2873
+ return key;
2874
+ }
2875
+ async function forwardImmediately(parameters, inboxes) {
2876
+ const { activity, activityId, activityType, allowPrivateAddress, specDeterminer, options, meterProvider, tracerProvider } = parameters;
2780
2877
  const logger = getLogger([
2781
2878
  "fedify",
2782
2879
  "federation",
2783
2880
  "inbox"
2784
2881
  ]);
2785
2882
  const deadline = (options ?? resolvePortableInboxForwardingOptions()).deadline.total("millisecond");
2786
- const sends = inboxes.map((inbox) => sendActivity({
2883
+ const forwarding = resolveForwardingKey(parameters).then((key) => Promise.all(inboxes.map((inbox) => sendActivity({
2787
2884
  activity,
2788
2885
  activityId: activityId.href,
2789
2886
  activityType,
2790
- keys: [],
2887
+ keys: key == null ? [] : [key],
2791
2888
  inbox,
2792
2889
  allowPrivateAddress,
2890
+ specDeterminer,
2793
2891
  meterProvider,
2794
2892
  tracerProvider
2795
2893
  }).catch((error) => {
@@ -2798,9 +2896,9 @@ async function forwardImmediately({ activity, activityId, activityType, allowPri
2798
2896
  inbox: inbox.href,
2799
2897
  error
2800
2898
  });
2801
- }));
2899
+ }))));
2802
2900
  let timer;
2803
- const timedOut = await Promise.race([Promise.all(sends).then(() => false), new Promise((resolve) => {
2901
+ const timedOut = await Promise.race([forwarding.then(() => false), new Promise((resolve) => {
2804
2902
  timer = setTimeout(() => resolve(true), deadline);
2805
2903
  })]);
2806
2904
  clearTimeout(timer);
@@ -2809,12 +2907,27 @@ async function forwardImmediately({ activity, activityId, activityType, allowPri
2809
2907
  deadline
2810
2908
  });
2811
2909
  }
2812
- async function enqueueForwarding({ activity, activityId, activityType, baseUrl, startQueue, meterProvider }, outboxQueue, inboxes) {
2910
+ async function enqueueForwarding(parameters, outboxQueue, inboxes) {
2911
+ const { activity, activityId, activityType, baseUrl, startQueue, meterProvider } = parameters;
2813
2912
  const logger = getLogger([
2814
2913
  "fedify",
2815
2914
  "federation",
2816
2915
  "inbox"
2817
2916
  ]);
2917
+ const key = await resolveForwardingKey(parameters);
2918
+ const keys = [];
2919
+ if (key != null) try {
2920
+ keys.push({
2921
+ keyId: key.keyId.href,
2922
+ privateKey: await exportJwk(key.privateKey)
2923
+ });
2924
+ } catch (error) {
2925
+ logger.error("Failed to export the gateway key {keyId}; forwarding activity {activityId} without HTTP Signatures:\n{error}", {
2926
+ keyId: key.keyId.href,
2927
+ activityId: activityId.href,
2928
+ error
2929
+ });
2930
+ }
2818
2931
  startQueue?.();
2819
2932
  const started = (/* @__PURE__ */ new Date()).toISOString();
2820
2933
  const traceContext = {};
@@ -2824,7 +2937,7 @@ async function enqueueForwarding({ activity, activityId, activityType, baseUrl,
2824
2937
  type: "outbox",
2825
2938
  id: crypto.randomUUID(),
2826
2939
  baseUrl,
2827
- keys: [],
2940
+ keys,
2828
2941
  activity,
2829
2942
  activityId: activityId.href,
2830
2943
  activityType,
@@ -2850,34 +2963,50 @@ async function enqueueForwarding({ activity, activityId, activityType, baseUrl,
2850
2963
  }
2851
2964
  //#endregion
2852
2965
  //#region src/federation/outgoing-proof.ts
2853
- function isPortableUrl(url) {
2854
- return url.protocol === "ap:" || url.protocol === "ap+ef61:";
2855
- }
2856
2966
  function formatKeyIds(candidates) {
2857
2967
  return candidates.map((c) => c.verificationMethod.href).join(", ");
2858
2968
  }
2859
2969
  /**
2860
2970
  * Rejects an activity of a portable actor whose ID cannot be authenticated by
2861
2971
  * the actor's DID: FEP-ef61 requires the activity to be a portable object
2862
- * signed by that DID, so its ID has to be a portable ID with the same DID.
2972
+ * signed by that DID, so its ID has to be a portable ID, i.e., an `ap:` or
2973
+ * `ap+ef61:` URI or a compatible identifier, with the same DID. A portable
2974
+ * actor is one whose ID is such an ID as well.
2863
2975
  * @throws {TypeError} If the activity is performed by a portable actor, but
2864
- * its ID is not a portable ID of the actor's DID, or its
2865
- * portable actors do not share a DID.
2976
+ * its ID is not a portable ID of the actor's DID, its
2977
+ * portable actors do not share a DID, or the ID of one of
2978
+ * them is a malformed compatible identifier.
2866
2979
  * @internal
2867
2980
  */
2868
2981
  function assertPortableActorActivity(activity) {
2869
- const portableActors = activity.actorIds.filter(isPortableUrl);
2982
+ const portableActors = activity.actorIds.filter((id) => isPortableId(id));
2870
2983
  if (portableActors.length < 1) return;
2871
- const did = getFe34Origin(portableActors[0]);
2872
- if (portableActors.some((actorId) => getFe34Origin(actorId) !== did)) throw new TypeError(`The activity ${activity.id?.href} has portable actors with different DIDs (${portableActors.map((a) => a.href).join(", ")}); a portable activity is signed by a single DID.`);
2873
- if (activity.id == null || !isPortableUrl(activity.id) || getFe34Origin(activity.id) !== did) throw new TypeError(`The activity ${activity.id?.href} is performed by the portable actor ${portableActors[0].href}, so its ID has to be an ap: or ap+ef61: URI with the same DID (${did}), as FEP-ef61 requires it to carry an Object Integrity Proof made by that DID.`);
2984
+ const dids = portableActors.map((actorId) => {
2985
+ const did = getPortableDid(actorId);
2986
+ if (did == null) throw new TypeError(`The activity ${activity.id?.href} is performed by the actor ${actorId.href}, whose ID is a malformed FEP-ef61 portable ID. A compatible identifier must have a valid DID and an object path, and must not have credentials or @gateway location hints.`);
2987
+ return did;
2988
+ });
2989
+ const did = dids[0];
2990
+ if (dids.some((d) => d !== did)) throw new TypeError(`The activity ${activity.id?.href} has portable actors with different DIDs (${portableActors.map((a) => a.href).join(", ")}); a portable activity is signed by a single DID.`);
2991
+ if (activity.id == null || !isPortableId(activity.id) || getPortableDid(activity.id) !== did) throw new TypeError(`The activity ${activity.id?.href} is performed by the portable actor ${portableActors[0].href}, so its ID has to be an ap: or ap+ef61: URI, or an FEP-ef61 compatible identifier, with the same DID (${did}), as FEP-ef61 requires it to carry an Object Integrity Proof made by that DID.`);
2992
+ if (!isCompatibleEf61Iri(activity.id)) return;
2993
+ const mismatched = portableActors.find((actorId) => isCompatibleEf61Iri(actorId) && actorId.origin !== activity.id?.origin);
2994
+ if (mismatched == null) return;
2995
+ getLogger([
2996
+ "fedify",
2997
+ "federation",
2998
+ "outbox"
2999
+ ]).warn("The activity {activityId} and its actor {actorId} are identified by FEP-ef61 compatible identifiers on different gateways. FEP-ef61 requires publishers to use the first gateway in the actor's gateways when constructing compatible identifiers.", {
3000
+ activityId: activity.id.href,
3001
+ actorId: mismatched.href
3002
+ });
2874
3003
  }
2875
3004
  /**
2876
3005
  * Creates the Object Integrity Proofs Fedify attaches to an outgoing activity.
2877
3006
  *
2878
3007
  * Keys whose IDs are FEP-ef61 compatible identifiers are gateway keys, which
2879
3008
  * never sign proofs. A portable activity, i.e., one with an `ap:` or
2880
- * `ap+ef61:` ID, that carries no proof is signed only by the one Ed25519 key
3009
+ * `ap+ef61:` ID or a compatible identifier, that carries no proof is signed only by the one Ed25519 key
2881
3010
  * whose verification method is a DID URL for its DID, even if it is the only
2882
3011
  * key; if no key or more than one key qualifies, this function throws.
2883
3012
  *
@@ -2916,7 +3045,7 @@ async function signOutgoingActivity(activity, candidates, options) {
2916
3045
  break;
2917
3046
  }
2918
3047
  const keys = candidates.filter((c) => c.privateKey.algorithm.name === "Ed25519" && !isCompatibleKeyId(c.verificationMethod));
2919
- if (!hasProof && activity.id != null && isPortableUrl(activity.id)) return await sign(selectPortableActivityKey(activity, activity.id, keys));
3048
+ if (!hasProof && activity.id != null && isPortableId(activity.id)) return await sign(selectPortableActivityKey(activity, activity.id, keys));
2920
3049
  if (keys.length < 1 || hasProof && !options.appendToExistingProofs) return {
2921
3050
  activity,
2922
3051
  hasProof,
@@ -2949,8 +3078,9 @@ async function signOutgoingActivity(activity, candidates, options) {
2949
3078
  * @throws {TypeError} If no key or more than one key qualifies.
2950
3079
  */
2951
3080
  function selectPortableActivityKey(activity, activityId, keys) {
2952
- const activityDid = getFe34Origin(activityId);
2953
- const eligible = keys.filter((c) => c.verificationMethod.protocol === "did:" && haveSameFe34Origin(activityId, c.verificationMethod));
3081
+ const activityDid = getPortableDid(activityId);
3082
+ if (activityDid == null) throw new TypeError(`Cannot sign the portable activity ${activityId.href}, as its ID is a malformed FEP-ef61 portable ID. A compatible identifier must have a valid DID and an object path, and must not have credentials or @gateway location hints.`);
3083
+ const eligible = keys.filter((c) => c.verificationMethod.protocol === "did:" && getPortableDid(c.verificationMethod) === activityDid);
2954
3084
  if (eligible.length !== 1) throw new TypeError(`Cannot choose an Object Integrity Proof key for the portable activity ${activityId.href}: ` + (eligible.length < 1 ? `none of its ${keys.length} Ed25519 keys (${formatKeyIds(keys)}) ` : `${eligible.length} of its Ed25519 keys (${formatKeyIds(eligible)}) `) + `${eligible.length < 1 ? "is" : "are"} a DID URL verification method for ${activityDid}. FEP-ef61 requires a portable activity's proof to be made by its DID, and the map-local compound-proof profile accepts exactly one direct proof per map. Gateway keys, whose IDs are compatible identifiers, never sign proofs. Supply exactly one Ed25519 key whose key ID is a DID URL for ${activityDid}, or sign the activity with signObject() before sending it.`);
2955
3085
  getLogger([
2956
3086
  "fedify",
@@ -3197,6 +3327,27 @@ function getWebFingerSubjectAndAliases({ resourceUrl, actorUri, preferredUsernam
3197
3327
  };
3198
3328
  }
3199
3329
  /**
3330
+ * Gets the compatible identifier that a WebFinger response links to for
3331
+ * an FEP-ef61 portable actor. An actor identified by an `ap:` or `ap+ef61:`
3332
+ * URI is linked through its compatible identifier on the given gateway, while
3333
+ * an actor identified by a compatible identifier is linked through its ID as
3334
+ * is, so that software without FEP-ef61 support finds the same ID in the actor
3335
+ * document.
3336
+ * @param actorId The portable actor's ID.
3337
+ * @param gateway The actor's first gateway.
3338
+ * @returns The compatible identifier, or `null` if the actor ID is malformed
3339
+ * or cannot be represented as a compatible identifier.
3340
+ */
3341
+ function getCompatibleActorId(actorId, gateway) {
3342
+ try {
3343
+ if (isPortableUri(actorId)) return toCompatibleEf61Id(actorId, gateway);
3344
+ return fromCompatibleEf61Id(actorId) == null ? null : actorId;
3345
+ } catch (error) {
3346
+ if (error instanceof TypeError) return null;
3347
+ throw error;
3348
+ }
3349
+ }
3350
+ /**
3200
3351
  * Computes the subject and aliases for an FEP-ef61 portable actor, whose
3201
3352
  * WebFinger address takes its domain from the first gateway of the actor
3202
3353
  * rather than from the actor ID. The canonical `ap:` ID is not emitted,
@@ -3360,21 +3511,23 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
3360
3511
  });
3361
3512
  let actorUri = context.getActorUri(identifier);
3362
3513
  let portable;
3363
- if (actor.id != null && (actor.id.protocol === "ap:" || actor.id.protocol === "ap+ef61:")) {
3514
+ if (actor.id != null && isPortableId(actor.id)) {
3364
3515
  const gateway = actor.gateway;
3365
- let compatibleId;
3366
- if (gateway != null && isGatewayUrl(gateway)) try {
3367
- compatibleId = toCompatibleEf61Id(actor.id, gateway);
3368
- } catch (error) {
3369
- if (!(error instanceof TypeError)) throw error;
3370
- }
3371
- if (gateway == null || compatibleId == null) {
3516
+ if (gateway == null || !isGatewayUrl(gateway)) {
3372
3517
  logger.error("The portable actor {actorId} (identifier: {identifier}) needs an HTTP(S) origin as the first item of its gateways property to be discovered through WebFinger.", {
3373
3518
  actorId: formatIri(actor.id),
3374
3519
  identifier
3375
3520
  });
3376
3521
  return await onNotFound(request);
3377
3522
  }
3523
+ const compatibleId = getCompatibleActorId(actor.id, gateway);
3524
+ if (compatibleId == null) {
3525
+ logger.error("The portable actor {actorId} (identifier: {identifier}) cannot be discovered through WebFinger, as its ID is malformed or cannot be represented as an FEP-ef61 compatible identifier.", {
3526
+ actorId: formatIri(actor.id),
3527
+ identifier
3528
+ });
3529
+ return await onNotFound(request);
3530
+ }
3378
3531
  actorUri = compatibleId;
3379
3532
  portable = {
3380
3533
  compatibleId,
@@ -5325,6 +5478,8 @@ var FederationImpl = class extends FederationBuilderImpl {
5325
5478
  outboxQueue: this.outboxQueue,
5326
5479
  startQueue: this.manuallyStartQueue ? void 0 : () => this._startQueueInternal(contextData),
5327
5480
  allowPrivateAddress: this.allowPrivateAddress,
5481
+ getKeys: () => this.#getPortableGatewayKeyPairs(context, identifier, recipient),
5482
+ specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
5328
5483
  options: this.portableInboxForwarding,
5329
5484
  meterProvider: this.meterProvider,
5330
5485
  tracerProvider: this.tracerProvider
@@ -5333,6 +5488,49 @@ var FederationImpl = class extends FederationBuilderImpl {
5333
5488
  }
5334
5489
  });
5335
5490
  }
5491
+ /**
5492
+ * Gets this server's gateway key pairs for the portable actor that owns
5493
+ * a portable inbox, which sign the activities forwarded from the inbox.
5494
+ * @param context The context.
5495
+ * @param identifier The identifier of the portable actor.
5496
+ * @param recipient The portable inbox.
5497
+ * @returns The key pairs, or an empty array if the actor has no gateway
5498
+ * keys on this server.
5499
+ */
5500
+ async #getPortableGatewayKeyPairs(context, identifier, recipient) {
5501
+ const logger = getLogger([
5502
+ "fedify",
5503
+ "federation",
5504
+ "inbox"
5505
+ ]);
5506
+ if (this.actorCallbacks?.keyPairsDispatcher == null || this.actorCallbacks.portableActorIdMapper == null) {
5507
+ logger.debug("Forwarding activities from the portable inbox {inbox} without HTTP Signatures, as gateway keys need both a key pairs dispatcher and a portable actor ID mapper.", { inbox: recipient.canonicalInboxId });
5508
+ return [];
5509
+ }
5510
+ const actorId = getCanonicalPortableId(recipient.actorId);
5511
+ if (actorId == null) return [];
5512
+ const keyPairs = await context.getActorKeyPairs(identifier);
5513
+ for (const { cryptographicKey } of keyPairs) {
5514
+ const owner = cryptographicKey.ownerId;
5515
+ const canonicalOwner = owner == null ? null : getCanonicalPortableId(owner);
5516
+ if (canonicalOwner === actorId) continue;
5517
+ if (canonicalOwner == null) logger.debug("Forwarding activities from the portable inbox {inbox} without HTTP Signatures, as the key pairs of the actor {identifier} are not the gateway keys of a portable actor.", {
5518
+ inbox: recipient.canonicalInboxId,
5519
+ identifier
5520
+ });
5521
+ else logger.warn("Forwarding activities from the portable inbox {inbox} without HTTP Signatures, as the key pairs of the actor {identifier} are the gateway keys of {owner}, not of the recipient {actorId}.", {
5522
+ inbox: recipient.canonicalInboxId,
5523
+ identifier,
5524
+ owner: canonicalOwner,
5525
+ actorId
5526
+ });
5527
+ return [];
5528
+ }
5529
+ return keyPairs.map(({ keyId, privateKey }) => ({
5530
+ keyId,
5531
+ privateKey
5532
+ }));
5533
+ }
5336
5534
  async #fetchHashlinkMedia(request, media, { onNotFound, contextData, span, metricState }) {
5337
5535
  metricState.endpoint = "hashlink_media";
5338
5536
  metricState.routeTemplate = HASHLINK_MEDIA_ROUTE_TEMPLATE;
@@ -6564,4 +6762,4 @@ function getRequestId(request) {
6564
6762
  return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
6565
6763
  }
6566
6764
  //#endregion
6567
- export { actorDehydrator as C, handleNodeInfoJrd as S, respondWithObjectIfAcceptable as _, OutboxContextImpl as a, handleBenchmarkTrigger as b, forwardPortableInboxActivity as c, handleCollection as d, handleCustomCollection as f, respondWithObject as g, handleOutbox as h, KvSpecDeterminer as i, resolvePortableInboxForwardingOptions as l, handleObject as m, FederationImpl as n, createFederation as o, handleInbox as p, InboxContextImpl as r, handleWebFinger as s, ContextImpl as t, handleActor as u, PORTABLE_OBJECT_CONTENT_TYPE as v, autoIdAssigner as w, handleNodeInfo as x, parseHashlinkGatewayRequest as y };
6765
+ export { handleNodeInfoJrd as C, handleNodeInfo as S, autoIdAssigner as T, respondWithObject as _, OutboxContextImpl as a, parseHashlinkGatewayRequest as b, assertPortableActorActivity as c, handleActor as d, handleCollection as f, handleOutbox as g, handleObject as h, KvSpecDeterminer as i, forwardPortableInboxActivity as l, handleInbox as m, FederationImpl as n, createFederation as o, handleCustomCollection as p, InboxContextImpl as r, handleWebFinger as s, ContextImpl as t, resolvePortableInboxForwardingOptions as u, respondWithObjectIfAcceptable as v, actorDehydrator as w, handleBenchmarkTrigger as x, PORTABLE_OBJECT_CONTENT_TYPE as y };