@fedify/fedify 2.5.0-dev.2378 → 2.5.0-dev.2424

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 (92) hide show
  1. package/dist/{builder-J1K0IJj6.mjs → builder-crKu0U3j.mjs} +2 -2
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{compound-proof-DtmVrMV7.mjs → compound-proof-D5pMfQau.mjs} +2 -2
  6. package/dist/{context-C2-UDo2c.d.ts → context-2wLkQrjb.d.ts} +11 -0
  7. package/dist/{context-BjD_CTxh.d.cts → context-DPocjp1l.d.cts} +11 -0
  8. package/dist/{deno-Ci6tSK9-.mjs → deno-Dgtb5dvg.mjs} +1 -1
  9. package/dist/{docloader-DZ9h6KJS.mjs → docloader-C8QI5jg2.mjs} +4 -2
  10. package/dist/federation/builder.test.mjs +1 -1
  11. package/dist/federation/compound-fanout.test.mjs +3 -3
  12. package/dist/federation/handler-compound-proof.test.mjs +5 -5
  13. package/dist/federation/handler.test.mjs +258 -5
  14. package/dist/federation/hashlink-media.test.mjs +2 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/inbox-report.test.mjs +30 -5
  17. package/dist/federation/inbox.test.mjs +43 -0
  18. package/dist/federation/metrics.test.mjs +1 -1
  19. package/dist/federation/middleware.test.mjs +254 -11
  20. package/dist/federation/mod.cjs +1 -1
  21. package/dist/federation/mod.d.cts +2 -2
  22. package/dist/federation/mod.d.ts +2 -2
  23. package/dist/federation/mod.js +1 -1
  24. package/dist/federation/outgoing-proof.test.mjs +4 -4
  25. package/dist/federation/portable-actor.test.mjs +3 -3
  26. package/dist/federation/portable-chain.test.mjs +3 -3
  27. package/dist/federation/portable-collection.test.mjs +4 -4
  28. package/dist/federation/portable-delivery.test.mjs +2 -2
  29. package/dist/federation/portable-gateway-keys.test.mjs +4 -4
  30. package/dist/federation/portable-inbox.test.mjs +4 -4
  31. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  32. package/dist/federation/portable-route-activity.test.mjs +2 -2
  33. package/dist/federation/portable.test.mjs +3 -3
  34. package/dist/federation/send.test.mjs +3 -3
  35. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  36. package/dist/federation/tasks/tasks.test.mjs +2 -2
  37. package/dist/federation/temporal.test.mjs +1 -1
  38. package/dist/federation/webfinger.test.mjs +1 -1
  39. package/dist/{federation-lzy7M3hT.cjs → federation-XZF9Yna_.cjs} +133 -21
  40. package/dist/{http-CFyizTHa.mjs → http-CO8l72H1.mjs} +4 -4
  41. package/dist/{http-Cmz7x6Iw.js → http-CRRQ6LBq.js} +1 -1
  42. package/dist/{http-D1RPHoq3.cjs → http-DZpLusNJ.cjs} +1 -1
  43. package/dist/inbox-q6uJubdj.mjs +188 -0
  44. package/dist/{kv-cache-rOQX3I3c.mjs → kv-cache-C-20uhXH.mjs} +1 -1
  45. package/dist/{kv-cache-C0-HuvwP.js → kv-cache-D5EHCk1_.js} +3 -1
  46. package/dist/{kv-cache-Jym5nP3J.cjs → kv-cache-DB0oTO06.cjs} +3 -1
  47. package/dist/{ld-DJ--ZUpr.mjs → ld-DqV2dhgT.mjs} +2 -2
  48. package/dist/{metrics-Dwgav7s_.mjs → metrics--5oGNIHa.mjs} +1 -1
  49. package/dist/{middleware-BbBsa5iR.mjs → middleware-BahtLJeT.mjs} +115 -180
  50. package/dist/{middleware-CJWxuUy5.mjs → middleware-Cna-mkwy.mjs} +1 -1
  51. package/dist/{middleware-CqgRIsWM.js → middleware-Mn7MeLDZ.js} +133 -21
  52. package/dist/{mod-BBPd4M_0.d.cts → mod-DKGoPoQC.d.cts} +1 -1
  53. package/dist/{mod-CUYBGKof.d.ts → mod-Dm-7RdhR.d.ts} +1 -1
  54. package/dist/mod.cjs +4 -4
  55. package/dist/mod.d.cts +2 -2
  56. package/dist/mod.d.ts +2 -2
  57. package/dist/mod.js +4 -4
  58. package/dist/nodeinfo/handler.test.mjs +1 -1
  59. package/dist/{owner-Btd7SwMj.mjs → owner-Cb6Kalag.mjs} +3 -3
  60. package/dist/{portable-collection-DwQT28O2.js → portable-collection-BweSVeOo.js} +1 -1
  61. package/dist/{portable-collection-BvWxS1sL.cjs → portable-collection-C3FBNHhB.cjs} +1 -1
  62. package/dist/{portable-collection-gb9V8XEO.mjs → portable-collection-DatZLGgt.mjs} +2 -2
  63. package/dist/{portable-key-Cwti99nP.mjs → portable-key-C2jzDc2S.mjs} +1 -1
  64. package/dist/{proof-Bwzv6mXZ.mjs → proof-BpQd-cat.mjs} +3 -3
  65. package/dist/{send-BrQYUSb4.mjs → send-CrgC-GYC.mjs} +3 -3
  66. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  67. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  68. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  69. package/dist/sig/compound-proof.test.mjs +2 -2
  70. package/dist/sig/http.test.mjs +2 -2
  71. package/dist/sig/key.test.mjs +1 -1
  72. package/dist/sig/ld.test.mjs +1 -1
  73. package/dist/sig/mitra-receive-interop.test.mjs +4 -4
  74. package/dist/sig/mitra-send-interop.test.mjs +3 -3
  75. package/dist/sig/mod.cjs +2 -2
  76. package/dist/sig/mod.js +2 -2
  77. package/dist/sig/owner.test.mjs +1 -1
  78. package/dist/sig/portable-collection.test.mjs +1 -1
  79. package/dist/sig/portable-interop.test.mjs +3 -3
  80. package/dist/sig/portable-key.test.mjs +5 -5
  81. package/dist/sig/proof.test.mjs +3 -3
  82. package/dist/sig/tootik-request-interop.test.mjs +4 -4
  83. package/dist/sig/tootik-send-interop.test.mjs +3 -3
  84. package/dist/sig/verification.test.mjs +3 -3
  85. package/dist/{temporal-BRaCTxVe.mjs → temporal-BjBxALiF.mjs} +1 -1
  86. package/dist/testing/kv.test.mjs +1 -1
  87. package/dist/testing/mod.d.mts +11 -0
  88. package/dist/utils/docloader.test.mjs +112 -37
  89. package/dist/utils/kv-cache.test.mjs +1 -1
  90. package/dist/utils/mod.cjs +1 -1
  91. package/dist/utils/mod.js +1 -1
  92. package/package.json +6 -6
@@ -4,27 +4,28 @@ globalThis.addEventListener = () => {};
4
4
  import { d as isPortableUri, f as isSameObjectId, i as getPortableDid, l as isPortableId, n as getCanonicalPortableId, o as hasPortableActor, r as getGatewayKeyBase, s as isCompatibleKeyId, t as getAuthenticationOrigin, u as isPortableKeyId } from "./portable-key-id-Ca30-hOa.mjs";
5
5
  import { n as isPubliclyAddressedNode, t as isInAudience } from "./audience-CHQ-FlLD.mjs";
6
6
  import { a as verificationObservation, r as snapshotKey, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
7
- import { n as version, t as name } from "./deno-Ci6tSK9-.mjs";
8
- 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-Dwgav7s_.mjs";
7
+ import { n as version, t as name } from "./deno-Dgtb5dvg.mjs";
8
+ 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--5oGNIHa.mjs";
9
9
  import { t as formatAcceptSignature } from "./accept-CPVqki78.mjs";
10
- import { T as validateCryptoKey, _ 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, w as importJwk, y as exportJwk } from "./ld-DJ--ZUpr.mjs";
10
+ import { T as validateCryptoKey, _ 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, w as importJwk, y as exportJwk } from "./ld-DqV2dhgT.mjs";
11
11
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
12
- import { c as verifyObject, d as verifyPortableObjectProofWithRoot, i as hasProofLike, l as verifyPortableObjectProof, o as signObject, t as InvalidPortableObjectIdError } from "./proof-Bwzv6mXZ.mjs";
13
- import { a as listRequestSignatures, c as selectRequestSignature, d as validateMaxSignatures, f as verifyRequest, p as verifyRequestDetailed, s as parseRfc9421SignatureInput } from "./http-CFyizTHa.mjs";
14
- import { t as getAuthenticatedDocumentLoader } from "./docloader-DZ9h6KJS.mjs";
15
- import { n as kvCache } from "./kv-cache-rOQX3I3c.mjs";
12
+ import { c as verifyObject, d as verifyPortableObjectProofWithRoot, i as hasProofLike, l as verifyPortableObjectProof, o as signObject, t as InvalidPortableObjectIdError } from "./proof-BpQd-cat.mjs";
13
+ import { a as listRequestSignatures, c as selectRequestSignature, d as validateMaxSignatures, f as verifyRequest, p as verifyRequestDetailed, s as parseRfc9421SignatureInput } from "./http-CO8l72H1.mjs";
14
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-C8QI5jg2.mjs";
15
+ import { n as kvCache } from "./kv-cache-C-20uhXH.mjs";
16
16
  import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-CEnNz8O7.mjs";
17
17
  import { t as nodeInfoToJson } from "./types-DE_LV1JB.mjs";
18
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-Btd7SwMj.mjs";
19
- import { t as verifyPortableObject } from "./portable-collection-gb9V8XEO.mjs";
20
- import { a as getOrderingDestination, i as sendActivityThroughGateways, n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-BrQYUSb4.mjs";
21
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-J1K0IJj6.mjs";
18
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-Cb6Kalag.mjs";
19
+ import { t as verifyPortableObject } from "./portable-collection-DatZLGgt.mjs";
20
+ import { a as getOrderingDestination, i as sendActivityThroughGateways, n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CrgC-GYC.mjs";
21
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-crKu0U3j.mjs";
22
22
  import { t as CircuitBreaker } from "./circuit-breaker-XJ53md4S.mjs";
23
23
  import { t as buildCollectionSynchronizationHeader } from "./collection-CnnP1UAv.mjs";
24
- import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-DtmVrMV7.mjs";
24
+ import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-D5pMfQau.mjs";
25
+ import { n as routeActivity, t as actorsHaveSameOrigin } from "./inbox-q6uJubdj.mjs";
25
26
  import { t as KvKeyCache } from "./keycache-D-MNltOk.mjs";
26
27
  import { t as acceptsJsonLd } from "./negotiation-CCocWT_N.mjs";
27
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BRaCTxVe.mjs";
28
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BjBxALiF.mjs";
28
29
  import { t as createExponentialBackoffPolicy } from "./retry-zX5xw5e0.mjs";
29
30
  import { t as TaskCodec } from "./codec-C6rTrpIp.mjs";
30
31
  import { getLogger, withContext } from "@logtape/logtape";
@@ -638,164 +639,6 @@ function visitJsonMaps(json, visit) {
638
639
  }
639
640
  }
640
641
  //#endregion
641
- //#region src/federation/inbox.ts
642
- async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
643
- const logger = getLogger([
644
- "fedify",
645
- "federation",
646
- "inbox"
647
- ]);
648
- let cacheKey = null;
649
- if (activity.id != null) {
650
- const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
651
- const strategy = idempotencyStrategy ?? "per-inbox";
652
- let keyString;
653
- if (typeof strategy === "function") keyString = await strategy(inboxContext, activity);
654
- else switch (strategy) {
655
- case "global":
656
- keyString = activity.id.href;
657
- break;
658
- case "per-origin":
659
- keyString = `${ctx.origin}\n${activity.id.href}`;
660
- break;
661
- case "per-inbox":
662
- keyString = `${ctx.origin}\n${activity.id.href}\n${recipient == null ? "sharedInbox" : `inbox\n${recipient}`}`;
663
- break;
664
- default: keyString = `${ctx.origin}\n${activity.id.href}`;
665
- }
666
- if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
667
- }
668
- if (cacheKey != null) {
669
- if (await kv.get(cacheKey) === true) {
670
- logger.debug("Activity {activityId} has already been processed.", {
671
- activityId: activity.id?.href,
672
- activity: json,
673
- recipient
674
- });
675
- span.setStatus({
676
- code: SpanStatusCode.UNSET,
677
- message: `Activity ${activity.id?.href} has already been processed.`
678
- });
679
- recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
680
- return "alreadyProcessed";
681
- }
682
- }
683
- if (activity.actorId == null) {
684
- logger.error("Missing actor.", { activity: json });
685
- span.setStatus({
686
- code: SpanStatusCode.ERROR,
687
- message: "Missing actor."
688
- });
689
- recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
690
- return "missingActor";
691
- }
692
- span.setAttribute("activitypub.actor.id", activity.actorId.href);
693
- if (queue != null) {
694
- const carrier = {};
695
- propagation.inject(context.active(), carrier);
696
- try {
697
- await queue.enqueue({
698
- type: "inbox",
699
- id: crypto.randomUUID(),
700
- baseUrl: ctx.origin,
701
- activity: originalJson ?? json,
702
- ...normalizedActivity == null ? {} : { normalizedActivity },
703
- ...ldSignatureVerified == null ? {} : { ldSignatureVerified },
704
- identifier: recipient,
705
- attempt: 0,
706
- started: (/* @__PURE__ */ new Date()).toISOString(),
707
- traceContext: carrier
708
- });
709
- } catch (error) {
710
- logger.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
711
- error,
712
- activityId: activity.id?.href,
713
- activity: json,
714
- recipient
715
- });
716
- span.setStatus({
717
- code: SpanStatusCode.ERROR,
718
- message: `Failed to enqueue the incoming activity ${activity.id?.href}.`
719
- });
720
- throw error;
721
- }
722
- getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
723
- role: "inbox",
724
- queue,
725
- activityType: getTypeId(activity).href
726
- }, 0);
727
- recordInboxActivity(meterProvider, "queued", getTypeId(activity).href);
728
- logger.info("Activity {activityId} is enqueued.", {
729
- activityId: activity.id?.href,
730
- activity: json,
731
- recipient
732
- });
733
- return "enqueued";
734
- }
735
- tracerProvider = tracerProvider ?? trace.getTracerProvider();
736
- return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
737
- const dispatched = inboxListeners?.dispatchWithClass(activity);
738
- if (dispatched == null) {
739
- logger.error("Unsupported activity type:\n{activity}", {
740
- activity: json,
741
- recipient
742
- });
743
- span.setStatus({
744
- code: SpanStatusCode.UNSET,
745
- message: `Unsupported activity type: ${getTypeId(activity).href}`
746
- });
747
- recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
748
- span.end();
749
- return "unsupportedActivity";
750
- }
751
- const { class: cls, listener } = dispatched;
752
- span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
753
- try {
754
- const activityType = getTypeId(activity).href;
755
- const started = performance.now();
756
- try {
757
- const contextFactory = listenerInboxContextFactory ?? inboxContextFactory;
758
- await listener(contextFactory(recipient, contextFactory === inboxContextFactory ? json : originalJson ?? json, activity.id?.href, activityType), activity);
759
- } finally {
760
- getFederationMetrics(meterProvider).recordInboxProcessingDuration(activityType, getDurationMs(started));
761
- }
762
- } catch (error) {
763
- try {
764
- await inboxErrorHandler?.(ctx, error);
765
- } catch (error) {
766
- logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
767
- error,
768
- activityId: activity.id?.href,
769
- activity: json,
770
- recipient
771
- });
772
- }
773
- logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
774
- error,
775
- activityId: activity.id?.href,
776
- activity: json,
777
- recipient
778
- });
779
- span.setStatus({
780
- code: SpanStatusCode.ERROR,
781
- message: String(error)
782
- });
783
- recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
784
- span.end();
785
- return "error";
786
- }
787
- recordInboxActivity(meterProvider, "processed", getTypeId(activity).href);
788
- if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
789
- logger.info("Activity {activityId} has been processed.", {
790
- activityId: activity.id?.href,
791
- activity: json,
792
- recipient
793
- });
794
- span.end();
795
- return "success";
796
- });
797
- }
798
- //#endregion
799
642
  //#region src/federation/portable.ts
800
643
  /**
801
644
  * The media type that FEP-ef61 gateways must use for portable objects.
@@ -1725,13 +1568,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
1725
1568
  * @param parameters The parameters for handling the collection.
1726
1569
  * @returns A promise that resolves to an HTTP response.
1727
1570
  */
1728
- async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
1729
- const spanName = name$1.trim().replace(/\s+/g, "_");
1571
+ async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
1572
+ const spanName = name$2.trim().replace(/\s+/g, "_");
1730
1573
  tracerProvider = tracerProvider ?? trace.getTracerProvider();
1731
1574
  const tracer = tracerProvider.getTracer(name, version);
1732
1575
  const cursor = new URL(request.url).searchParams.get("cursor");
1733
1576
  const metricBase = {
1734
- kind: getCollectionMetricKind(name$1),
1577
+ kind: getCollectionMetricKind(name$2),
1735
1578
  page: cursor != null,
1736
1579
  dispatcher: "built_in"
1737
1580
  };
@@ -1777,7 +1620,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
1777
1620
  span.setStatus({ code: SpanStatusCode.ERROR });
1778
1621
  return await onNotFound(request);
1779
1622
  }
1780
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
1623
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
1781
1624
  itemCount = items.length;
1782
1625
  span.setAttribute("fedify.collection.items", itemCount);
1783
1626
  return items;
@@ -1819,7 +1662,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
1819
1662
  } else {
1820
1663
  const uri = new URL(portable == null ? baseUri : pageBase);
1821
1664
  uri.searchParams.set("cursor", cursor);
1822
- const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
1665
+ const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
1823
1666
  kind: SpanKind.SERVER,
1824
1667
  attributes: {
1825
1668
  "activitypub.collection.id": uri.href,
@@ -1835,7 +1678,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
1835
1678
  span.setStatus({ code: SpanStatusCode.ERROR });
1836
1679
  return await onNotFound(request);
1837
1680
  }
1838
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
1681
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
1839
1682
  itemCount = items.length;
1840
1683
  span.setAttribute("fedify.collection.items", itemCount);
1841
1684
  return {
@@ -2988,11 +2831,53 @@ async function handleInboxInternal(request, parameters, span) {
2988
2831
  return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
2989
2832
  }
2990
2833
  }
2834
+ if (!skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
2835
+ observation.authentication = {
2836
+ status: "rejected",
2837
+ reason: {
2838
+ type: "activityOriginMismatch",
2839
+ activityId: new URL(activity.id.href),
2840
+ actorIds: activity.actorIds.map((id) => new URL(id.href))
2841
+ }
2842
+ };
2843
+ logger.error("The activity ({activityId}) and its actors do not have the same origin.", {
2844
+ activity: json,
2845
+ recipient,
2846
+ activityId: activity.id.href,
2847
+ actorIds: activity.actorIds.map((actor) => actor.href)
2848
+ });
2849
+ span.setStatus({
2850
+ code: SpanStatusCode.ERROR,
2851
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
2852
+ });
2853
+ return new Response("The activity and its actors do not have the same origin.", {
2854
+ status: 401,
2855
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
2856
+ });
2857
+ }
2991
2858
  observation.authentication = skipSignatureVerification ? { status: "skipped" } : {
2992
2859
  status: "verified",
2993
2860
  attempts: observation.verification.attempts.filter((attempt) => attempt.status === "verified")
2994
2861
  };
2995
2862
  observation.stage = "dispatch";
2863
+ if (activity.actorId == null) {
2864
+ observation.result = {
2865
+ disposition: "rejected",
2866
+ reason: "missingActor"
2867
+ };
2868
+ logger.error("Missing actor.", {
2869
+ activity: json,
2870
+ recipient
2871
+ });
2872
+ span.setStatus({
2873
+ code: SpanStatusCode.ERROR,
2874
+ message: "Missing actor."
2875
+ });
2876
+ return new Response("Missing actor.", {
2877
+ status: 400,
2878
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
2879
+ });
2880
+ }
2996
2881
  const routeResult = await routeActivity({
2997
2882
  context: ctx,
2998
2883
  json,
@@ -3213,8 +3098,8 @@ var CustomCollectionHandler = class {
3213
3098
  * @param CollectionPage The CollectionPage constructor.
3214
3099
  * @param filterPredicate Optional filter predicate for items.
3215
3100
  */
3216
- constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
3217
- this.name = name$2;
3101
+ constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
3102
+ this.name = name$1;
3218
3103
  this.values = values;
3219
3104
  this.context = context;
3220
3105
  this.callbacks = callbacks;
@@ -5840,6 +5725,35 @@ var FederationImpl = class extends FederationBuilderImpl {
5840
5725
  span.setAttribute("activitypub.activity.id", activity.id.href);
5841
5726
  listenerSpan.setAttribute("activitypub.activity.id", activity.id.href);
5842
5727
  }
5728
+ if (activity.actorId == null) {
5729
+ logger.error("Missing actor in queued incoming activity.", {
5730
+ activityId: activity.id?.href,
5731
+ activity: message.activity,
5732
+ recipient: message.identifier
5733
+ });
5734
+ listenerSpan.setStatus({
5735
+ code: SpanStatusCode.ERROR,
5736
+ message: "Missing actor."
5737
+ });
5738
+ recordInboxActivity(this.meterProvider, "rejected", activityType);
5739
+ listenerSpan.end();
5740
+ return;
5741
+ }
5742
+ if (!this.skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
5743
+ logger.error("The queued activity ({activityId}) and its actors do not have the same origin.", {
5744
+ activityId: activity.id.href,
5745
+ actorIds: activity.actorIds.map((actor) => actor.href),
5746
+ activity: message.activity,
5747
+ recipient: message.identifier
5748
+ });
5749
+ listenerSpan.setStatus({
5750
+ code: SpanStatusCode.ERROR,
5751
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
5752
+ });
5753
+ recordInboxActivity(this.meterProvider, "rejected", activityType);
5754
+ listenerSpan.end();
5755
+ return;
5756
+ }
5843
5757
  cacheKey = activity.id == null ? null : [
5844
5758
  ...this.kvPrefixes.activityIdempotence,
5845
5759
  context.origin,
@@ -7916,6 +7830,20 @@ var ContextImpl = class ContextImpl {
7916
7830
  recipient,
7917
7831
  activity: json
7918
7832
  });
7833
+ if (activity.actorId == null) {
7834
+ logger.debug("Activity is missing an actor; unable to verify.", {
7835
+ recipient,
7836
+ activity: json
7837
+ });
7838
+ return false;
7839
+ }
7840
+ if (activity.id != null && !actorsHaveSameOrigin(activity)) {
7841
+ logger.debug("Activity has actors from different origins; unable to verify.", {
7842
+ recipient,
7843
+ activity: json
7844
+ });
7845
+ return false;
7846
+ }
7919
7847
  const routeResult = await routeActivity({
7920
7848
  context: this,
7921
7849
  json,
@@ -8038,6 +7966,12 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
8038
7966
  #signedKey = void 0;
8039
7967
  async getSignedKey(options = {}) {
8040
7968
  if (this.#signedKey != null) return this.#signedKey;
7969
+ const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
7970
+ documentLoader: options.documentLoader ?? this.documentLoader,
7971
+ contextLoader: options.contextLoader ?? this.contextLoader,
7972
+ tracerProvider: options.tracerProvider ?? this.tracerProvider,
7973
+ keyTtl: this.federation.publicKeyTtl
7974
+ });
8041
7975
  return this.#signedKey = await verifyRequest(this.request, {
8042
7976
  ...this,
8043
7977
  contextLoader: options.contextLoader ?? this.contextLoader,
@@ -8045,7 +7979,8 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
8045
7979
  timeWindow: this.federation.signatureTimeWindow,
8046
7980
  maxSignatures: this.federation.maxHttpSignatures,
8047
7981
  meterProvider: this.meterProvider,
8048
- tracerProvider: options.tracerProvider ?? this.tracerProvider
7982
+ tracerProvider: options.tracerProvider ?? this.tracerProvider,
7983
+ keyCache
8049
7984
  });
8050
7985
  }
8051
7986
  #signedKeyOwner = void 0;
@@ -1,5 +1,5 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as FederationImpl } from "./middleware-BbBsa5iR.mjs";
4
+ import { n as FederationImpl } from "./middleware-BahtLJeT.mjs";
5
5
  export { FederationImpl };
@@ -2,10 +2,10 @@ import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./rolldown-runtime-BC-Eo5Mj.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-DAtXl_Kc.js";
5
- import { $ as getFederationMetrics, A as detachSignature, At as isPortableId, B as wrapContextLoaderForJsonLd, Ct as getAuthenticationOrigin, Dt as getRawCanonicalPortableId, E as assertSafeJsonLd, Et as getPortableDid, F as isInvalidUrlTypeError, Ft as name, I as signJsonLd, It as version, K as importJwk, L as verifyCompactJsonLd, M as hasSignature, Mt as isPortableUri, N as hasSignatureLike, Nt as isSameObjectId, O as compactJsonLd, Ot as hasPortableActor, P as isClearlyMalformedContextReference, Q as getDurationMs, S as verifyPreparedPortableObjectProofPolicy, St as verificationObservation, T as InvalidContextReferenceError, Tt as getGatewayKeyBase, V as exportJwk, Y as MAX_PORTABLE_KEY_TTL, _ as verifyMapLocalProof, at as recordCollectionPageItems, b as verifyPortableObjectProofPolicy, bt as observeAttempt, c as verifyRequestDetailed, d as InvalidPortableObjectIdError, dt as recordOutboxActivity, et as getRemoteHost, f as classifyFep2277CoreType, ft as recordOutboxEnqueue, g as signObject, gt as formatAcceptSignature, h as preparePortableObjectProofPolicy, ht as preloadedOnlyDocumentLoader, i as selectRequestSignature, it as recordCollectionDispatchDuration, j as getNormalizationContextLoader, jt as isPortableKeyId, kt as isCompatibleKeyId, lt as recordFanoutRecipients, m as hasProofLike, mt as registerQueueDepthGauge, n as listRequestSignatures, nt as isAbortError, o as validateMaxSignatures, ot as recordCollectionRequest, pt as recordWebFingerHandle, q as validateCryptoKey, r as parseRfc9421SignatureInput, rt as recordCircuitBreakerStateChange, s as verifyRequest, st as recordCollectionTotalItems, t as doubleKnock, tt as instrumentDocumentLoader, ut as recordInboxActivity, v as verifyObject, w as normalizeOutgoingActivityJsonLd, wt as getCanonicalPortableId, x as verifyPortableObjectProofWithRoot, xt as snapshotKey, y as verifyPortableObjectProof } from "./http-Cmz7x6Iw.js";
5
+ import { $ as getFederationMetrics, A as detachSignature, At as isPortableId, B as wrapContextLoaderForJsonLd, Ct as getAuthenticationOrigin, Dt as getRawCanonicalPortableId, E as assertSafeJsonLd, Et as getPortableDid, F as isInvalidUrlTypeError, Ft as name, I as signJsonLd, It as version, K as importJwk, L as verifyCompactJsonLd, M as hasSignature, Mt as isPortableUri, N as hasSignatureLike, Nt as isSameObjectId, O as compactJsonLd, Ot as hasPortableActor, P as isClearlyMalformedContextReference, Q as getDurationMs, S as verifyPreparedPortableObjectProofPolicy, St as verificationObservation, T as InvalidContextReferenceError, Tt as getGatewayKeyBase, V as exportJwk, Y as MAX_PORTABLE_KEY_TTL, _ as verifyMapLocalProof, at as recordCollectionPageItems, b as verifyPortableObjectProofPolicy, bt as observeAttempt, c as verifyRequestDetailed, d as InvalidPortableObjectIdError, dt as recordOutboxActivity, et as getRemoteHost, f as classifyFep2277CoreType, ft as recordOutboxEnqueue, g as signObject, gt as formatAcceptSignature, h as preparePortableObjectProofPolicy, ht as preloadedOnlyDocumentLoader, i as selectRequestSignature, it as recordCollectionDispatchDuration, j as getNormalizationContextLoader, jt as isPortableKeyId, kt as isCompatibleKeyId, lt as recordFanoutRecipients, m as hasProofLike, mt as registerQueueDepthGauge, n as listRequestSignatures, nt as isAbortError, o as validateMaxSignatures, ot as recordCollectionRequest, pt as recordWebFingerHandle, q as validateCryptoKey, r as parseRfc9421SignatureInput, rt as recordCircuitBreakerStateChange, s as verifyRequest, st as recordCollectionTotalItems, t as doubleKnock, tt as instrumentDocumentLoader, ut as recordInboxActivity, v as verifyObject, w as normalizeOutgoingActivityJsonLd, wt as getCanonicalPortableId, x as verifyPortableObjectProofWithRoot, xt as snapshotKey, y as verifyPortableObjectProof } from "./http-CRRQ6LBq.js";
6
6
  import { a as MAX_BODY_SIZE, i as BodyTooLargeError, n as getNodeInfo, o as readBoundedText, t as nodeInfoToJson } from "./types-_S2_MeLF.js";
7
- import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "./portable-collection-DwQT28O2.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-C0-HuvwP.js";
7
+ import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "./portable-collection-BweSVeOo.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-D5EHCk1_.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Router, RouterError, assertPath } from "@fedify/uri-template";
11
11
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, PUBLIC_COLLECTION, Tombstone, getTypeId, isActor, lookupObject, traverseCollection } from "@fedify/vocab";
@@ -2805,12 +2805,41 @@ async function isInAudience(object, actor, options = {}) {
2805
2805
  }
2806
2806
  //#endregion
2807
2807
  //#region src/federation/inbox.ts
2808
+ /**
2809
+ * Checks whether an activity's ID and all of its actor IDs have the same
2810
+ * [FEP-fe34] origin. Activities without an ID have no origin to authenticate.
2811
+ *
2812
+ * Origins are compared by `getAuthenticationOrigin()`, so a portable activity
2813
+ * and its portable actors, including compatible identifiers on any gateway,
2814
+ * are compared by their DIDs. An ID that has no supported origin, such as an
2815
+ * opaque URN, never matches.
2816
+ *
2817
+ * The caller is responsible for rejecting a missing primary actor ID before
2818
+ * relying on this check.
2819
+ *
2820
+ * [FEP-fe34]: https://w3id.org/fep/fe34
2821
+ * @internal
2822
+ */
2823
+ function actorsHaveSameOrigin(activity) {
2824
+ if (activity.id == null) return true;
2825
+ const origin = getAuthenticationOrigin(activity.id);
2826
+ return origin != null && activity.actorIds.every((actor) => getAuthenticationOrigin(actor) === origin);
2827
+ }
2808
2828
  async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
2809
2829
  const logger = getLogger([
2810
2830
  "fedify",
2811
2831
  "federation",
2812
2832
  "inbox"
2813
2833
  ]);
2834
+ if (activity.actorId == null) {
2835
+ logger.error("Missing actor.", { activity: json });
2836
+ span.setStatus({
2837
+ code: SpanStatusCode.ERROR,
2838
+ message: "Missing actor."
2839
+ });
2840
+ recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
2841
+ return "missingActor";
2842
+ }
2814
2843
  let cacheKey = null;
2815
2844
  if (activity.id != null) {
2816
2845
  const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
@@ -2846,15 +2875,6 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
2846
2875
  return "alreadyProcessed";
2847
2876
  }
2848
2877
  }
2849
- if (activity.actorId == null) {
2850
- logger.error("Missing actor.", { activity: json });
2851
- span.setStatus({
2852
- code: SpanStatusCode.ERROR,
2853
- message: "Missing actor."
2854
- });
2855
- recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
2856
- return "missingActor";
2857
- }
2858
2878
  span.setAttribute("activitypub.actor.id", activity.actorId.href);
2859
2879
  if (queue != null) {
2860
2880
  const carrier = {};
@@ -4772,13 +4792,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
4772
4792
  * @param parameters The parameters for handling the collection.
4773
4793
  * @returns A promise that resolves to an HTTP response.
4774
4794
  */
4775
- async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
4776
- const spanName = name$1.trim().replace(/\s+/g, "_");
4795
+ async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
4796
+ const spanName = name$2.trim().replace(/\s+/g, "_");
4777
4797
  tracerProvider = tracerProvider ?? trace.getTracerProvider();
4778
4798
  const tracer = tracerProvider.getTracer(name, version);
4779
4799
  const cursor = new URL(request.url).searchParams.get("cursor");
4780
4800
  const metricBase = {
4781
- kind: getCollectionMetricKind(name$1),
4801
+ kind: getCollectionMetricKind(name$2),
4782
4802
  page: cursor != null,
4783
4803
  dispatcher: "built_in"
4784
4804
  };
@@ -4824,7 +4844,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
4824
4844
  span.setStatus({ code: SpanStatusCode.ERROR });
4825
4845
  return await onNotFound(request);
4826
4846
  }
4827
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
4847
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
4828
4848
  itemCount = items.length;
4829
4849
  span.setAttribute("fedify.collection.items", itemCount);
4830
4850
  return items;
@@ -4866,7 +4886,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
4866
4886
  } else {
4867
4887
  const uri = new URL(portable == null ? baseUri : pageBase);
4868
4888
  uri.searchParams.set("cursor", cursor);
4869
- const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
4889
+ const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
4870
4890
  kind: SpanKind.SERVER,
4871
4891
  attributes: {
4872
4892
  "activitypub.collection.id": uri.href,
@@ -4882,7 +4902,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
4882
4902
  span.setStatus({ code: SpanStatusCode.ERROR });
4883
4903
  return await onNotFound(request);
4884
4904
  }
4885
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
4905
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
4886
4906
  itemCount = items.length;
4887
4907
  span.setAttribute("fedify.collection.items", itemCount);
4888
4908
  return {
@@ -6035,11 +6055,53 @@ async function handleInboxInternal(request, parameters, span) {
6035
6055
  return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
6036
6056
  }
6037
6057
  }
6058
+ if (!skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
6059
+ observation.authentication = {
6060
+ status: "rejected",
6061
+ reason: {
6062
+ type: "activityOriginMismatch",
6063
+ activityId: new URL(activity.id.href),
6064
+ actorIds: activity.actorIds.map((id) => new URL(id.href))
6065
+ }
6066
+ };
6067
+ logger.error("The activity ({activityId}) and its actors do not have the same origin.", {
6068
+ activity: json,
6069
+ recipient,
6070
+ activityId: activity.id.href,
6071
+ actorIds: activity.actorIds.map((actor) => actor.href)
6072
+ });
6073
+ span.setStatus({
6074
+ code: SpanStatusCode.ERROR,
6075
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
6076
+ });
6077
+ return new Response("The activity and its actors do not have the same origin.", {
6078
+ status: 401,
6079
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
6080
+ });
6081
+ }
6038
6082
  observation.authentication = skipSignatureVerification ? { status: "skipped" } : {
6039
6083
  status: "verified",
6040
6084
  attempts: observation.verification.attempts.filter((attempt) => attempt.status === "verified")
6041
6085
  };
6042
6086
  observation.stage = "dispatch";
6087
+ if (activity.actorId == null) {
6088
+ observation.result = {
6089
+ disposition: "rejected",
6090
+ reason: "missingActor"
6091
+ };
6092
+ logger.error("Missing actor.", {
6093
+ activity: json,
6094
+ recipient
6095
+ });
6096
+ span.setStatus({
6097
+ code: SpanStatusCode.ERROR,
6098
+ message: "Missing actor."
6099
+ });
6100
+ return new Response("Missing actor.", {
6101
+ status: 400,
6102
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
6103
+ });
6104
+ }
6043
6105
  const routeResult = await routeActivity({
6044
6106
  context: ctx,
6045
6107
  json,
@@ -6260,8 +6322,8 @@ var CustomCollectionHandler = class {
6260
6322
  * @param CollectionPage The CollectionPage constructor.
6261
6323
  * @param filterPredicate Optional filter predicate for items.
6262
6324
  */
6263
- constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
6264
- this.name = name$2;
6325
+ constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
6326
+ this.name = name$1;
6265
6327
  this.values = values;
6266
6328
  this.context = context;
6267
6329
  this.callbacks = callbacks;
@@ -9296,6 +9358,35 @@ var FederationImpl = class extends FederationBuilderImpl {
9296
9358
  span.setAttribute("activitypub.activity.id", activity.id.href);
9297
9359
  listenerSpan.setAttribute("activitypub.activity.id", activity.id.href);
9298
9360
  }
9361
+ if (activity.actorId == null) {
9362
+ logger.error("Missing actor in queued incoming activity.", {
9363
+ activityId: activity.id?.href,
9364
+ activity: message.activity,
9365
+ recipient: message.identifier
9366
+ });
9367
+ listenerSpan.setStatus({
9368
+ code: SpanStatusCode.ERROR,
9369
+ message: "Missing actor."
9370
+ });
9371
+ recordInboxActivity(this.meterProvider, "rejected", activityType);
9372
+ listenerSpan.end();
9373
+ return;
9374
+ }
9375
+ if (!this.skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
9376
+ logger.error("The queued activity ({activityId}) and its actors do not have the same origin.", {
9377
+ activityId: activity.id.href,
9378
+ actorIds: activity.actorIds.map((actor) => actor.href),
9379
+ activity: message.activity,
9380
+ recipient: message.identifier
9381
+ });
9382
+ listenerSpan.setStatus({
9383
+ code: SpanStatusCode.ERROR,
9384
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
9385
+ });
9386
+ recordInboxActivity(this.meterProvider, "rejected", activityType);
9387
+ listenerSpan.end();
9388
+ return;
9389
+ }
9299
9390
  cacheKey = activity.id == null ? null : [
9300
9391
  ...this.kvPrefixes.activityIdempotence,
9301
9392
  context.origin,
@@ -11372,6 +11463,20 @@ var ContextImpl = class ContextImpl {
11372
11463
  recipient,
11373
11464
  activity: json
11374
11465
  });
11466
+ if (activity.actorId == null) {
11467
+ logger.debug("Activity is missing an actor; unable to verify.", {
11468
+ recipient,
11469
+ activity: json
11470
+ });
11471
+ return false;
11472
+ }
11473
+ if (activity.id != null && !actorsHaveSameOrigin(activity)) {
11474
+ logger.debug("Activity has actors from different origins; unable to verify.", {
11475
+ recipient,
11476
+ activity: json
11477
+ });
11478
+ return false;
11479
+ }
11375
11480
  const routeResult = await routeActivity({
11376
11481
  context: this,
11377
11482
  json,
@@ -11494,6 +11599,12 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
11494
11599
  #signedKey = void 0;
11495
11600
  async getSignedKey(options = {}) {
11496
11601
  if (this.#signedKey != null) return this.#signedKey;
11602
+ const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
11603
+ documentLoader: options.documentLoader ?? this.documentLoader,
11604
+ contextLoader: options.contextLoader ?? this.contextLoader,
11605
+ tracerProvider: options.tracerProvider ?? this.tracerProvider,
11606
+ keyTtl: this.federation.publicKeyTtl
11607
+ });
11497
11608
  return this.#signedKey = await verifyRequest(this.request, {
11498
11609
  ...this,
11499
11610
  contextLoader: options.contextLoader ?? this.contextLoader,
@@ -11501,7 +11612,8 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
11501
11612
  timeWindow: this.federation.signatureTimeWindow,
11502
11613
  maxSignatures: this.federation.maxHttpSignatures,
11503
11614
  meterProvider: this.meterProvider,
11504
- tracerProvider: options.tracerProvider ?? this.tracerProvider
11615
+ tracerProvider: options.tracerProvider ?? this.tracerProvider,
11616
+ keyCache
11505
11617
  });
11506
11618
  }
11507
11619
  #signedKeyOwner = void 0;
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { Jt as WebFingerLinksDispatcher, St as ActorHandleMapper, bt as ActorAliasMapper, p as RequestContext, xt as ActorDispatcher } from "./context-BjD_CTxh.cjs";
2
+ import { Jt as WebFingerLinksDispatcher, St as ActorHandleMapper, bt as ActorAliasMapper, p as RequestContext, xt as ActorDispatcher } from "./context-DPocjp1l.cjs";
3
3
  import { MeterProvider, Span, Tracer } from "@opentelemetry/api";
4
4
  import { RouterError, RouterOptions, RouterRouteResult } from "@fedify/uri-template";
5
5