@fedify/fedify 2.4.0-dev.2122 → 2.4.0-dev.2129

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 (98) hide show
  1. package/dist/{builder-BCXywsZF.mjs → builder-C0bxZDL0.mjs} +3 -3
  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-Fxd45Oy5.mjs → compound-proof-D9Kljk_7.mjs} +3 -3
  6. package/dist/{context-tOiJfBoD.d.ts → context-Cz1w5Krc.d.ts} +31 -5
  7. package/dist/{context-CoNRxGYp.mjs → context-DfSVPcJ8.mjs} +6 -3
  8. package/dist/{context-SMNOiiY6.d.cts → context-Dvec_D_h.d.cts} +31 -5
  9. package/dist/{deno-BZrnW0Qz.mjs → deno-_o3lkDlG.mjs} +1 -1
  10. package/dist/{docloader-3BHaS20Z.mjs → docloader-BbS0rO-Y.mjs} +7 -7
  11. package/dist/federation/builder.test.mjs +1 -1
  12. package/dist/federation/compound-fanout.test.mjs +3 -3
  13. package/dist/federation/handler-compound-proof.test.mjs +4 -4
  14. package/dist/federation/handler.test.mjs +6 -6
  15. package/dist/federation/hashlink-media.test.mjs +2 -2
  16. package/dist/federation/idempotency.test.mjs +2 -2
  17. package/dist/federation/metrics.test.mjs +1 -1
  18. package/dist/federation/middleware.test.mjs +8 -8
  19. package/dist/federation/mod.cjs +1 -1
  20. package/dist/federation/mod.d.cts +2 -2
  21. package/dist/federation/mod.d.ts +2 -2
  22. package/dist/federation/mod.js +1 -1
  23. package/dist/federation/outgoing-proof.test.mjs +6 -6
  24. package/dist/federation/portable-actor.test.mjs +3 -3
  25. package/dist/federation/portable-chain.test.d.mts +2 -0
  26. package/dist/federation/portable-chain.test.mjs +358 -0
  27. package/dist/federation/portable-gateway-keys.test.mjs +77 -6
  28. package/dist/federation/portable-inbox.test.mjs +9 -4
  29. package/dist/federation/portable.test.mjs +3 -3
  30. package/dist/federation/send.test.mjs +3 -3
  31. package/dist/federation/tasks/enqueue.test.mjs +2 -2
  32. package/dist/federation/tasks/tasks.test.mjs +3 -3
  33. package/dist/federation/temporal.test.mjs +1 -1
  34. package/dist/federation/webfinger.test.mjs +2 -2
  35. package/dist/{federation-Ml6NrgRV.cjs → federation-DRY8KrkB.cjs} +46 -22
  36. package/dist/{http-4bmgw-mA.cjs → http-B1J6E-bT.cjs} +384 -33
  37. package/dist/{http-B9BQDNIy.mjs → http-BpOiZE09.mjs} +18 -12
  38. package/dist/{http-D76Py0M4.d.cts → http-C-x_OLSp.d.ts} +57 -14
  39. package/dist/{http-BETASGl0.js → http-C2M6wcs8.js} +374 -35
  40. package/dist/{http-BrQgkJay.d.ts → http-CjezPjFX.d.cts} +57 -14
  41. package/dist/{key-PyYvun0F.mjs → key-DolJjJab.mjs} +103 -16
  42. package/dist/{kv-cache-CPqUxRL3.mjs → kv-cache-Bq2cah0c.mjs} +1 -1
  43. package/dist/{kv-cache-C4mv2ZFQ.js → kv-cache-D7TiyMxv.js} +6 -6
  44. package/dist/{kv-cache-D2Bz6t_c.cjs → kv-cache-D9nRbG2Q.cjs} +6 -6
  45. package/dist/{ld-u4JOD4iO.mjs → ld-Dwc176V4.mjs} +3 -3
  46. package/dist/{metrics-DCLoLvLz.mjs → metrics-CDaHfBXY.mjs} +1 -1
  47. package/dist/{middleware-B7bmtONC.mjs → middleware-CmB1FD8A.mjs} +1 -1
  48. package/dist/{middleware-DWlAGlyP.js → middleware-CylX-pvI.js} +52 -28
  49. package/dist/{middleware-CgOqRkK-.mjs → middleware-DN3MdTDg.mjs} +64 -39
  50. package/dist/{mod-CTh7ijx5.d.ts → mod-Bz9tFXI2.d.ts} +14 -3
  51. package/dist/{mod-Cwdt_CWU.d.ts → mod-CZetqT5h.d.ts} +1 -1
  52. package/dist/{mod-Cr79cQlc.d.cts → mod-D4g9ffEn.d.cts} +1 -1
  53. package/dist/{mod-DnElMslb.d.cts → mod-DGOIxEfb.d.cts} +1 -1
  54. package/dist/{mod-DMdGFMEl.d.cts → mod-S--JxYjo.d.cts} +14 -3
  55. package/dist/{mod-COWgSo2v.d.ts → mod-owwElvpw.d.ts} +1 -1
  56. package/dist/mod.cjs +8 -8
  57. package/dist/mod.d.cts +5 -5
  58. package/dist/mod.d.ts +5 -5
  59. package/dist/mod.js +5 -5
  60. package/dist/nodeinfo/handler.test.mjs +2 -2
  61. package/dist/{owner-CPFM-sqo.mjs → owner-BNHhwjNu.mjs} +37 -4
  62. package/dist/{sig-C1xOA4ml.js → portable-collection-CRpTUHCY.mjs} +5 -4
  63. package/dist/portable-collection-CgglAI9B.js +656 -0
  64. package/dist/{sig-Cb9VSeiF.cjs → portable-collection-PTGD0q70.cjs} +253 -2
  65. package/dist/portable-key-DqX2emHQ.mjs +395 -0
  66. package/dist/{portable-key-id-T7lecIbt.mjs → portable-key-id-Bg259c4Z.mjs} +69 -2
  67. package/dist/{proof-BCOg7Njv.mjs → proof-B4_0E-KU.mjs} +5 -5
  68. package/dist/{send-C8eOPat3.mjs → send-Dpu5qbP5.mjs} +3 -3
  69. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  70. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  71. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  72. package/dist/sig/compound-proof.test.mjs +2 -2
  73. package/dist/sig/http.test.mjs +2 -2
  74. package/dist/sig/key.test.mjs +1 -1
  75. package/dist/sig/ld.test.mjs +2 -2
  76. package/dist/sig/mod.cjs +5 -6
  77. package/dist/sig/mod.d.cts +2 -2
  78. package/dist/sig/mod.d.ts +2 -2
  79. package/dist/sig/mod.js +2 -3
  80. package/dist/sig/owner.test.mjs +1 -1
  81. package/dist/sig/portable-collection.test.mjs +20 -431
  82. package/dist/sig/portable-key.test.mjs +479 -5
  83. package/dist/sig/proof.test.mjs +3 -3
  84. package/dist/{temporal-vjHOhBpy.mjs → temporal-78JVR3GK.mjs} +1 -1
  85. package/dist/testing/kv.test.mjs +1 -1
  86. package/dist/testing/mod.d.mts +30 -4
  87. package/dist/testing/mod.mjs +2 -2
  88. package/dist/{testing-BWq1dCzx.mjs → testing-otQhu4aD.mjs} +1 -1
  89. package/dist/utils/docloader.test.mjs +81 -2
  90. package/dist/utils/kv-cache.test.mjs +1 -1
  91. package/dist/utils/mod.cjs +1 -1
  92. package/dist/utils/mod.d.cts +1 -1
  93. package/dist/utils/mod.d.ts +1 -1
  94. package/dist/utils/mod.js +1 -1
  95. package/package.json +7 -7
  96. package/dist/owner-DkA0Lz7v.cjs +0 -225
  97. package/dist/owner-wNinn7RK.js +0 -215
  98. package/dist/portable-key-DyylakVV.mjs +0 -214
@@ -1,7 +1,7 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { Actor, CryptographicKey, Multikey } from "@fedify/vocab";
3
- import { MeterProvider, TracerProvider } from "@opentelemetry/api";
4
3
  import { DocumentLoader } from "@fedify/vocab-runtime";
4
+ import { MeterProvider, TracerProvider } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/sig/portable-key.d.ts
7
7
  /**
@@ -29,6 +29,28 @@ type PortableGatewayKeyResolution = {
29
29
  */
30
30
  readonly expires?: Temporal.Instant;
31
31
  };
32
+ /**
33
+ * The result of resolving a key of a portable actor at an `ap:` or
34
+ * `ap+ef61:` key ID.
35
+ * @internal
36
+ */
37
+ type PortableActorKeyResolution = Exclude<PortableGatewayKeyResolution, {
38
+ readonly type: "legacy";
39
+ }> | {
40
+ /**
41
+ * Whether the actor's document vouches for the key could not be
42
+ * determined, e.g., because no gateway could be reached.
43
+ */
44
+ readonly type: "unavailable";
45
+ readonly error: unknown;
46
+ /**
47
+ * Whether the failure can be cached as a failure to fetch the key, i.e.,
48
+ * every gateway failed to serve the actor's document at all. A failure
49
+ * that is not cacheable comes with an error that has no HTTP status,
50
+ * since none of the statuses describes the lookup as a whole.
51
+ */
52
+ readonly cacheable: boolean;
53
+ };
32
54
  //#endregion
33
55
  //#region src/sig/key.d.ts
34
56
  /**
@@ -119,17 +141,34 @@ interface FetchKeyOptions {
119
141
  */
120
142
  keyIdBoundByCaller?: boolean;
121
143
  /**
122
- * Resolves a gateway key of an [FEP-ef61] portable actor, i.e., a key whose
123
- * ID is a compatible identifier and dereferences to a portable actor's
124
- * document. Such a key is resolved only through this function, and is
125
- * rejected if it is omitted, so that only HTTP Signature verification,
126
- * which passes it, accepts gateway keys. Object Integrity Proofs and
127
- * Linked Data Signatures never do.
144
+ * Resolves keys of [FEP-ef61] portable actors, which only HTTP Signature
145
+ * verification passes, so that only it accepts them. Object Integrity
146
+ * Proofs and Linked Data Signatures never do: such a key is rejected if
147
+ * this is omitted.
128
148
  *
129
149
  * [FEP-ef61]: https://w3id.org/fep/ef61
130
150
  * @internal
131
151
  */
132
- portableGatewayKeyResolver?: (document: unknown, actor: Actor, keyId: URL) => Promise<PortableGatewayKeyResolution>;
152
+ portableKeyResolvers?: PortableKeyResolvers;
153
+ }
154
+ /**
155
+ * Resolves keys of [FEP-ef61] portable actors for HTTP Signature
156
+ * verification. See {@link FetchKeyOptions.portableKeyResolvers}.
157
+ *
158
+ * [FEP-ef61]: https://w3id.org/fep/ef61
159
+ * @internal
160
+ */
161
+ interface PortableKeyResolvers {
162
+ /**
163
+ * Resolves a gateway key, i.e., a key whose ID is a compatible identifier
164
+ * and dereferences to a portable actor's document.
165
+ */
166
+ gatewayKey(document: unknown, actor: Actor, keyId: URL): Promise<PortableGatewayKeyResolution>;
167
+ /**
168
+ * Resolves a key of a portable actor itself, i.e., a key whose ID is an
169
+ * `ap:` or `ap+ef61:` URI.
170
+ */
171
+ actorKey(keyId: URL): Promise<PortableActorKeyResolution>;
133
172
  }
134
173
  /**
135
174
  * The result of {@link fetchKey}.
@@ -182,9 +221,11 @@ type FetchableKeyClass<T extends CryptographicKey | Multikey> = (new (...args: a
182
221
  * Gateway keys of [FEP-ef61] portable actors, i.e., keys whose IDs are
183
222
  * compatible identifiers that dereference to portable actor documents, are
184
223
  * not resolved by this function, as they only authenticate HTTP requests;
185
- * use `verifyRequest()` or `getKeyOwner()` for them instead. Keys whose IDs
186
- * are compatible identifiers are never read from or written to the key
187
- * cache under their IDs, except for failures to fetch them.
224
+ * use `verifyRequest()` or `getKeyOwner()` for them instead. Nor are keys
225
+ * of portable actors whose IDs are `ap:` or `ap+ef61:` URIs, for the same
226
+ * reason. Keys whose IDs are compatible identifiers or `ap:` or `ap+ef61:`
227
+ * URIs are never read from or written to the key cache under their IDs,
228
+ * except for failures to fetch them.
188
229
  *
189
230
  * [FEP-ef61]: https://w3id.org/fep/ef61
190
231
  * @template T The type of the key to fetch. Either {@link CryptographicKey}
@@ -204,9 +245,11 @@ declare function fetchKey<T extends CryptographicKey | Multikey>(keyId: URL | st
204
245
  * Gateway keys of [FEP-ef61] portable actors, i.e., keys whose IDs are
205
246
  * compatible identifiers that dereference to portable actor documents, are
206
247
  * not resolved by this function, as they only authenticate HTTP requests;
207
- * use `verifyRequest()` or `getKeyOwner()` for them instead. Keys whose IDs
208
- * are compatible identifiers are never read from or written to the key
209
- * cache under their IDs, except for failures to fetch them.
248
+ * use `verifyRequest()` or `getKeyOwner()` for them instead. Nor are keys
249
+ * of portable actors whose IDs are `ap:` or `ap+ef61:` URIs, for the same
250
+ * reason. Keys whose IDs are compatible identifiers or `ap:` or `ap+ef61:`
251
+ * URIs are never read from or written to the key cache under their IDs,
252
+ * except for failures to fetch them.
210
253
  *
211
254
  * [FEP-ef61]: https://w3id.org/fep/ef61
212
255
  *
@@ -1,9 +1,9 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BZrnW0Qz.mjs";
5
- import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-DCLoLvLz.mjs";
6
- import { a as isCompatibleKeyId, o as isPortableActorDocument, s as isPortableId } from "./portable-key-id-T7lecIbt.mjs";
4
+ import { n as version, t as name } from "./deno-_o3lkDlG.mjs";
5
+ import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-CDaHfBXY.mjs";
6
+ import { c as isPortableId, f as parseKeyIdString, o as isCompatibleKeyId, s as isPortableActorDocument, u as isPortableUri } from "./portable-key-id-Bg259c4Z.mjs";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { CryptographicKey, Multikey, Object as Object$1, isActor } from "@fedify/vocab";
9
9
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -236,6 +236,17 @@ function bypassKeyCacheReads(keyCache) {
236
236
  };
237
237
  return bypassed;
238
238
  }
239
+ /**
240
+ * Parses a key ID given as a string. Unlike `new URL()`, it accepts `ap:`
241
+ * and `ap+ef61:` URIs, and refuses a portable or compatible key ID whose
242
+ * identity URL parsing would change, e.g., by resolving dot segments.
243
+ * @throws {TypeError} If the key ID is invalid.
244
+ */
245
+ function parseKeyIdOrThrow(keyId) {
246
+ const parsed = parseKeyIdString(keyId);
247
+ if (parsed == null) throw new TypeError(`Invalid key ID: ${keyId}`);
248
+ return parsed;
249
+ }
239
250
  async function withFetchKeySpan(keyId, tracerProvider, fetcher) {
240
251
  tracerProvider ??= trace.getTracerProvider();
241
252
  return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.fetch_key", {
@@ -272,9 +283,11 @@ async function withFetchKeySpan(keyId, tracerProvider, fetcher) {
272
283
  * Gateway keys of [FEP-ef61] portable actors, i.e., keys whose IDs are
273
284
  * compatible identifiers that dereference to portable actor documents, are
274
285
  * not resolved by this function, as they only authenticate HTTP requests;
275
- * use `verifyRequest()` or `getKeyOwner()` for them instead. Keys whose IDs
276
- * are compatible identifiers are never read from or written to the key
277
- * cache under their IDs, except for failures to fetch them.
286
+ * use `verifyRequest()` or `getKeyOwner()` for them instead. Nor are keys
287
+ * of portable actors whose IDs are `ap:` or `ap+ef61:` URIs, for the same
288
+ * reason. Keys whose IDs are compatible identifiers or `ap:` or `ap+ef61:`
289
+ * URIs are never read from or written to the key cache under their IDs,
290
+ * except for failures to fetch them.
278
291
  *
279
292
  * [FEP-ef61]: https://w3id.org/fep/ef61
280
293
  * @template T The type of the key to fetch. Either {@link CryptographicKey}
@@ -287,7 +300,7 @@ async function withFetchKeySpan(keyId, tracerProvider, fetcher) {
287
300
  * @since 1.3.0
288
301
  */
289
302
  function fetchKey(keyId, cls, options = {}) {
290
- keyId = typeof keyId === "string" ? new URL(keyId) : keyId;
303
+ keyId = typeof keyId === "string" ? parseKeyIdOrThrow(keyId) : keyId;
291
304
  return withFetchKeySpan(keyId, options.tracerProvider, () => fetchKeyInternal(keyId, cls, options));
292
305
  }
293
306
  /**
@@ -297,9 +310,11 @@ function fetchKey(keyId, cls, options = {}) {
297
310
  * Gateway keys of [FEP-ef61] portable actors, i.e., keys whose IDs are
298
311
  * compatible identifiers that dereference to portable actor documents, are
299
312
  * not resolved by this function, as they only authenticate HTTP requests;
300
- * use `verifyRequest()` or `getKeyOwner()` for them instead. Keys whose IDs
301
- * are compatible identifiers are never read from or written to the key
302
- * cache under their IDs, except for failures to fetch them.
313
+ * use `verifyRequest()` or `getKeyOwner()` for them instead. Nor are keys
314
+ * of portable actors whose IDs are `ap:` or `ap+ef61:` URIs, for the same
315
+ * reason. Keys whose IDs are compatible identifiers or `ap:` or `ap+ef61:`
316
+ * URIs are never read from or written to the key cache under their IDs,
317
+ * except for failures to fetch them.
303
318
  *
304
319
  * [FEP-ef61]: https://w3id.org/fep/ef61
305
320
  *
@@ -313,7 +328,7 @@ function fetchKey(keyId, cls, options = {}) {
313
328
  * @since 2.1.0
314
329
  */
315
330
  async function fetchKeyDetailed(keyId, cls, options = {}) {
316
- const cacheKey = typeof keyId === "string" ? new URL(keyId) : keyId;
331
+ const cacheKey = typeof keyId === "string" ? parseKeyIdOrThrow(keyId) : keyId;
317
332
  return await withFetchKeySpan(cacheKey, options.tracerProvider, async () => {
318
333
  return await fetchKeyWithResult(cacheKey, cls, options, async (cacheKey, keyId, keyCache, logger) => {
319
334
  const fetchError = await keyCache?.getFetchError?.(cacheKey);
@@ -452,7 +467,7 @@ async function resolveDidKey(cacheKey, cls, keyCache, logger) {
452
467
  cached: false
453
468
  };
454
469
  }
455
- async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, { documentLoader, contextLoader, keyCache, tracerProvider, keyIdBoundByCaller, portableGatewayKeyResolver }, logger) {
470
+ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, { documentLoader, contextLoader, keyCache, tracerProvider, keyIdBoundByCaller, portableKeyResolvers }, logger) {
456
471
  let object;
457
472
  try {
458
473
  object = await Object$1.fromJsonLd(document, {
@@ -483,7 +498,7 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
483
498
  }
484
499
  if (isCompatibleKeyId(cacheKey) && isPortableActorDocument(object)) {
485
500
  const scopedCache = keyCache;
486
- if (portableGatewayKeyResolver == null || cls !== CryptographicKey) {
501
+ if (portableKeyResolvers == null || cls !== CryptographicKey) {
487
502
  logger.debug("Failed to verify; key {keyId} is a gateway key of the portable actor {actorId}, which is only accepted for HTTP Signatures.", {
488
503
  keyId,
489
504
  actorId: object.id?.href
@@ -494,7 +509,7 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
494
509
  cached: false
495
510
  };
496
511
  }
497
- const resolution = await portableGatewayKeyResolver(document, object, cacheKey);
512
+ const resolution = await portableKeyResolvers.gatewayKey(document, object, cacheKey);
498
513
  if (resolution.type !== "verified") {
499
514
  logger.debug("Failed to verify; the portable actor {actorId} does not vouch for its gateway key {keyId}.", {
500
515
  keyId,
@@ -654,6 +669,11 @@ async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, o
654
669
  ]);
655
670
  const keyId = cacheKey.href;
656
671
  const keyCache = options.keyCache;
672
+ if (isPortableUri(cacheKey)) {
673
+ const result = await fetchPortableActorKey(cacheKey, cls, options, onCachedUnavailable, onFetchError, logger);
674
+ outcome = result.outcome;
675
+ return result.result;
676
+ }
657
677
  if (isCompatibleKeyId(cacheKey)) {
658
678
  const result = await fetchCompatibleKey(cacheKey, cls, options, onCachedUnavailable, onFetchError, logger);
659
679
  outcome = result.outcome;
@@ -705,7 +725,7 @@ async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, o
705
725
  */
706
726
  function getCompatibleKeyScope(cls, options) {
707
727
  if (cls !== CryptographicKey) return "multikey";
708
- return options.portableGatewayKeyResolver == null ? "cryptographicKey" : "httpSignature";
728
+ return options.portableKeyResolvers == null ? "cryptographicKey" : "httpSignature";
709
729
  }
710
730
  /**
711
731
  * Looks up a key at an [FEP-ef61] compatible identifier. Such a key may be
@@ -759,8 +779,75 @@ async function fetchCompatibleKey(cacheKey, cls, options, onCachedUnavailable, o
759
779
  outcome: { result: resolved.key != null ? "fetched" : "invalid" }
760
780
  };
761
781
  }
782
+ /**
783
+ * Looks up a key of an [FEP-ef61] portable actor at an `ap:` or `ap+ef61:`
784
+ * key ID. Such a key is accepted only for HTTP Signatures, and is rejected
785
+ * for any other purpose without being fetched. Like keys at compatible
786
+ * identifiers, what it resolves to is cached in the namespace of the lookup's
787
+ * purpose, and a failure to fetch the actor's document from every gateway is
788
+ * cached in the shared namespace. A failure that is neither, e.g., one
789
+ * gateway being unreachable while another served an invalid document, is not
790
+ * cached at all.
791
+ *
792
+ * [FEP-ef61]: https://w3id.org/fep/ef61
793
+ */
794
+ async function fetchPortableActorKey(cacheKey, cls, options, onCachedUnavailable, onFetchError, logger) {
795
+ const keyId = cacheKey.href;
796
+ const resolvers = options.portableKeyResolvers;
797
+ if (resolvers == null || cls !== CryptographicKey) {
798
+ logger.debug("Failed to verify; key {keyId} is a key of a portable actor, which is only accepted for HTTP Signatures.", { keyId });
799
+ return {
800
+ result: {
801
+ key: null,
802
+ cached: false
803
+ },
804
+ outcome: { result: "invalid" }
805
+ };
806
+ }
807
+ const sharedCache = options.keyCache;
808
+ const scopedCache = sharedCache?.compatibleKeyScope?.("httpSignature");
809
+ const cached = await getCachedFetchKey(cacheKey, keyId, cls, scopedCache, logger);
810
+ if (cached != null) return {
811
+ result: cached,
812
+ outcome: { result: "hit" }
813
+ };
814
+ if (await sharedCache?.get(cacheKey) === null) {
815
+ logger.debug("Entry {keyId} found in cache, but it could not be fetched.", { keyId });
816
+ return {
817
+ result: await onCachedUnavailable(cacheKey, keyId, sharedCache, logger),
818
+ outcome: { result: "hit" }
819
+ };
820
+ }
821
+ logger.debug("Resolving key {keyId} to verify signature...", { keyId });
822
+ const resolution = await resolvers.actorKey(cacheKey);
823
+ if (resolution.type === "verified") {
824
+ await scopedCache?.set(cacheKey, resolution.key, { expires: resolution.expires });
825
+ return {
826
+ result: {
827
+ key: resolution.key,
828
+ cached: false
829
+ },
830
+ outcome: { result: "fetched" }
831
+ };
832
+ }
833
+ if (resolution.type === "rejected") {
834
+ await scopedCache?.set(cacheKey, null);
835
+ return {
836
+ result: {
837
+ key: null,
838
+ cached: false
839
+ },
840
+ outcome: { result: "invalid" }
841
+ };
842
+ }
843
+ await scopedCache?.delete(cacheKey);
844
+ return {
845
+ result: await onFetchError(resolution.error, cacheKey, keyId, resolution.cacheable ? sharedCache : void 0, logger),
846
+ outcome: resolution.cacheable ? classifyFetchError(resolution.error) : { result: "error" }
847
+ };
848
+ }
762
849
  async function fetchKeyInternal(keyId, cls, options = {}) {
763
- return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
850
+ return await fetchKeyWithResult(typeof keyId === "string" ? parseKeyIdOrThrow(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
764
851
  return {
765
852
  key: null,
766
853
  cached: true
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { p as recordDocumentCache } from "./metrics-DCLoLvLz.mjs";
4
+ import { p as recordDocumentCache } from "./metrics-CDaHfBXY.mjs";
5
5
  import { getLogger } from "@logtape/logtape";
6
6
  import { preloadedContexts } from "@fedify/vocab-runtime";
7
7
  //#region src/utils/kv-cache.ts
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { H as validateCryptoKey, et as recordDocumentCache, t as doubleKnock } from "./http-BETASGl0.js";
3
+ import { U as validateCryptoKey, t as doubleKnock, tt as recordDocumentCache } from "./http-C2M6wcs8.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
6
6
  import { curry } from "es-toolkit";
@@ -24,21 +24,21 @@ const logger$1 = getLogger([
24
24
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, tracerProvider } = {}) {
25
25
  validateCryptoKey(identity.privateKey);
26
26
  async function load(url, options) {
27
- await validateUrl(url);
27
+ await validateUrl(url, options);
28
28
  return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
29
29
  maxRedirection,
30
30
  specDeterminer,
31
31
  log: curry(logRequest)(logger$1),
32
32
  tracerProvider,
33
33
  signal: options?.signal,
34
- validateRedirect: validateUrl
35
- }), load);
34
+ validateRedirect: (url) => validateUrl(url, options)
35
+ }), load, options);
36
36
  }
37
- async function validateUrl(url) {
37
+ async function validateUrl(url, options) {
38
38
  if (!allowPrivateAddress) try {
39
39
  await validatePublicUrl(url);
40
40
  } catch (error) {
41
- if (error instanceof UrlError) logger$1.error("Disallowed private URL: {url}", {
41
+ if (error instanceof UrlError) logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
42
42
  url,
43
43
  error
44
44
  });
@@ -1,5 +1,5 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
- const require_http = require("./http-4bmgw-mA.cjs");
2
+ const require_http = require("./http-B1J6E-bT.cjs");
3
3
  let _logtape_logtape = require("@logtape/logtape");
4
4
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
5
5
  let es_toolkit = require("es-toolkit");
@@ -23,21 +23,21 @@ const logger$1 = (0, _logtape_logtape.getLogger)([
23
23
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, tracerProvider } = {}) {
24
24
  require_http.validateCryptoKey(identity.privateKey);
25
25
  async function load(url, options) {
26
- await validateUrl(url);
26
+ await validateUrl(url, options);
27
27
  return (0, _fedify_vocab_runtime.getRemoteDocument)(url, await require_http.doubleKnock((0, _fedify_vocab_runtime.createActivityPubRequest)(url, { userAgent }), identity, {
28
28
  maxRedirection,
29
29
  specDeterminer,
30
30
  log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
31
31
  tracerProvider,
32
32
  signal: options?.signal,
33
- validateRedirect: validateUrl
34
- }), load);
33
+ validateRedirect: (url) => validateUrl(url, options)
34
+ }), load, options);
35
35
  }
36
- async function validateUrl(url) {
36
+ async function validateUrl(url, options) {
37
37
  if (!allowPrivateAddress) try {
38
38
  await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
39
39
  } catch (error) {
40
- if (error instanceof _fedify_vocab_runtime.UrlError) logger$1.error("Disallowed private URL: {url}", {
40
+ if (error instanceof _fedify_vocab_runtime.UrlError) logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
41
41
  url,
42
42
  error
43
43
  });
@@ -1,9 +1,9 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BZrnW0Qz.mjs";
5
- import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-DCLoLvLz.mjs";
6
- import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-PyYvun0F.mjs";
4
+ import { n as version, t as name } from "./deno-_o3lkDlG.mjs";
5
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-CDaHfBXY.mjs";
6
+ import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-DolJjJab.mjs";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -1,7 +1,7 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BZrnW0Qz.mjs";
4
+ import { n as version, t as name } from "./deno-_o3lkDlG.mjs";
5
5
  import { metrics } from "@opentelemetry/api";
6
6
  import { FetchError } from "@fedify/vocab-runtime";
7
7
  //#region src/federation/metrics.ts
@@ -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-CgOqRkK-.mjs";
4
+ import { n as FederationImpl } from "./middleware-DN3MdTDg.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 recordCollectionTotalItems, A as isInvalidUrlTypeError, C as compactJsonLd, D as hasSignature, E as getNormalizationContextLoader, F as wrapContextLoaderForJsonLd, G as getFederationMetrics, H as validateCryptoKey, I as exportJwk, J as isAbortError, K as getRemoteHost, M as verifyCompactJsonLd, O as hasSignatureLike, Q as recordCollectionRequest, T as detachSignature, V as importJwk, W as getDurationMs, X as recordCollectionDispatchDuration, Y as recordCircuitBreakerStateChange, Z as recordCollectionPageItems, _ as verifyPortableObjectProofWithRoot, _t as isPortableId, at as recordWebFingerHandle, b as InvalidContextReferenceError, bt as name, ct as formatAcceptSignature, d as hasProofLike, f as signObject, ft as getCanonicalPortableId, g as verifyPortableObjectProofPolicy, gt as isCompatibleKeyId, h as verifyPortableObjectProof, ht as hasPortableActor, i as selectRequestSignature, it as recordOutboxEnqueue, j as signJsonLd, k as isClearlyMalformedContextReference, l as InvalidPortableObjectIdError, m as verifyObject, mt as getPortableDid, n as listRequestSignatures, nt as recordInboxActivity, o as verifyRequest, ot as registerQueueDepthGauge, p as verifyMapLocalProof, pt as getGatewayKeyBase, q as instrumentDocumentLoader, r as parseRfc9421SignatureInput, rt as recordOutboxActivity, s as verifyRequestDetailed, st as preloadedOnlyDocumentLoader, t as doubleKnock, tt as recordFanoutRecipients, vt as isPortableUri, x as assertSafeJsonLd, xt as version, y as normalizeOutgoingActivityJsonLd } from "./http-BETASGl0.js";
5
+ import { $ as recordCollectionRequest, A as isClearlyMalformedContextReference, Ct as version, D as getNormalizationContextLoader, E as detachSignature, G as getDurationMs, H as importJwk, I as wrapContextLoaderForJsonLd, J as instrumentDocumentLoader, K as getFederationMetrics, L as exportJwk, M as signJsonLd, N as verifyCompactJsonLd, O as hasSignature, Q as recordCollectionPageItems, S as assertSafeJsonLd, St as name, U as validateCryptoKey, X as recordCircuitBreakerStateChange, Y as isAbortError, Z as recordCollectionDispatchDuration, _ as verifyPortableObjectProofPolicy, _t as isCompatibleKeyId, at as recordOutboxEnqueue, b as normalizeOutgoingActivityJsonLd, bt as isPortableUri, ct as preloadedOnlyDocumentLoader, et as recordCollectionTotalItems, f as hasProofLike, g as verifyPortableObjectProof, gt as hasPortableActor, h as verifyObject, ht as getPortableDid, i as selectRequestSignature, it as recordOutboxActivity, j as isInvalidUrlTypeError, k as hasSignatureLike, lt as formatAcceptSignature, m as verifyMapLocalProof, mt as getGatewayKeyBase, n as listRequestSignatures, nt as recordFanoutRecipients, o as verifyRequest, ot as recordWebFingerHandle, p as signObject, pt as getCanonicalPortableId, q as getRemoteHost, r as parseRfc9421SignatureInput, rt as recordInboxActivity, s as verifyRequestDetailed, st as registerQueueDepthGauge, t as doubleKnock, u as InvalidPortableObjectIdError, v as verifyPortableObjectProofWithRoot, vt as isPortableId, w as compactJsonLd, x as InvalidContextReferenceError, yt as isPortableKeyId } from "./http-C2M6wcs8.js";
6
6
  import { a as MAX_BODY_SIZE, i as BodyTooLargeError, n as getNodeInfo, o as readBoundedText, t as nodeInfoToJson } from "./types-C_cNlNVK.js";
7
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-wNinn7RK.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-C4mv2ZFQ.js";
7
+ import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "./portable-collection-CgglAI9B.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-D7TiyMxv.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, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
@@ -3668,13 +3668,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
3668
3668
  * @param parameters The parameters for handling the collection.
3669
3669
  * @returns A promise that resolves to an HTTP response.
3670
3670
  */
3671
- async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
3672
- const spanName = name$1.trim().replace(/\s+/g, "_");
3671
+ async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
3672
+ const spanName = name$2.trim().replace(/\s+/g, "_");
3673
3673
  tracerProvider = tracerProvider ?? trace.getTracerProvider();
3674
3674
  const tracer = tracerProvider.getTracer(name, version);
3675
3675
  const cursor = new URL(request.url).searchParams.get("cursor");
3676
3676
  const metricBase = {
3677
- kind: getCollectionMetricKind(name$1),
3677
+ kind: getCollectionMetricKind(name$2),
3678
3678
  page: cursor != null,
3679
3679
  dispatcher: "built_in"
3680
3680
  };
@@ -3715,7 +3715,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
3715
3715
  span.setStatus({ code: SpanStatusCode.ERROR });
3716
3716
  return await onNotFound(request);
3717
3717
  }
3718
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
3718
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
3719
3719
  itemCount = items.length;
3720
3720
  span.setAttribute("fedify.collection.items", itemCount);
3721
3721
  return items;
@@ -3755,7 +3755,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
3755
3755
  } else {
3756
3756
  const uri = new URL(baseUri);
3757
3757
  uri.searchParams.set("cursor", cursor);
3758
- const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
3758
+ const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
3759
3759
  kind: SpanKind.SERVER,
3760
3760
  attributes: {
3761
3761
  "activitypub.collection.id": uri.href,
@@ -3771,7 +3771,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
3771
3771
  span.setStatus({ code: SpanStatusCode.ERROR });
3772
3772
  return await onNotFound(request);
3773
3773
  }
3774
- const items = filterCollectionItems(page.items, name$1, filterPredicate);
3774
+ const items = filterCollectionItems(page.items, name$2, filterPredicate);
3775
3775
  itemCount = items.length;
3776
3776
  span.setAttribute("fedify.collection.items", itemCount);
3777
3777
  return {
@@ -4506,7 +4506,8 @@ async function handleInboxInternal(request, parameters, span) {
4506
4506
  documentLoader: ctx.documentLoader,
4507
4507
  keyCache,
4508
4508
  meterProvider,
4509
- tracerProvider
4509
+ tracerProvider,
4510
+ verifyPortableObject: ctx.verifyPortableObject
4510
4511
  });
4511
4512
  } catch (error) {
4512
4513
  if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(jsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
@@ -4664,7 +4665,7 @@ async function handleInboxInternal(request, parameters, span) {
4664
4665
  "http_signatures.verified": httpSigKey != null,
4665
4666
  "http_signatures.key_id": httpSigKey?.id?.href ?? ""
4666
4667
  });
4667
- if (!skipSignatureVerification && !proofVerified && (isPortableActivity(activity) || isPortableGatewayKey(httpSigKey))) {
4668
+ if (!skipSignatureVerification && !proofVerified && (isPortableActivity(activity) || isPortableActorKey(httpSigKey))) {
4668
4669
  if (deferredLdSignatureError != null) throw deferredLdSignatureError;
4669
4670
  logger.error("The activity {activityId} of the portable actor {actorId} is not authenticated by a valid Object Integrity Proof.", {
4670
4671
  activity: json,
@@ -4959,8 +4960,8 @@ var CustomCollectionHandler = class {
4959
4960
  * @param CollectionPage The CollectionPage constructor.
4960
4961
  * @param filterPredicate Optional filter predicate for items.
4961
4962
  */
4962
- constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
4963
- this.name = name$2;
4963
+ constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
4964
+ this.name = name$1;
4964
4965
  this.values = values;
4965
4966
  this.context = context;
4966
4967
  this.callbacks = callbacks;
@@ -5445,13 +5446,13 @@ const MIN_COMPONENTS = [
5445
5446
  "@authority"
5446
5447
  ];
5447
5448
  /**
5448
- * Checks whether an HTTP Signature key is a gateway key of an FEP-ef61
5449
- * portable actor, i.e., its ID is a compatible identifier and it is owned by
5450
- * a portable actor, which only the portable actor's signed document can
5451
- * establish.
5449
+ * Checks whether an HTTP Signature key is a key of an FEP-ef61 portable
5450
+ * actor, i.e., its ID is a compatible identifier or an `ap:` or `ap+ef61:`
5451
+ * URI, and it is owned by a portable actor, which only the portable actor's
5452
+ * signed document can establish.
5452
5453
  */
5453
- function isPortableGatewayKey(key) {
5454
- return key?.id != null && isCompatibleKeyId(key.id) && key.ownerId != null && isPortableId(key.ownerId);
5454
+ function isPortableActorKey(key) {
5455
+ return key?.id != null && isPortableKeyId(key.id) && key.ownerId != null && isPortableId(key.ownerId);
5455
5456
  }
5456
5457
  /**
5457
5458
  * Checks whether an activity needs an Object Integrity Proof by its DID:
@@ -5800,7 +5801,7 @@ async function signOutgoingActivity(activity, candidates, options) {
5800
5801
  hasProof = true;
5801
5802
  break;
5802
5803
  }
5803
- const keys = candidates.filter((c) => c.privateKey.algorithm.name === "Ed25519" && !isCompatibleKeyId(c.verificationMethod));
5804
+ const keys = candidates.filter((c) => c.privateKey.algorithm.name === "Ed25519" && !isPortableKeyId(c.verificationMethod));
5804
5805
  if (!hasProof && activity.id != null && isPortableId(activity.id)) return await sign(selectPortableActivityKey(activity, activity.id, keys));
5805
5806
  if (keys.length < 1 || hasProof && !options.appendToExistingProofs) return {
5806
5807
  activity,
@@ -7114,11 +7115,16 @@ var FederationImpl = class extends FederationBuilderImpl {
7114
7115
  });
7115
7116
  return parsedActorIds;
7116
7117
  };
7117
- const parseActivity = () => Activity.fromJsonLd(message.activity, {
7118
- contextLoader: this.contextLoaderFactory(loaderOptions),
7119
- documentLoader: rsaKeyPair == null ? this.documentLoaderFactory(loaderOptions) : this.authenticatedDocumentLoaderFactory(rsaKeyPair, loaderOptions),
7120
- tracerProvider: this.tracerProvider
7121
- });
7118
+ const parseActivity = () => {
7119
+ const contextLoader = this.contextLoaderFactory(loaderOptions);
7120
+ const documentLoader = rsaKeyPair == null ? this.documentLoaderFactory(loaderOptions) : this.authenticatedDocumentLoaderFactory(rsaKeyPair, loaderOptions);
7121
+ return Activity.fromJsonLd(message.activity, {
7122
+ contextLoader,
7123
+ documentLoader,
7124
+ tracerProvider: this.tracerProvider,
7125
+ verifyPortableObject: createPortableObjectVerifier(documentLoader, contextLoader, this)
7126
+ });
7127
+ };
7122
7128
  const enqueueHeldOutboxMessage = async (delay, heldSince) => {
7123
7129
  const { outboxQueue } = this;
7124
7130
  if (outboxQueue == null) return;
@@ -7760,7 +7766,7 @@ var FederationImpl = class extends FederationBuilderImpl {
7760
7766
  const ldSignable = !hasPortableActor(activity);
7761
7767
  for (const { keyId, privateKey } of keys) {
7762
7768
  validateCryptoKey(privateKey, "private");
7763
- if (ldSignable && rsaKey == null && privateKey.algorithm.name === "RSASSA-PKCS1-v1_5" && !isCompatibleKeyId(keyId)) rsaKey = {
7769
+ if (ldSignable && rsaKey == null && privateKey.algorithm.name === "RSASSA-PKCS1-v1_5" && !isPortableKeyId(keyId)) rsaKey = {
7764
7770
  keyId,
7765
7771
  privateKey
7766
7772
  };
@@ -8594,12 +8600,28 @@ function getCollectionMetricRoute(routeName) {
8594
8600
  }
8595
8601
  }
8596
8602
  const FANOUT_THRESHOLD = 5;
8603
+ /**
8604
+ * Creates the FEP-ef61 portable object verifier that a context applies to
8605
+ * portable objects it dereferences: `verifyPortableObject()` with the given
8606
+ * loaders and the federation's tracer provider as defaults. Other options,
8607
+ * such as the document URL, gateways, and referrer, are passed through as
8608
+ * they are.
8609
+ */
8610
+ function createPortableObjectVerifier(documentLoader, contextLoader, federation) {
8611
+ return (document, options = {}) => verifyPortableObject(document, {
8612
+ ...options,
8613
+ documentLoader: options.documentLoader ?? documentLoader,
8614
+ contextLoader: options.contextLoader ?? contextLoader,
8615
+ tracerProvider: options.tracerProvider ?? federation.tracerProvider
8616
+ });
8617
+ }
8597
8618
  var ContextImpl = class ContextImpl {
8598
8619
  url;
8599
8620
  federation;
8600
8621
  data;
8601
8622
  documentLoader;
8602
8623
  contextLoader;
8624
+ verifyPortableObject;
8603
8625
  invokedFromActorKeyPairsDispatcher;
8604
8626
  #codec;
8605
8627
  constructor({ url, federation, data, documentLoader, contextLoader, invokedFromActorKeyPairsDispatcher }) {
@@ -8608,6 +8630,7 @@ var ContextImpl = class ContextImpl {
8608
8630
  this.data = data;
8609
8631
  this.documentLoader = documentLoader;
8610
8632
  this.contextLoader = contextLoader;
8633
+ this.verifyPortableObject = createPortableObjectVerifier(documentLoader, contextLoader, federation);
8611
8634
  this.invokedFromActorKeyPairsDispatcher = invokedFromActorKeyPairsDispatcher;
8612
8635
  }
8613
8636
  /**
@@ -8959,7 +8982,7 @@ var ContextImpl = class ContextImpl {
8959
8982
  userAgent: options.userAgent ?? this.federation.userAgent,
8960
8983
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
8961
8984
  meterProvider: options.meterProvider ?? this.meterProvider,
8962
- verifyPortableObject: options.verifyPortableObject ?? verifyPortableObjectProof,
8985
+ verifyPortableObject: options.verifyPortableObject ?? this.verifyPortableObject,
8963
8986
  allowPrivateAddress: this.federation.allowPrivateAddress
8964
8987
  });
8965
8988
  }
@@ -8967,7 +8990,8 @@ var ContextImpl = class ContextImpl {
8967
8990
  return traverseCollection(collection, {
8968
8991
  ...options,
8969
8992
  documentLoader: options.documentLoader ?? this.documentLoader,
8970
- contextLoader: options.contextLoader ?? this.contextLoader
8993
+ contextLoader: options.contextLoader ?? this.contextLoader,
8994
+ verifyPortableObject: options.verifyPortableObject ?? this.verifyPortableObject
8971
8995
  });
8972
8996
  }
8973
8997
  lookupNodeInfo(url, options = {}) {