@fedify/fedify 2.5.0-dev.2448 → 2.5.0-dev.2494

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 (126) hide show
  1. package/README.md +3 -0
  2. package/dist/{builder-DbC8bn6k.mjs → builder-Y3pokaG2.mjs} +2 -2
  3. package/dist/{client-D-XP_Ccb.d.cts → client-3InDZbba.d.cts} +0 -1
  4. package/dist/{client-D-XP_Ccb.d.ts → client-3InDZbba.d.ts} +0 -1
  5. package/dist/{client-CEnNz8O7.mjs → client-5SIFzW3q.mjs} +113 -64
  6. package/dist/compat/mod.d.cts +1 -1
  7. package/dist/compat/mod.d.ts +1 -1
  8. package/dist/compat/transformers.test.mjs +1 -1
  9. package/dist/{compound-proof-heeXW2_A.mjs → compound-proof-BM7AINht.mjs} +2 -2
  10. package/dist/{context-GlHrzdSP.d.ts → context-DQJE9YfH.d.ts} +29 -3
  11. package/dist/{context-BazwQrHn.d.cts → context-DSuL3YWx.d.cts} +29 -3
  12. package/dist/{deno-Dpewt_jJ.mjs → deno-D7blYLbb.mjs} +1 -1
  13. package/dist/docloader-DbBbDaY-.mjs +136 -0
  14. package/dist/{exporter-DThFfe7P.mjs → exporter-DVG68ozH.mjs} +36 -30
  15. package/dist/federation/builder.test.mjs +1 -1
  16. package/dist/federation/compound-fanout.test.mjs +6 -3
  17. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  18. package/dist/federation/handler.test.mjs +5 -5
  19. package/dist/federation/hashlink-media.test.mjs +2 -2
  20. package/dist/federation/idempotency.test.mjs +2 -2
  21. package/dist/federation/inbox-actorless.test.mjs +5 -5
  22. package/dist/federation/inbox-report.test.mjs +5 -5
  23. package/dist/federation/inbox-view.test.mjs +1 -1
  24. package/dist/federation/inbox.test.mjs +1 -1
  25. package/dist/federation/metrics.test.mjs +1 -1
  26. package/dist/federation/middleware.test.mjs +468 -33
  27. package/dist/federation/mod.cjs +1 -1
  28. package/dist/federation/mod.d.cts +3 -3
  29. package/dist/federation/mod.d.ts +3 -3
  30. package/dist/federation/mod.js +1 -1
  31. package/dist/federation/mq.test.mjs +1 -1
  32. package/dist/federation/outgoing-proof.test.mjs +9 -6
  33. package/dist/federation/portable-actor.test.mjs +3 -3
  34. package/dist/federation/portable-chain.test.mjs +3 -3
  35. package/dist/federation/portable-collection.test.mjs +4 -4
  36. package/dist/federation/portable-delivery.test.mjs +2 -2
  37. package/dist/federation/portable-gateway-keys.test.mjs +11 -5
  38. package/dist/federation/portable-inbox.test.mjs +4 -4
  39. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  40. package/dist/federation/portable-route-activity.test.mjs +2 -2
  41. package/dist/federation/portable.test.mjs +3 -3
  42. package/dist/federation/send.test.mjs +502 -93
  43. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  44. package/dist/federation/tasks/tasks.test.mjs +2 -2
  45. package/dist/federation/temporal.test.mjs +1 -1
  46. package/dist/federation/webfinger.test.mjs +1 -1
  47. package/dist/{federation-D8YexkP1.cjs → federation-CFaTsSMN.cjs} +246 -108
  48. package/dist/{http-CAl7Num5.cjs → http-2SwIR4b-.cjs} +179 -110
  49. package/dist/{http-BBr-VLil.js → http-CrYxBKqG.js} +178 -109
  50. package/dist/{http-BZkyQIkb.mjs → http-CxKd10Lq.mjs} +204 -106
  51. package/dist/{inbox-wDuMKaFW.mjs → inbox-CM0UktG8.mjs} +2 -2
  52. package/dist/{inbox-view-NE9wXdLo.mjs → inbox-view-BJ5DBPFo.mjs} +1 -1
  53. package/dist/{key-nYGY4QB9.d.cts → key-DbLNT-vA.d.ts} +1 -2
  54. package/dist/{key-DhsBxxZN.d.ts → key-DlHT4R6k.d.cts} +1 -2
  55. package/dist/{kv-cache-CTQSfkmp.mjs → kv-cache-CIdGATck.mjs} +1 -1
  56. package/dist/{kv-cache-CjgCOz3i.cjs → kv-cache-Cd8xKv-x.cjs} +72 -27
  57. package/dist/{kv-cache-U7uz5nx4.js → kv-cache-DbgFe35y.js} +73 -28
  58. package/dist/{ld-Cel1RRZ5.d.cts → ld-CWVpo_NM.d.cts} +1 -1
  59. package/dist/{ld-CQFuiah9.mjs → ld-DUeBHFWH.mjs} +2 -2
  60. package/dist/{ld-CcuZ4NZa.d.ts → ld-Inagww4R.d.ts} +1 -1
  61. package/dist/{metrics-B-QxRSSR.mjs → metrics-B7TvoAP7.mjs} +1 -1
  62. package/dist/{middleware-BdlNa8BD.mjs → middleware-BE4JXx-U.mjs} +1 -1
  63. package/dist/{middleware-CuVa0UuS.mjs → middleware-BEaUojg7.mjs} +89 -49
  64. package/dist/{middleware-P-AZEQMn.js → middleware-CId6efsJ.js} +247 -109
  65. package/dist/{mod-DvWOv2Ho.d.cts → mod-6TQ4UQZb.d.cts} +1 -1
  66. package/dist/{mod-BHQE-7WQ.d.ts → mod-B4kBw1-8.d.ts} +1 -1
  67. package/dist/{mod-DkhfZC1u.d.ts → mod-B7j30IQf.d.ts} +2 -9
  68. package/dist/{mod-B2783_3v.d.cts → mod-C1nT74IG.d.cts} +1 -1
  69. package/dist/{mod-DjZfJj9R.d.ts → mod-CIeBgsOC.d.ts} +1 -1
  70. package/dist/{mod-B5-wdzmJ.d.cts → mod-YvA4Rk8J.d.cts} +2 -9
  71. package/dist/mod.cjs +5 -5
  72. package/dist/mod.d.cts +7 -7
  73. package/dist/mod.d.ts +7 -7
  74. package/dist/mod.js +5 -5
  75. package/dist/nodeinfo/client.test.mjs +337 -19
  76. package/dist/nodeinfo/handler.test.mjs +1 -1
  77. package/dist/nodeinfo/mod.cjs +1 -1
  78. package/dist/nodeinfo/mod.d.cts +1 -1
  79. package/dist/nodeinfo/mod.d.ts +1 -1
  80. package/dist/nodeinfo/mod.js +1 -1
  81. package/dist/otel/exporter.test.mjs +257 -1
  82. package/dist/otel/mod.cjs +36 -30
  83. package/dist/otel/mod.d.cts +13 -0
  84. package/dist/otel/mod.d.ts +13 -0
  85. package/dist/otel/mod.js +36 -30
  86. package/dist/{owner-ccKkQOAf.mjs → owner-CwijV0c5.mjs} +3 -3
  87. package/dist/{portable-collection-DUlQ3s2M.js → portable-collection-2jn_4V7Y.js} +1 -1
  88. package/dist/{portable-collection-CndnpXfo.mjs → portable-collection-B023xqhZ.mjs} +2 -2
  89. package/dist/{portable-collection-TC-kvkVI.cjs → portable-collection-BeS88JJp.cjs} +1 -1
  90. package/dist/{portable-key-D5tFOoV-.mjs → portable-key-BpBucRfb.mjs} +1 -1
  91. package/dist/{proof-DPoF06nz.mjs → proof-DQh2z9fx.mjs} +3 -3
  92. package/dist/{send-CF44O1Df.mjs → send-DN5HNBv-.mjs} +174 -76
  93. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  94. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  95. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  96. package/dist/sig/compound-proof.test.mjs +2 -2
  97. package/dist/sig/http.test.mjs +553 -2
  98. package/dist/sig/key.test.mjs +1 -1
  99. package/dist/sig/ld.test.mjs +1 -1
  100. package/dist/sig/mitra-receive-interop.test.mjs +4 -4
  101. package/dist/sig/mitra-send-interop.test.mjs +3 -3
  102. package/dist/sig/mod.cjs +2 -2
  103. package/dist/sig/mod.d.cts +3 -3
  104. package/dist/sig/mod.d.ts +3 -3
  105. package/dist/sig/mod.js +2 -2
  106. package/dist/sig/owner.test.mjs +1 -1
  107. package/dist/sig/portable-collection.test.mjs +1 -1
  108. package/dist/sig/portable-interop.test.mjs +3 -3
  109. package/dist/sig/portable-key.test.mjs +5 -5
  110. package/dist/sig/proof.test.mjs +4 -4
  111. package/dist/sig/tootik-request-interop.test.mjs +4 -4
  112. package/dist/sig/tootik-send-interop.test.mjs +3 -3
  113. package/dist/sig/verification.test.mjs +3 -3
  114. package/dist/{temporal-XlZ4Wb94.mjs → temporal-yl7Z7A6y.mjs} +1 -1
  115. package/dist/testing/kv.test.mjs +1 -1
  116. package/dist/testing/mod.d.mts +26 -0
  117. package/dist/{types-_S2_MeLF.js → types-DUjZb4i6.js} +112 -63
  118. package/dist/{types-poIao40f.cjs → types-hKCCjii0.cjs} +111 -62
  119. package/dist/utils/docloader.test.mjs +344 -36
  120. package/dist/utils/kv-cache.test.mjs +1 -1
  121. package/dist/utils/mod.cjs +1 -1
  122. package/dist/utils/mod.d.cts +1 -1
  123. package/dist/utils/mod.d.ts +1 -1
  124. package/dist/utils/mod.js +1 -1
  125. package/package.json +8 -8
  126. package/dist/docloader-CpsDyqVN.mjs +0 -91
@@ -1,9 +1,10 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { X as validateCryptoKey, dt as recordDocumentCache, t as doubleKnock } from "./http-BBr-VLil.js";
3
+ import { X as validateCryptoKey, dt as recordDocumentCache, t as doubleKnockScoped } from "./http-CrYxBKqG.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
- import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout, validatePublicUrl, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
5
+ import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
6
6
  import { curry } from "es-toolkit";
7
+ import { openDirectFetch, openPublicFetch } from "@fedify/vocab-runtime/internal";
7
8
  //#region src/utils/docloader.ts
8
9
  const logger$1 = getLogger([
9
10
  "fedify",
@@ -27,13 +28,35 @@ const DEFAULT_MAX_REDIRECTION = 20;
27
28
  * @throws {RangeError} If the `timeout` option is invalid.
28
29
  * @since 0.4.0
29
30
  */
30
- function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, timeout, tracerProvider } = {}) {
31
+ function getAuthenticatedDocumentLoader(identity, options = {}) {
32
+ return createAuthenticatedDocumentLoader(identity, options);
33
+ }
34
+ /**
35
+ * The placeholder that the alternate document callback of
36
+ * `getRemoteDocument()` returns, so that the alternate document is loaded
37
+ * after the current hop is closed.
38
+ */
39
+ const ALTERNATE_PLACEHOLDER = Object.freeze({
40
+ contextUrl: null,
41
+ document: null,
42
+ documentUrl: "about:blank"
43
+ });
44
+ /**
45
+ * The implementation of {@link getAuthenticatedDocumentLoader}. This is not
46
+ * exported from any entry point.
47
+ * @param identity The identity to get the document loader for.
48
+ * @param options The options for the document loader.
49
+ * @param deps The dependencies, for tests.
50
+ * @returns The authenticated document loader.
51
+ * @throws {TypeError} If the key is invalid or unsupported.
52
+ */
53
+ function createAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, timeout, tracerProvider } = {}, deps = {}) {
31
54
  validateCryptoKey(identity.privateKey);
32
55
  const resolvedTimeout = resolveDocumentLoaderTimeout(timeout);
33
56
  async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
34
57
  options?.signal?.throwIfAborted();
35
58
  let currentUrl = new URL(url).href;
36
- await validateUrl(currentUrl, options);
59
+ validateUrl(currentUrl);
37
60
  visited.add(currentUrl);
38
61
  const originalRequest = createActivityPubRequest(currentUrl, { userAgent });
39
62
  function follow(nextUrl) {
@@ -42,46 +65,68 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
42
65
  if (visited.has(nextUrl)) throw new FetchError(currentUrl, `Redirect loop detected: ${nextUrl}`);
43
66
  redirected++;
44
67
  }
45
- const response = await doubleKnock(originalRequest, identity, {
68
+ const result = await doubleKnockScoped(originalRequest, identity, {
46
69
  maxRedirection,
47
70
  specDeterminer,
48
71
  log: curry(logRequest)(logger$1),
49
72
  tracerProvider,
50
73
  signal: options?.signal,
51
- validateRedirect: async (nextUrl) => {
74
+ validateRedirect: (nextUrl) => {
52
75
  follow(nextUrl);
53
- await validateUrl(nextUrl, options);
76
+ validateUrl(nextUrl);
54
77
  visited.add(nextUrl);
55
78
  currentUrl = nextUrl;
56
79
  }
80
+ }, (hopUrl) => openHop(hopUrl, options), async (response) => {
81
+ options?.signal?.throwIfAborted();
82
+ let alternateUrl;
83
+ const document = await getRemoteDocument(currentUrl, response, (url) => {
84
+ alternateUrl = url;
85
+ return Promise.resolve(ALTERNATE_PLACEHOLDER);
86
+ }, options);
87
+ if (alternateUrl == null) return { document };
88
+ if (!response.bodyUsed && response.body?.locked !== true) response.body?.cancel().catch((error) => {
89
+ logger$1.debug("Failed to cancel the response body from {url}: {error}", {
90
+ url: currentUrl,
91
+ error
92
+ });
93
+ });
94
+ return { alternateUrl };
57
95
  });
58
96
  options?.signal?.throwIfAborted();
59
- return getRemoteDocument(currentUrl, response, (alternateUrl) => {
60
- follow(alternateUrl);
61
- return load(alternateUrl, options, redirected, visited);
62
- }, options);
97
+ if ("document" in result) return result.document;
98
+ follow(result.alternateUrl);
99
+ return load(result.alternateUrl, options, redirected, visited);
100
+ }
101
+ function openUnvalidatedHop(url, signal) {
102
+ if (deps.openHop != null) return deps.openHop(url);
103
+ return allowPrivateAddress ? openDirectFetch(url) : openPublicFetch(url, { signal });
104
+ }
105
+ async function openHop(url, options) {
106
+ try {
107
+ const session = await openUnvalidatedHop(url, options?.signal);
108
+ if (options?.signal?.aborted) {
109
+ await session.close();
110
+ options.signal.throwIfAborted();
111
+ }
112
+ return session;
113
+ } catch (error) {
114
+ if (error instanceof UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
115
+ url,
116
+ error
117
+ });
118
+ else logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
119
+ url,
120
+ error
121
+ });
122
+ throw error;
123
+ }
63
124
  }
64
- async function validateUrl(url, options) {
125
+ function validateUrl(url) {
65
126
  const parsedUrl = new URL(url);
66
127
  const protocol = parsedUrl.protocol;
67
128
  if (protocol !== "http:" && protocol !== "https:") throw new UrlError(`Unsupported protocol: ${protocol}`);
68
129
  if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new UrlError("URLs with credentials are not allowed");
69
- if (!allowPrivateAddress) {
70
- try {
71
- await validatePublicUrl(url);
72
- } catch (error) {
73
- if (error instanceof UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
74
- url,
75
- error
76
- });
77
- else logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
78
- url,
79
- error
80
- });
81
- throw error;
82
- }
83
- options?.signal?.throwIfAborted();
84
- }
85
130
  }
86
131
  return withDocumentLoaderTimeout((url, options) => load(url, options), resolvedTimeout);
87
132
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { a as KeyCache, v as VerificationObservationOptions } from "./key-nYGY4QB9.cjs";
2
+ import { a as KeyCache, v as VerificationObservationOptions } from "./key-DlHT4R6k.cjs";
3
3
  import { Activity, Actor, CryptographicKey } from "@fedify/vocab";
4
4
  import { DocumentLoader } from "@fedify/vocab-runtime";
5
5
  import { MeterProvider, TracerProvider } from "@opentelemetry/api";
@@ -3,8 +3,8 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { c as isPortableActorDocument, d as isPortableUri, l as isPortableId, m as parseKeyIdString, s as isCompatibleKeyId } from "./portable-key-id-Ca30-hOa.mjs";
5
5
  import { a as verificationObservation, i as triedKey, n as observeCheck, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
6
- import { n as version, t as name } from "./deno-Dpewt_jJ.mjs";
7
- import { _ as recordKeyLookup, n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch, t as classifyFetchError } from "./metrics-B-QxRSSR.mjs";
6
+ import { n as version, t as name } from "./deno-D7blYLbb.mjs";
7
+ import { _ as recordKeyLookup, n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch, t as classifyFetchError } from "./metrics-B7TvoAP7.mjs";
8
8
  import { n as attachKeyOwnerEvidence, t as MAX_PORTABLE_KEY_TTL } from "./key-owner-evidence-APB6NpSk.mjs";
9
9
  import { getLogger } from "@logtape/logtape";
10
10
  import { Activity, CryptographicKey, Multikey, Object as Object$1, getTypeId, isActor } from "@fedify/vocab";
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { a as KeyCache, v as VerificationObservationOptions } from "./key-DhsBxxZN.js";
2
+ import { a as KeyCache, v as VerificationObservationOptions } from "./key-DbLNT-vA.js";
3
3
  import { Activity, Actor, CryptographicKey } from "@fedify/vocab";
4
4
  import { MeterProvider, TracerProvider } from "@opentelemetry/api";
5
5
  import { DocumentLoader } from "@fedify/vocab-runtime";
@@ -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-Dpewt_jJ.mjs";
4
+ import { n as version, t as name } from "./deno-D7blYLbb.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-CuVa0UuS.mjs";
4
+ import { n as FederationImpl } from "./middleware-BEaUojg7.mjs";
5
5
  export { FederationImpl };
@@ -5,30 +5,30 @@ import { d as isPortableUri, f as isSameObjectId, i as getPortableDid, l as isPo
5
5
  import { n as isPubliclyAddressedNode, t as isInAudience } from "./audience-CHQ-FlLD.mjs";
6
6
  import { i as getEmptyAuthenticationEvidence, n as deserializeAuthentication, t as createAuthenticationEvidence } from "./inbox-authentication-DflPYlLL.mjs";
7
7
  import { a as verificationObservation, r as snapshotKey, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
8
- import { n as version, t as name } from "./deno-Dpewt_jJ.mjs";
9
- 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-B-QxRSSR.mjs";
8
+ import { n as version, t as name } from "./deno-D7blYLbb.mjs";
9
+ 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-B7TvoAP7.mjs";
10
10
  import { t as formatAcceptSignature } from "./accept-CPVqki78.mjs";
11
11
  import { r as getVerifiedKeyOwnerEvidence } from "./key-owner-evidence-APB6NpSk.mjs";
12
- import { D as validateCryptoKey, E as importJwk, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, g as verifyCompactJsonLdDetailed, l as hasSignature, m as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike, x as exportJwk, y as wrapContextLoaderForJsonLd } from "./ld-CQFuiah9.mjs";
12
+ import { D as validateCryptoKey, E as importJwk, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, g as verifyCompactJsonLdDetailed, l as hasSignature, m as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike, x as exportJwk, y as wrapContextLoaderForJsonLd } from "./ld-DUeBHFWH.mjs";
13
13
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
14
- import { a as hasProofLike, d as verifyPortableObjectProof, i as getProofSigner, l as verifyObject, p as verifyPortableObjectProofWithRoot, s as signObject, t as InvalidPortableObjectIdError, u as verifyObjectDetailed } from "./proof-DPoF06nz.mjs";
15
- import { a as listRequestSignatures, c as selectRequestSignature, d as validateMaxSignatures, f as verifyRequest, p as verifyRequestDetailed, s as parseRfc9421SignatureInput } from "./http-BZkyQIkb.mjs";
16
- import { t as getAuthenticatedDocumentLoader } from "./docloader-CpsDyqVN.mjs";
17
- import { n as kvCache } from "./kv-cache-CTQSfkmp.mjs";
18
- import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-CEnNz8O7.mjs";
14
+ import { a as hasProofLike, d as verifyPortableObjectProof, i as getProofSigner, l as verifyObject, p as verifyPortableObjectProofWithRoot, s as signObject, t as InvalidPortableObjectIdError, u as verifyObjectDetailed } from "./proof-DQh2z9fx.mjs";
15
+ import { c as parseRfc9421SignatureInput, f as validateMaxSignatures, l as selectRequestSignature, m as verifyRequestDetailed, o as listRequestSignatures, p as verifyRequest } from "./http-CxKd10Lq.mjs";
16
+ import { n as getAuthenticatedDocumentLoader } from "./docloader-DbBbDaY-.mjs";
17
+ import { n as kvCache } from "./kv-cache-CIdGATck.mjs";
18
+ import { d as MAX_BODY_SIZE, f as readBoundedText, t as getNodeInfo, u as BodyTooLargeError } from "./client-5SIFzW3q.mjs";
19
19
  import { t as nodeInfoToJson } from "./types-DE_LV1JB.mjs";
20
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-ccKkQOAf.mjs";
21
- import { t as verifyPortableObject } from "./portable-collection-CndnpXfo.mjs";
22
- import { a as getOrderingDestination, i as sendActivityThroughGateways, n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CF44O1Df.mjs";
23
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-DbC8bn6k.mjs";
20
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-CwijV0c5.mjs";
21
+ import { t as verifyPortableObject } from "./portable-collection-B023xqhZ.mjs";
22
+ import { a as sendActivityThroughGateways, i as sendActivity, n as extractInboxes, o as getOrderingDestination, t as SendActivityError } from "./send-DN5HNBv-.mjs";
23
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-Y3pokaG2.mjs";
24
24
  import { t as CircuitBreaker } from "./circuit-breaker-XJ53md4S.mjs";
25
25
  import { t as buildCollectionSynchronizationHeader } from "./collection-CnnP1UAv.mjs";
26
- import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-heeXW2_A.mjs";
27
- import { a as isActorlessActivityAuthenticated, i as getInboxIdempotencyKey, n as checkActorlessActivity, o as isInboxActivityProcessed, s as routeActivity, t as actorsHaveSameOrigin } from "./inbox-wDuMKaFW.mjs";
28
- import { c as expandDocument, d as parseSerializedVerifiedActivityView, f as restoreVerifiedActivityView, i as createReleasableLoader, l as getActorPresence, n as buildVerifiedActivityView, o as deepFreeze, r as createContextSnapshot, t as ContextSnapshotMissError } from "./inbox-view-NE9wXdLo.mjs";
26
+ import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-BM7AINht.mjs";
27
+ import { a as isActorlessActivityAuthenticated, i as getInboxIdempotencyKey, n as checkActorlessActivity, o as isInboxActivityProcessed, s as routeActivity, t as actorsHaveSameOrigin } from "./inbox-CM0UktG8.mjs";
28
+ import { c as expandDocument, d as parseSerializedVerifiedActivityView, f as restoreVerifiedActivityView, i as createReleasableLoader, l as getActorPresence, n as buildVerifiedActivityView, o as deepFreeze, r as createContextSnapshot, t as ContextSnapshotMissError } from "./inbox-view-BJ5DBPFo.mjs";
29
29
  import { t as KvKeyCache } from "./keycache-N2opu4-3.mjs";
30
30
  import { t as acceptsJsonLd } from "./negotiation-CCocWT_N.mjs";
31
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-XlZ4Wb94.mjs";
31
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-yl7Z7A6y.mjs";
32
32
  import { t as createExponentialBackoffPolicy } from "./retry-zX5xw5e0.mjs";
33
33
  import { t as TaskCodec } from "./codec-C6rTrpIp.mjs";
34
34
  import { getLogger, withContext } from "@logtape/logtape";
@@ -6504,7 +6504,7 @@ var FederationImpl = class extends FederationBuilderImpl {
6504
6504
  onNotAcceptable ??= notAcceptable;
6505
6505
  onUnauthorized ??= unauthorized;
6506
6506
  const url = new URL(request.url);
6507
- const route = this.router.route(url.pathname);
6507
+ const route = this.router.route(url.pathname, { allowUnencodedColon: true });
6508
6508
  if (route == null) {
6509
6509
  const media = this.hashlinkMediaDispatcher == null ? null : parseHashlinkGatewayRequest(url);
6510
6510
  if (media != null) return await this.#fetchHashlinkMedia(request, media, {
@@ -8323,52 +8323,92 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
8323
8323
  if (object instanceof Tombstone && !(object instanceof cls) && options?.tombstone !== "passthrough") return null;
8324
8324
  return object;
8325
8325
  }
8326
- #signedKey = void 0;
8326
+ #signedKey = null;
8327
+ #signedKeyOwner = null;
8328
+ #signatureChecks = /* @__PURE__ */ new WeakMap();
8329
+ #getSignatureCheck(documentLoader, contextLoader) {
8330
+ let checks = this.#signatureChecks.get(documentLoader);
8331
+ if (checks == null) {
8332
+ checks = /* @__PURE__ */ new WeakMap();
8333
+ this.#signatureChecks.set(documentLoader, checks);
8334
+ }
8335
+ let check = checks.get(contextLoader);
8336
+ if (check == null) {
8337
+ check = {};
8338
+ checks.set(contextLoader, check);
8339
+ }
8340
+ return check;
8341
+ }
8327
8342
  async getSignedKey(options = {}) {
8328
8343
  if (this.#signedKey != null) return this.#signedKey;
8329
- const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
8330
- documentLoader: options.documentLoader ?? this.documentLoader,
8331
- contextLoader: options.contextLoader ?? this.contextLoader,
8344
+ const documentLoader = options.documentLoader ?? this.documentLoader;
8345
+ const contextLoader = options.contextLoader ?? this.contextLoader;
8346
+ const check = this.#getSignatureCheck(documentLoader, contextLoader);
8347
+ if (check.key != null) return check.key;
8348
+ const keyCache = documentLoader === this.documentLoader && contextLoader === this.contextLoader ? new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
8349
+ documentLoader,
8350
+ contextLoader,
8332
8351
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
8333
8352
  keyTtl: this.federation.publicKeyTtl
8334
- });
8335
- return this.#signedKey = await verifyRequest(this.request, {
8353
+ }) : void 0;
8354
+ const promise = verifyRequest(this.request, {
8336
8355
  ...this,
8337
- contextLoader: options.contextLoader ?? this.contextLoader,
8338
- documentLoader: options.documentLoader ?? this.documentLoader,
8356
+ contextLoader,
8357
+ documentLoader,
8339
8358
  timeWindow: this.federation.signatureTimeWindow,
8340
8359
  maxSignatures: this.federation.maxHttpSignatures,
8360
+ keyCache,
8341
8361
  meterProvider: this.meterProvider,
8342
- tracerProvider: options.tracerProvider ?? this.tracerProvider,
8343
- keyCache
8362
+ tracerProvider: options.tracerProvider ?? this.tracerProvider
8363
+ }).then((key) => {
8364
+ if (key != null) this.#signedKey ??= key;
8365
+ return key;
8366
+ }).catch((error) => {
8367
+ if (check.key === promise) check.key = void 0;
8368
+ throw error;
8344
8369
  });
8370
+ check.key = promise;
8371
+ return await promise;
8345
8372
  }
8346
- #signedKeyOwner = void 0;
8347
8373
  async getSignedKeyOwner(options = {}) {
8348
8374
  if (this.#signedKeyOwner != null) return this.#signedKeyOwner;
8349
- const key = await this.getSignedKey(options);
8350
- if (key == null) return this.#signedKeyOwner = null;
8351
- try {
8352
- return this.#signedKeyOwner = await getKeyOwner(key, {
8353
- contextLoader: options.contextLoader ?? this.contextLoader,
8354
- documentLoader: options.documentLoader ?? this.documentLoader,
8355
- tracerProvider: options.tracerProvider ?? this.tracerProvider
8356
- });
8357
- } catch (error) {
8358
- if (error instanceof FetchError) {
8359
- getLogger([
8360
- "fedify",
8361
- "federation",
8362
- "actor"
8363
- ]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
8364
- keyId: key.id?.href,
8365
- keyOwner: error.url.href,
8366
- error
8367
- });
8368
- return this.#signedKeyOwner = null;
8375
+ const normalizedOptions = {
8376
+ documentLoader: options.documentLoader ?? this.documentLoader,
8377
+ contextLoader: options.contextLoader ?? this.contextLoader,
8378
+ tracerProvider: options.tracerProvider ?? this.tracerProvider
8379
+ };
8380
+ const check = this.#getSignatureCheck(normalizedOptions.documentLoader, normalizedOptions.contextLoader);
8381
+ if (check.owner != null) return check.owner;
8382
+ const promise = this.getSignedKey(normalizedOptions).then(async (key) => {
8383
+ if (key == null) {
8384
+ if (check.owner === promise) check.owner = void 0;
8385
+ return null;
8386
+ }
8387
+ try {
8388
+ const owner = await getKeyOwner(key, normalizedOptions);
8389
+ if (owner != null) this.#signedKeyOwner ??= owner;
8390
+ return owner;
8391
+ } catch (error) {
8392
+ if (error instanceof FetchError) {
8393
+ getLogger([
8394
+ "fedify",
8395
+ "federation",
8396
+ "actor"
8397
+ ]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
8398
+ keyId: key.id?.href,
8399
+ keyOwner: error.url.href,
8400
+ error
8401
+ });
8402
+ return null;
8403
+ }
8404
+ throw error;
8369
8405
  }
8406
+ }).catch((error) => {
8407
+ if (check.owner === promise) check.owner = void 0;
8370
8408
  throw error;
8371
- }
8409
+ });
8410
+ check.owner = promise;
8411
+ return await promise;
8372
8412
  }
8373
8413
  async isSignedByAudience(object, options = {}) {
8374
8414
  return await isInAudience(object, null) || await isInAudience(object, await this.getSignedKeyOwner(options), options);