@fedify/fedify 2.1.26 → 2.1.28

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 (58) hide show
  1. package/dist/{builder-9KbL1CoC.mjs → builder-CW1BrLbm.mjs} +3 -3
  2. package/dist/compat/transformers.test.mjs +2 -2
  3. package/dist/{deno-ChmEXNOv.mjs → deno-CJgU2mcr.mjs} +1 -1
  4. package/dist/{docloader-DEVImb5e.mjs → docloader-o3fCIlIa.mjs} +2 -2
  5. package/dist/federation/builder.test.mjs +2 -2
  6. package/dist/federation/collection.test.mjs +1 -1
  7. package/dist/federation/handler.test.mjs +7 -7
  8. package/dist/federation/idempotency.test.mjs +3 -3
  9. package/dist/federation/inbox.test.mjs +1 -1
  10. package/dist/federation/keycache.test.mjs +33 -2
  11. package/dist/federation/kv.test.mjs +1 -1
  12. package/dist/federation/middleware.test.mjs +7 -7
  13. package/dist/federation/mod.cjs +1 -1
  14. package/dist/federation/mod.js +1 -1
  15. package/dist/federation/send.test.mjs +3 -3
  16. package/dist/federation/temporal.test.mjs +1 -1
  17. package/dist/federation/webfinger.test.mjs +2 -2
  18. package/dist/{http-B_M80hBW.mjs → http-Dcj1ulAh.mjs} +2 -2
  19. package/dist/{http-CeK9QmL_.js → http-DtypHuuK.js} +104 -10
  20. package/dist/{http-BOH-uFLj.cjs → http-EEfKB8Qb.cjs} +103 -9
  21. package/dist/{inbox-B_O6TjZS.mjs → inbox-CVYVJI0M.mjs} +1 -1
  22. package/dist/{key-BJcK-1Av.mjs → key-DRLvwDTh.mjs} +104 -10
  23. package/dist/{keycache-CaO7wyQA.mjs → keycache-RFlZObU3.mjs} +23 -2
  24. package/dist/{kv-cache-BlOG31SS.cjs → kv-cache-BWVKAAmc.cjs} +1 -1
  25. package/dist/{kv-cache-CEJICY0R.js → kv-cache-CEJCaF4E.js} +1 -1
  26. package/dist/{ld-YAXn6sG8.mjs → ld-C5BZ98YK.mjs} +2 -2
  27. package/dist/{middleware-DmTWC5VG.mjs → middleware-CqQoREZ9.mjs} +1 -1
  28. package/dist/{middleware-dGW2gSDG.cjs → middleware-DZxmsbPB.cjs} +1 -1
  29. package/dist/{middleware-DHGVHIUj.cjs → middleware-Dw9sPiec.cjs} +26 -6
  30. package/dist/{middleware-Co_QOX9H.mjs → middleware-SSrXiJIV.mjs} +15 -15
  31. package/dist/{middleware-C-45wr85.js → middleware-wCgWm4Eh.js} +25 -5
  32. package/dist/mod.cjs +4 -4
  33. package/dist/mod.js +4 -4
  34. package/dist/nodeinfo/client.test.mjs +1 -1
  35. package/dist/nodeinfo/handler.test.mjs +2 -2
  36. package/dist/nodeinfo/types.test.mjs +1 -1
  37. package/dist/otel/exporter.test.mjs +1 -1
  38. package/dist/{owner-B3ZkY-Ov.mjs → owner-cPOoPvmr.mjs} +2 -2
  39. package/dist/{proof-DIGrz49z.mjs → proof-BTknCsN7.mjs} +2 -2
  40. package/dist/{proof-BeGIkK97.js → proof-DPU3poip.js} +1 -1
  41. package/dist/{proof-DzOl2GlQ.cjs → proof-De1y2j-e.cjs} +1 -1
  42. package/dist/{send-N2w1IwXT.mjs → send-DDuHNgHz.mjs} +2 -2
  43. package/dist/sig/http.test.mjs +62 -3
  44. package/dist/sig/key.test.mjs +198 -4
  45. package/dist/sig/ld.test.mjs +2 -2
  46. package/dist/sig/mod.cjs +2 -2
  47. package/dist/sig/mod.js +2 -2
  48. package/dist/sig/owner.test.mjs +1 -1
  49. package/dist/sig/proof.test.mjs +1 -1
  50. package/dist/{temporal-CpT0u5Mx.mjs → temporal-CxXY--ZL.mjs} +1 -1
  51. package/dist/utils/docloader.test.mjs +2 -2
  52. package/dist/utils/mod.cjs +1 -1
  53. package/dist/utils/mod.js +1 -1
  54. package/package.json +6 -6
  55. /package/dist/{client-DM72NZuk.mjs → client-CjDMsn4a.mjs} +0 -0
  56. /package/dist/{collection-ChgDTHLz.mjs → collection-BD6-SZ6O.mjs} +0 -0
  57. /package/dist/{kv-BrZHNugx.mjs → kv-HvthQAHr.mjs} +0 -0
  58. /package/dist/{types-C37hquWI.mjs → types-DCP0WLdt.mjs} +0 -0
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
11
11
  let byte_encodings_base64 = require("byte-encodings/base64");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.1.26";
14
+ var version = "2.1.28";
15
15
  //#endregion
16
16
  //#region src/sig/accept.ts
17
17
  /**
@@ -153,6 +153,64 @@ function fulfillAcceptSignature(entry, localKeyId, localAlg) {
153
153
  }
154
154
  //#endregion
155
155
  //#region src/sig/key.ts
156
+ /** Classifies decoding failures without hiding unexpected loader errors. */
157
+ function classifyKeyJsonLdError(error, seen = /* @__PURE__ */ new Set()) {
158
+ if (!(error instanceof Error) || !error.name.startsWith("jsonld.")) return null;
159
+ if (seen.has(error)) throw error;
160
+ seen.add(error);
161
+ const details = error.details;
162
+ if (typeof details?.code !== "string") return null;
163
+ if (details.code !== "loading remote context failed" || !("cause" in details) && !("cause" in error)) return "invalid";
164
+ const cause = "cause" in details ? details.cause : error.cause;
165
+ const nestedFailure = classifyKeyJsonLdError(cause, seen);
166
+ if (nestedFailure != null) return nestedFailure;
167
+ if (cause instanceof SyntaxError) return "invalid";
168
+ if (cause instanceof _fedify_vocab_runtime.FetchError || cause instanceof _fedify_vocab_runtime.UrlError) return "fetch";
169
+ if (cause instanceof Error && [
170
+ "AbortError",
171
+ "TimeoutError",
172
+ "NetworkError"
173
+ ].includes(cause.name)) return "fetch";
174
+ if (cause instanceof TypeError) {
175
+ const urlCode = cause.code;
176
+ if (cause.name === "InvalidContextReferenceError") return "invalid";
177
+ if (urlCode === "ERR_INVALID_URL" || cause.message === "Invalid URL string." || /^Invalid URL(?::|$)/.test(cause.message) || / cannot be parsed as a URL\.?$/.test(cause.message)) return typeof details.url === "string" && /^[A-Za-z][A-Za-z0-9+.-]*:/.test(details.url) && !URL.canParse(details.url) ? "invalid" : "fetch";
178
+ const networkCause = cause.cause;
179
+ const code = cause.code ?? networkCause?.code;
180
+ if (typeof code === "string" && [
181
+ "ECONNREFUSED",
182
+ "ECONNRESET",
183
+ "ECONNABORTED",
184
+ "ETIMEDOUT",
185
+ "EHOSTUNREACH",
186
+ "ENETUNREACH",
187
+ "ENOTFOUND",
188
+ "EAI_AGAIN",
189
+ "UND_ERR_CONNECT_TIMEOUT",
190
+ "UND_ERR_HEADERS_TIMEOUT",
191
+ "UND_ERR_BODY_TIMEOUT",
192
+ "UND_ERR_SOCKET"
193
+ ].includes(code) || /^(fetch failed|Failed to fetch|error sending request|error reading a body from connection|Unable to connect|ConnectionRefused|Network connection lost|The socket connection was closed unexpectedly)/.test(cause.message)) return "fetch";
194
+ }
195
+ throw cause;
196
+ }
197
+ /** Carries a context transport failure through the key decoding boundary. */
198
+ var KeyContextFetchError = class extends Error {
199
+ constructor(error) {
200
+ super("Failed to fetch a key's JSON-LD context.", { cause: error });
201
+ this.error = error;
202
+ }
203
+ };
204
+ function contextFetchError(error) {
205
+ const seen = /* @__PURE__ */ new Set();
206
+ while (error instanceof Error && !seen.has(error)) {
207
+ seen.add(error);
208
+ const details = error.details;
209
+ if (!error.name.startsWith("jsonld.") || details?.code !== "loading remote context failed") break;
210
+ error = "cause" in details ? details.cause : error.cause;
211
+ }
212
+ return new KeyContextFetchError(error);
213
+ }
156
214
  /**
157
215
  * Checks if the given key is valid and supported. No-op if the key is valid,
158
216
  * otherwise throws an error.
@@ -247,6 +305,9 @@ async function importJwk(jwk, type) {
247
305
  * @internal
248
306
  */
249
307
  async function fetchActorDocument(actorId, options = {}) {
308
+ return await fetchActorDocumentInternal(actorId, options, false);
309
+ }
310
+ async function fetchActorDocumentInternal(actorId, options, propagateContextFetchErrors) {
250
311
  const logger = (0, _logtape_logtape.getLogger)([
251
312
  "fedify",
252
313
  "sig",
@@ -277,9 +338,12 @@ async function fetchActorDocument(actorId, options = {}) {
277
338
  baseUrl: documentUrl
278
339
  });
279
340
  } catch (error) {
280
- if (!(error instanceof TypeError)) throw error;
281
- logger.debug("The document served at {documentUrl} is not a valid object: {error}", {
341
+ const failure = classifyKeyJsonLdError(error);
342
+ if (failure === "fetch" && propagateContextFetchErrors) throw contextFetchError(error);
343
+ if (failure == null && !(error instanceof TypeError)) throw error;
344
+ logger.debug("Failed to decode the actor document at {documentUrl}: {error}", {
282
345
  documentUrl: documentUrl.href,
346
+ failure: failure ?? "invalid",
283
347
  error
284
348
  });
285
349
  return null;
@@ -318,6 +382,9 @@ async function fetchActorDocument(actorId, options = {}) {
318
382
  * @internal
319
383
  */
320
384
  async function verifyKeyOwnership(key, options = {}) {
385
+ return await verifyKeyOwnershipInternal(key, options, false);
386
+ }
387
+ async function verifyKeyOwnershipInternal(key, options, propagateContextFetchErrors) {
321
388
  const logger = (0, _logtape_logtape.getLogger)([
322
389
  "fedify",
323
390
  "sig",
@@ -327,7 +394,7 @@ async function verifyKeyOwnership(key, options = {}) {
327
394
  if (keyId == null) return null;
328
395
  const claimedOwnerId = key instanceof _fedify_vocab.CryptographicKey ? key.ownerId : key.controllerId;
329
396
  if (claimedOwnerId == null) return null;
330
- const owner = await fetchActorDocument(claimedOwnerId, options);
397
+ const owner = await fetchActorDocumentInternal(claimedOwnerId, options, propagateContextFetchErrors);
331
398
  if (owner == null) {
332
399
  logger.debug("The owner ({claimedOwnerId}) that key {keyId} claims could not be resolved.", {
333
400
  keyId: keyId.href,
@@ -479,6 +546,21 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
479
546
  tracerProvider
480
547
  });
481
548
  } catch (e) {
549
+ const failure = classifyKeyJsonLdError(e);
550
+ if (failure === "fetch") throw contextFetchError(e);
551
+ if (failure != null) {
552
+ logger.debug("Failed to decode key {keyId}: {error}", {
553
+ keyId,
554
+ failure,
555
+ error: e
556
+ });
557
+ await keyCache?.set(cacheKey, null);
558
+ await clearFetchErrorMetadata(cacheKey, keyCache);
559
+ return {
560
+ key: null,
561
+ cached: false
562
+ };
563
+ }
482
564
  if (!(e instanceof TypeError)) throw e;
483
565
  try {
484
566
  object = await cls.fromJsonLd(document, {
@@ -487,8 +569,14 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
487
569
  tracerProvider
488
570
  });
489
571
  } catch (e) {
490
- if (e instanceof TypeError) {
491
- logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
572
+ const failure = classifyKeyJsonLdError(e);
573
+ if (failure === "fetch") throw contextFetchError(e);
574
+ if (failure != null || e instanceof TypeError) {
575
+ logger.debug("Failed to decode key {keyId}: {error}", {
576
+ keyId,
577
+ failure: failure ?? "invalid",
578
+ error: e
579
+ });
492
580
  await keyCache?.set(cacheKey, null);
493
581
  await clearFetchErrorMetadata(cacheKey, keyCache);
494
582
  return {
@@ -580,16 +668,17 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
580
668
  const claimedOwnerId = key instanceof _fedify_vocab.CryptographicKey ? key.ownerId : key.controllerId;
581
669
  if (ownerDocument != null && claimedOwnerId == null) key = key instanceof _fedify_vocab.CryptographicKey ? key.clone({ owner: ownerDocument.id }) : key.clone({ controller: ownerDocument.id });
582
670
  else if (claimedOwnerId != null && claimedOwnerId.href !== ownerDocument?.id?.href) {
583
- if (await verifyKeyOwnership(key, {
671
+ if (await verifyKeyOwnershipInternal(key, {
584
672
  documentLoader,
585
673
  contextLoader,
586
674
  tracerProvider
587
- }) == null) {
675
+ }, true) == null) {
588
676
  logger.debug("Failed to verify; the owner {claimedOwnerId} that key {keyId} claims does not list the key as its own.", {
589
677
  keyId,
590
678
  claimedOwnerId: claimedOwnerId.href
591
679
  });
592
680
  await keyCache?.set(cacheKey, null);
681
+ await clearFetchErrorMetadata(cacheKey, keyCache);
593
682
  return {
594
683
  key: null,
595
684
  cached: false
@@ -627,7 +716,12 @@ async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, o
627
716
  } catch (error) {
628
717
  return await onFetchError(error, cacheKey, keyId, keyCache, logger);
629
718
  }
630
- return await resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, options, logger);
719
+ try {
720
+ return await resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, options, logger);
721
+ } catch (error) {
722
+ if (!(error instanceof KeyContextFetchError)) throw error;
723
+ return await onFetchError(error.error, cacheKey, keyId, keyCache, logger);
724
+ }
631
725
  }
632
726
  async function fetchKeyInternal(keyId, cls, options = {}) {
633
727
  return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-ChmEXNOv.mjs";
4
+ import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
5
5
  import { Activity, getTypeId } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
@@ -1,12 +1,70 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-ChmEXNOv.mjs";
4
+ import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
5
5
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
- import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
7
+ import { FetchError, UrlError, getDocumentLoader } from "@fedify/vocab-runtime";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  //#region src/sig/key.ts
10
+ /** Classifies decoding failures without hiding unexpected loader errors. */
11
+ function classifyKeyJsonLdError(error, seen = /* @__PURE__ */ new Set()) {
12
+ if (!(error instanceof Error) || !error.name.startsWith("jsonld.")) return null;
13
+ if (seen.has(error)) throw error;
14
+ seen.add(error);
15
+ const details = error.details;
16
+ if (typeof details?.code !== "string") return null;
17
+ if (details.code !== "loading remote context failed" || !("cause" in details) && !("cause" in error)) return "invalid";
18
+ const cause = "cause" in details ? details.cause : error.cause;
19
+ const nestedFailure = classifyKeyJsonLdError(cause, seen);
20
+ if (nestedFailure != null) return nestedFailure;
21
+ if (cause instanceof SyntaxError) return "invalid";
22
+ if (cause instanceof FetchError || cause instanceof UrlError) return "fetch";
23
+ if (cause instanceof Error && [
24
+ "AbortError",
25
+ "TimeoutError",
26
+ "NetworkError"
27
+ ].includes(cause.name)) return "fetch";
28
+ if (cause instanceof TypeError) {
29
+ const urlCode = cause.code;
30
+ if (cause.name === "InvalidContextReferenceError") return "invalid";
31
+ if (urlCode === "ERR_INVALID_URL" || cause.message === "Invalid URL string." || /^Invalid URL(?::|$)/.test(cause.message) || / cannot be parsed as a URL\.?$/.test(cause.message)) return typeof details.url === "string" && /^[A-Za-z][A-Za-z0-9+.-]*:/.test(details.url) && !URL.canParse(details.url) ? "invalid" : "fetch";
32
+ const networkCause = cause.cause;
33
+ const code = cause.code ?? networkCause?.code;
34
+ if (typeof code === "string" && [
35
+ "ECONNREFUSED",
36
+ "ECONNRESET",
37
+ "ECONNABORTED",
38
+ "ETIMEDOUT",
39
+ "EHOSTUNREACH",
40
+ "ENETUNREACH",
41
+ "ENOTFOUND",
42
+ "EAI_AGAIN",
43
+ "UND_ERR_CONNECT_TIMEOUT",
44
+ "UND_ERR_HEADERS_TIMEOUT",
45
+ "UND_ERR_BODY_TIMEOUT",
46
+ "UND_ERR_SOCKET"
47
+ ].includes(code) || /^(fetch failed|Failed to fetch|error sending request|error reading a body from connection|Unable to connect|ConnectionRefused|Network connection lost|The socket connection was closed unexpectedly)/.test(cause.message)) return "fetch";
48
+ }
49
+ throw cause;
50
+ }
51
+ /** Carries a context transport failure through the key decoding boundary. */
52
+ var KeyContextFetchError = class extends Error {
53
+ constructor(error) {
54
+ super("Failed to fetch a key's JSON-LD context.", { cause: error });
55
+ this.error = error;
56
+ }
57
+ };
58
+ function contextFetchError(error) {
59
+ const seen = /* @__PURE__ */ new Set();
60
+ while (error instanceof Error && !seen.has(error)) {
61
+ seen.add(error);
62
+ const details = error.details;
63
+ if (!error.name.startsWith("jsonld.") || details?.code !== "loading remote context failed") break;
64
+ error = "cause" in details ? details.cause : error.cause;
65
+ }
66
+ return new KeyContextFetchError(error);
67
+ }
10
68
  /**
11
69
  * Checks if the given key is valid and supported. No-op if the key is valid,
12
70
  * otherwise throws an error.
@@ -101,6 +159,9 @@ async function importJwk(jwk, type) {
101
159
  * @internal
102
160
  */
103
161
  async function fetchActorDocument(actorId, options = {}) {
162
+ return await fetchActorDocumentInternal(actorId, options, false);
163
+ }
164
+ async function fetchActorDocumentInternal(actorId, options, propagateContextFetchErrors) {
104
165
  const logger = getLogger([
105
166
  "fedify",
106
167
  "sig",
@@ -131,9 +192,12 @@ async function fetchActorDocument(actorId, options = {}) {
131
192
  baseUrl: documentUrl
132
193
  });
133
194
  } catch (error) {
134
- if (!(error instanceof TypeError)) throw error;
135
- logger.debug("The document served at {documentUrl} is not a valid object: {error}", {
195
+ const failure = classifyKeyJsonLdError(error);
196
+ if (failure === "fetch" && propagateContextFetchErrors) throw contextFetchError(error);
197
+ if (failure == null && !(error instanceof TypeError)) throw error;
198
+ logger.debug("Failed to decode the actor document at {documentUrl}: {error}", {
136
199
  documentUrl: documentUrl.href,
200
+ failure: failure ?? "invalid",
137
201
  error
138
202
  });
139
203
  return null;
@@ -172,6 +236,9 @@ async function fetchActorDocument(actorId, options = {}) {
172
236
  * @internal
173
237
  */
174
238
  async function verifyKeyOwnership(key, options = {}) {
239
+ return await verifyKeyOwnershipInternal(key, options, false);
240
+ }
241
+ async function verifyKeyOwnershipInternal(key, options, propagateContextFetchErrors) {
175
242
  const logger = getLogger([
176
243
  "fedify",
177
244
  "sig",
@@ -181,7 +248,7 @@ async function verifyKeyOwnership(key, options = {}) {
181
248
  if (keyId == null) return null;
182
249
  const claimedOwnerId = key instanceof CryptographicKey ? key.ownerId : key.controllerId;
183
250
  if (claimedOwnerId == null) return null;
184
- const owner = await fetchActorDocument(claimedOwnerId, options);
251
+ const owner = await fetchActorDocumentInternal(claimedOwnerId, options, propagateContextFetchErrors);
185
252
  if (owner == null) {
186
253
  logger.debug("The owner ({claimedOwnerId}) that key {keyId} claims could not be resolved.", {
187
254
  keyId: keyId.href,
@@ -333,6 +400,21 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
333
400
  tracerProvider
334
401
  });
335
402
  } catch (e) {
403
+ const failure = classifyKeyJsonLdError(e);
404
+ if (failure === "fetch") throw contextFetchError(e);
405
+ if (failure != null) {
406
+ logger.debug("Failed to decode key {keyId}: {error}", {
407
+ keyId,
408
+ failure,
409
+ error: e
410
+ });
411
+ await keyCache?.set(cacheKey, null);
412
+ await clearFetchErrorMetadata(cacheKey, keyCache);
413
+ return {
414
+ key: null,
415
+ cached: false
416
+ };
417
+ }
336
418
  if (!(e instanceof TypeError)) throw e;
337
419
  try {
338
420
  object = await cls.fromJsonLd(document, {
@@ -341,8 +423,14 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
341
423
  tracerProvider
342
424
  });
343
425
  } catch (e) {
344
- if (e instanceof TypeError) {
345
- logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
426
+ const failure = classifyKeyJsonLdError(e);
427
+ if (failure === "fetch") throw contextFetchError(e);
428
+ if (failure != null || e instanceof TypeError) {
429
+ logger.debug("Failed to decode key {keyId}: {error}", {
430
+ keyId,
431
+ failure: failure ?? "invalid",
432
+ error: e
433
+ });
346
434
  await keyCache?.set(cacheKey, null);
347
435
  await clearFetchErrorMetadata(cacheKey, keyCache);
348
436
  return {
@@ -434,16 +522,17 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
434
522
  const claimedOwnerId = key instanceof CryptographicKey ? key.ownerId : key.controllerId;
435
523
  if (ownerDocument != null && claimedOwnerId == null) key = key instanceof CryptographicKey ? key.clone({ owner: ownerDocument.id }) : key.clone({ controller: ownerDocument.id });
436
524
  else if (claimedOwnerId != null && claimedOwnerId.href !== ownerDocument?.id?.href) {
437
- if (await verifyKeyOwnership(key, {
525
+ if (await verifyKeyOwnershipInternal(key, {
438
526
  documentLoader,
439
527
  contextLoader,
440
528
  tracerProvider
441
- }) == null) {
529
+ }, true) == null) {
442
530
  logger.debug("Failed to verify; the owner {claimedOwnerId} that key {keyId} claims does not list the key as its own.", {
443
531
  keyId,
444
532
  claimedOwnerId: claimedOwnerId.href
445
533
  });
446
534
  await keyCache?.set(cacheKey, null);
535
+ await clearFetchErrorMetadata(cacheKey, keyCache);
447
536
  return {
448
537
  key: null,
449
538
  cached: false
@@ -481,7 +570,12 @@ async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, o
481
570
  } catch (error) {
482
571
  return await onFetchError(error, cacheKey, keyId, keyCache, logger);
483
572
  }
484
- return await resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, options, logger);
573
+ try {
574
+ return await resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, options, logger);
575
+ } catch (error) {
576
+ if (!(error instanceof KeyContextFetchError)) throw error;
577
+ return await onFetchError(error.error, cacheKey, keyId, keyCache, logger);
578
+ }
485
579
  }
486
580
  async function fetchKeyInternal(keyId, cls, options = {}) {
487
581
  return await fetchKeyWithResult(typeof keyId === "string" ? new URL(keyId) : keyId, cls, options, (_cacheKey, _keyId, _keyCache, _logger) => {
@@ -2,6 +2,7 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { CryptographicKey, Multikey } from "@fedify/vocab";
5
+ import { FetchError, UrlError } from "@fedify/vocab-runtime";
5
6
  //#region src/federation/keycache.ts
6
7
  const KEY_CACHE_GENERATION = "2";
7
8
  var KvKeyCache = class {
@@ -76,8 +77,15 @@ var KvKeyCache = class {
76
77
  })
77
78
  };
78
79
  else if ("errorName" in cached && typeof cached.errorName === "string" && "errorMessage" in cached && typeof cached.errorMessage === "string") {
79
- const error = new Error(cached.errorMessage);
80
+ let error;
81
+ if ("errorType" in cached && cached.errorType === "FetchError" && "errorUrl" in cached && typeof cached.errorUrl === "string" && URL.canParse(cached.errorUrl)) {
82
+ error = new FetchError(cached.errorUrl);
83
+ error.message = cached.errorMessage;
84
+ } else if ("errorType" in cached && cached.errorType === "UrlError" && "errorReason" in cached && (cached.errorReason === "dns" || cached.errorReason === "disallowed")) error = new UrlError(cached.errorMessage, { reason: cached.errorReason });
85
+ else error = new Error(cached.errorMessage);
80
86
  error.name = cached.errorName;
87
+ if ("errorCause" in cached && cached.errorCause != null && typeof cached.errorCause === "object" && "name" in cached.errorCause && typeof cached.errorCause.name === "string" && "message" in cached.errorCause && typeof cached.errorCause.message === "string") if ("isDomException" in cached.errorCause && cached.errorCause.isDomException === true) error.cause = new DOMException(cached.errorCause.message, cached.errorCause.name);
88
+ else error.cause = Object.assign(new Error(cached.errorCause.message), { name: cached.errorCause.name });
81
89
  return { error };
82
90
  }
83
91
  }
@@ -95,9 +103,22 @@ var KvKeyCache = class {
95
103
  }, { ttl: this.unavailableKeyTtl });
96
104
  return;
97
105
  }
106
+ const cause = error.error.cause;
98
107
  await this.kv.set(this.#getFetchErrorKey(keyId), {
99
108
  errorName: error.error.name,
100
- errorMessage: error.error.message
109
+ errorMessage: error.error.message,
110
+ ...error.error instanceof FetchError ? {
111
+ errorType: "FetchError",
112
+ errorUrl: error.error.url.href
113
+ } : error.error instanceof UrlError ? {
114
+ errorType: "UrlError",
115
+ errorReason: error.error.reason
116
+ } : {},
117
+ ...cause instanceof Error || cause instanceof DOMException ? { errorCause: {
118
+ name: cause.name,
119
+ message: cause.message,
120
+ isDomException: cause instanceof DOMException
121
+ } } : {}
101
122
  }, { ttl: this.unavailableKeyTtl });
102
123
  }
103
124
  };
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-BOH-uFLj.cjs");
4
+ const require_http = require("./http-EEfKB8Qb.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { f as validateCryptoKey, t as doubleKnock } from "./http-CeK9QmL_.js";
3
+ import { f as validateCryptoKey, t as doubleKnock } from "./http-DtypHuuK.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-ChmEXNOv.mjs";
5
- import { r as fetchKey, s as validateCryptoKey } from "./key-BJcK-1Av.mjs";
4
+ import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
5
+ import { r as fetchKey, s as validateCryptoKey } from "./key-DRLvwDTh.mjs";
6
6
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,5 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as FederationImpl } from "./middleware-Co_QOX9H.mjs";
4
+ import { n as FederationImpl } from "./middleware-SSrXiJIV.mjs";
5
5
  export { FederationImpl };
@@ -1,4 +1,4 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
- const require_middleware = require("./middleware-DHGVHIUj.cjs");
3
+ const require_middleware = require("./middleware-Dw9sPiec.cjs");
4
4
  exports.FederationImpl = require_middleware.FederationImpl;
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
4
  const require_transformers = require("./transformers-NeAONrAq.cjs");
5
- const require_http = require("./http-BOH-uFLj.cjs");
5
+ const require_http = require("./http-EEfKB8Qb.cjs");
6
6
  const require_types = require("./types-DRPjmHVV.cjs");
7
- const require_proof = require("./proof-DzOl2GlQ.cjs");
8
- const require_kv_cache = require("./kv-cache-BlOG31SS.cjs");
7
+ const require_proof = require("./proof-De1y2j-e.cjs");
8
+ const require_kv_cache = require("./kv-cache-BWVKAAmc.cjs");
9
9
  let _logtape_logtape = require("@logtape/logtape");
10
10
  let _fedify_vocab = require("@fedify/vocab");
11
11
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -337,7 +337,7 @@ var FederationBuilderImpl = class {
337
337
  this.collectionTypeIds = {};
338
338
  }
339
339
  async build(options) {
340
- const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-dGW2gSDG.cjs"));
340
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-DZxmsbPB.cjs"));
341
341
  const f = new FederationImpl(options);
342
342
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
343
343
  f.router = this.router.clone();
@@ -943,8 +943,15 @@ var KvKeyCache = class {
943
943
  })
944
944
  };
945
945
  else if ("errorName" in cached && typeof cached.errorName === "string" && "errorMessage" in cached && typeof cached.errorMessage === "string") {
946
- const error = new Error(cached.errorMessage);
946
+ let error;
947
+ if ("errorType" in cached && cached.errorType === "FetchError" && "errorUrl" in cached && typeof cached.errorUrl === "string" && URL.canParse(cached.errorUrl)) {
948
+ error = new _fedify_vocab_runtime.FetchError(cached.errorUrl);
949
+ error.message = cached.errorMessage;
950
+ } else if ("errorType" in cached && cached.errorType === "UrlError" && "errorReason" in cached && (cached.errorReason === "dns" || cached.errorReason === "disallowed")) error = new _fedify_vocab_runtime.UrlError(cached.errorMessage, { reason: cached.errorReason });
951
+ else error = new Error(cached.errorMessage);
947
952
  error.name = cached.errorName;
953
+ if ("errorCause" in cached && cached.errorCause != null && typeof cached.errorCause === "object" && "name" in cached.errorCause && typeof cached.errorCause.name === "string" && "message" in cached.errorCause && typeof cached.errorCause.message === "string") if ("isDomException" in cached.errorCause && cached.errorCause.isDomException === true) error.cause = new DOMException(cached.errorCause.message, cached.errorCause.name);
954
+ else error.cause = Object.assign(new Error(cached.errorCause.message), { name: cached.errorCause.name });
948
955
  return { error };
949
956
  }
950
957
  }
@@ -962,9 +969,22 @@ var KvKeyCache = class {
962
969
  }, { ttl: this.unavailableKeyTtl });
963
970
  return;
964
971
  }
972
+ const cause = error.error.cause;
965
973
  await this.kv.set(this.#getFetchErrorKey(keyId), {
966
974
  errorName: error.error.name,
967
- errorMessage: error.error.message
975
+ errorMessage: error.error.message,
976
+ ...error.error instanceof _fedify_vocab_runtime.FetchError ? {
977
+ errorType: "FetchError",
978
+ errorUrl: error.error.url.href
979
+ } : error.error instanceof _fedify_vocab_runtime.UrlError ? {
980
+ errorType: "UrlError",
981
+ errorReason: error.error.reason
982
+ } : {},
983
+ ...cause instanceof Error || cause instanceof DOMException ? { errorCause: {
984
+ name: cause.name,
985
+ message: cause.message,
986
+ isDomException: cause instanceof DOMException
987
+ } } : {}
968
988
  }, { ttl: this.unavailableKeyTtl });
969
989
  }
970
990
  };
@@ -2,25 +2,25 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-ChmEXNOv.mjs";
5
+ import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-BavzedPB.mjs";
7
- import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-BJcK-1Av.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-B_M80hBW.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-DEVImb5e.mjs";
7
+ import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-DRLvwDTh.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-Dcj1ulAh.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-o3fCIlIa.mjs";
10
10
  import { n as kvCache } from "./kv-cache-DqEKe5E0.mjs";
11
- import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-YAXn6sG8.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-B3ZkY-Ov.mjs";
13
- import { n as signObject, r as verifyObject } from "./proof-DIGrz49z.mjs";
14
- import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-DM72NZuk.mjs";
15
- import { t as nodeInfoToJson } from "./types-C37hquWI.mjs";
16
- import { n as routeActivity } from "./inbox-B_O6TjZS.mjs";
17
- import { t as FederationBuilderImpl } from "./builder-9KbL1CoC.mjs";
18
- import { t as buildCollectionSynchronizationHeader } from "./collection-ChgDTHLz.mjs";
19
- import { t as KvKeyCache } from "./keycache-CaO7wyQA.mjs";
11
+ import { t as KvKeyCache } from "./keycache-RFlZObU3.mjs";
12
+ import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-C5BZ98YK.mjs";
13
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-cPOoPvmr.mjs";
14
+ import { n as signObject, r as verifyObject } from "./proof-BTknCsN7.mjs";
15
+ import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-CjDMsn4a.mjs";
16
+ import { t as nodeInfoToJson } from "./types-DCP0WLdt.mjs";
17
+ import { n as routeActivity } from "./inbox-CVYVJI0M.mjs";
18
+ import { t as FederationBuilderImpl } from "./builder-CW1BrLbm.mjs";
19
+ import { t as buildCollectionSynchronizationHeader } from "./collection-BD6-SZ6O.mjs";
20
20
  import { t as acceptsJsonLd } from "./negotiation-BehA2uul.mjs";
21
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-CpT0u5Mx.mjs";
21
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-CxXY--ZL.mjs";
22
22
  import { t as createExponentialBackoffPolicy } from "./retry-B_E3V_Dx.mjs";
23
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-N2w1IwXT.mjs";
23
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-DDuHNgHz.mjs";
24
24
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
25
25
  import { lookupWebFinger } from "@fedify/webfinger";
26
26
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./chunk-CRNNMoPX.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-BGMIq1cs.js";
5
- import { a as verifyRequestDetailed, d as importJwk, f as validateCryptoKey, i as verifyRequest, m as formatAcceptSignature, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, v as name, y as version } from "./http-CeK9QmL_.js";
5
+ import { a as verifyRequestDetailed, d as importJwk, f as validateCryptoKey, i as verifyRequest, m as formatAcceptSignature, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, v as name, y as version } from "./http-DtypHuuK.js";
6
6
  import { a as MAX_BODY_SIZE, i as BodyTooLargeError, n as getNodeInfo, o as readBoundedText, t as nodeInfoToJson } from "./types-miAYfiGO.js";
7
- import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-BeGIkK97.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CEJICY0R.js";
7
+ import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-DPU3poip.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CEJCaF4E.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
11
11
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -942,8 +942,15 @@ var KvKeyCache = class {
942
942
  })
943
943
  };
944
944
  else if ("errorName" in cached && typeof cached.errorName === "string" && "errorMessage" in cached && typeof cached.errorMessage === "string") {
945
- const error = new Error(cached.errorMessage);
945
+ let error;
946
+ if ("errorType" in cached && cached.errorType === "FetchError" && "errorUrl" in cached && typeof cached.errorUrl === "string" && URL.canParse(cached.errorUrl)) {
947
+ error = new FetchError(cached.errorUrl);
948
+ error.message = cached.errorMessage;
949
+ } else if ("errorType" in cached && cached.errorType === "UrlError" && "errorReason" in cached && (cached.errorReason === "dns" || cached.errorReason === "disallowed")) error = new UrlError(cached.errorMessage, { reason: cached.errorReason });
950
+ else error = new Error(cached.errorMessage);
946
951
  error.name = cached.errorName;
952
+ if ("errorCause" in cached && cached.errorCause != null && typeof cached.errorCause === "object" && "name" in cached.errorCause && typeof cached.errorCause.name === "string" && "message" in cached.errorCause && typeof cached.errorCause.message === "string") if ("isDomException" in cached.errorCause && cached.errorCause.isDomException === true) error.cause = new DOMException(cached.errorCause.message, cached.errorCause.name);
953
+ else error.cause = Object.assign(new Error(cached.errorCause.message), { name: cached.errorCause.name });
947
954
  return { error };
948
955
  }
949
956
  }
@@ -961,9 +968,22 @@ var KvKeyCache = class {
961
968
  }, { ttl: this.unavailableKeyTtl });
962
969
  return;
963
970
  }
971
+ const cause = error.error.cause;
964
972
  await this.kv.set(this.#getFetchErrorKey(keyId), {
965
973
  errorName: error.error.name,
966
- errorMessage: error.error.message
974
+ errorMessage: error.error.message,
975
+ ...error.error instanceof FetchError ? {
976
+ errorType: "FetchError",
977
+ errorUrl: error.error.url.href
978
+ } : error.error instanceof UrlError ? {
979
+ errorType: "UrlError",
980
+ errorReason: error.error.reason
981
+ } : {},
982
+ ...cause instanceof Error || cause instanceof DOMException ? { errorCause: {
983
+ name: cause.name,
984
+ message: cause.message,
985
+ isDomException: cause instanceof DOMException
986
+ } } : {}
967
987
  }, { ttl: this.unavailableKeyTtl });
968
988
  }
969
989
  };