@fedify/fedify 2.5.0-dev.2597 → 2.5.0-dev.2614

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 (123) hide show
  1. package/dist/{builder-Da_V_LDj.mjs → builder-B2H8GsyI.mjs} +82 -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-BqqP38Sf.mjs → compound-proof-BavXW-ow.mjs} +2 -2
  6. package/dist/{context-ByflxsY9.d.cts → context-C1NqcIct.d.cts} +1061 -443
  7. package/dist/{context-uQUY5fQT.d.ts → context-xrqq4Hrq.d.ts} +1064 -446
  8. package/dist/{deno-4cGKg59R.mjs → deno-CRXki9-m.mjs} +1 -1
  9. package/dist/{docloader-BiHD6NSO.mjs → docloader-Ca6i6ddp.mjs} +2 -2
  10. package/dist/federation/builder.test.mjs +1 -1
  11. package/dist/federation/compound-fanout.test.mjs +3 -3
  12. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  13. package/dist/federation/handler.test.mjs +4 -4
  14. package/dist/federation/hashlink-media.test.mjs +2 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/inbox-actorless.test.mjs +5 -5
  17. package/dist/federation/inbox-report.test.mjs +220 -5
  18. package/dist/federation/inbox-view.test.mjs +1 -1
  19. package/dist/federation/inbox.test.mjs +1 -1
  20. package/dist/federation/metrics.test.mjs +1 -1
  21. package/dist/federation/middleware.test.mjs +7 -7
  22. package/dist/federation/mod.cjs +1 -1
  23. package/dist/federation/mod.d.cts +3 -3
  24. package/dist/federation/mod.d.ts +4 -4
  25. package/dist/federation/mod.js +1 -1
  26. package/dist/federation/mq.test.mjs +1 -1
  27. package/dist/federation/outbound-body.test.d.mts +2 -0
  28. package/dist/federation/outbound-body.test.mjs +149 -0
  29. package/dist/federation/outbound-capture.test.d.mts +2 -0
  30. package/dist/federation/outbound-capture.test.mjs +394 -0
  31. package/dist/federation/outbound-dispatch.test.d.mts +2 -0
  32. package/dist/federation/outbound-dispatch.test.mjs +368 -0
  33. package/dist/federation/outbound-document.test.d.mts +2 -0
  34. package/dist/federation/outbound-document.test.mjs +171 -0
  35. package/dist/federation/outbound-provenance.test.d.mts +2 -0
  36. package/dist/federation/outbound-provenance.test.mjs +543 -0
  37. package/dist/federation/outbound-report.test.d.mts +2 -0
  38. package/dist/federation/outbound-report.test.mjs +5475 -0
  39. package/dist/federation/outbound-workers.test.d.mts +2 -0
  40. package/dist/federation/outbound-workers.test.mjs +64 -0
  41. package/dist/federation/outbound-workflow.test.d.mts +2 -0
  42. package/dist/federation/outbound-workflow.test.mjs +154 -0
  43. package/dist/federation/outgoing-proof.test.mjs +4 -4
  44. package/dist/federation/portable-actor.test.mjs +3 -3
  45. package/dist/federation/portable-chain.test.mjs +3 -3
  46. package/dist/federation/portable-collection.test.mjs +4 -4
  47. package/dist/federation/portable-delivery.test.mjs +106 -7
  48. package/dist/federation/portable-gateway-keys.test.mjs +5 -5
  49. package/dist/federation/portable-inbox.test.mjs +430 -5
  50. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  51. package/dist/federation/portable-route-activity.test.mjs +2 -2
  52. package/dist/federation/portable.test.mjs +3 -3
  53. package/dist/federation/send.test.mjs +44 -3
  54. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  55. package/dist/federation/tasks/tasks.test.mjs +2 -2
  56. package/dist/federation/temporal.test.mjs +1 -1
  57. package/dist/federation/webfinger.test.mjs +1 -1
  58. package/dist/{federation-BKJZEC0O.cjs → federation-DRl81KbJ.cjs} +2358 -405
  59. package/dist/{http-DQP4rw46.js → http-C2H4DT6t.js} +62 -32
  60. package/dist/{http-KU7_TLD9.cjs → http-DHSIMipE.cjs} +62 -32
  61. package/dist/{http-D5n4S1oL.mjs → http-DqOXkYbX.mjs} +64 -34
  62. package/dist/{inbox-CElAglrC.mjs → inbox-C4iW1g0F.mjs} +90 -3
  63. package/dist/{inbox-view-BTUuIIf6.mjs → inbox-view-Bu_aSwFJ.mjs} +1 -1
  64. package/dist/{key-DbLNT-vA.d.ts → key-dwwAg5bA.d.ts} +1 -1
  65. package/dist/{kv-cache-CFBwLUZr.js → kv-cache-B-x_OrBo.js} +1 -1
  66. package/dist/{kv-cache-DrQn-ugb.cjs → kv-cache-CHR_BVyM.cjs} +1 -1
  67. package/dist/{kv-cache-BV55jAE6.mjs → kv-cache-DJsxu9nI.mjs} +1 -1
  68. package/dist/{ld-CmAQYDWE.mjs → ld-C5JOBBFj.mjs} +2 -2
  69. package/dist/{ld-Inagww4R.d.ts → ld-o4LnhCYY.d.ts} +2 -2
  70. package/dist/{metrics-BvV60TwE.mjs → metrics-CTteRnEr.mjs} +1 -1
  71. package/dist/{metrics-DoRtI0qU.d.ts → metrics-DVKYY6K1.d.ts} +1 -1
  72. package/dist/{middleware-Di4y_M3y.js → middleware-B-tMVSUA.js} +2303 -351
  73. package/dist/{middleware-D02eC0j7.mjs → middleware-BkRqMGPU.mjs} +1573 -325
  74. package/dist/{middleware-iAJcDIM2.mjs → middleware-CPigKLnt.mjs} +1 -1
  75. package/dist/{mod-B7j30IQf.d.ts → mod-CQC9xlLZ.d.ts} +3 -3
  76. package/dist/{mod-B4kBw1-8.d.ts → mod-D22ZsiKi.d.ts} +2 -2
  77. package/dist/{mod-BN0TTfyQ.d.ts → mod-DO0epJGH.d.ts} +1 -1
  78. package/dist/{mod-DF2gbN_d.d.cts → mod-TwiQgEf3.d.cts} +1 -1
  79. package/dist/mod.cjs +4 -4
  80. package/dist/mod.d.cts +4 -4
  81. package/dist/mod.d.ts +8 -8
  82. package/dist/mod.js +4 -4
  83. package/dist/nodeinfo/handler.test.mjs +1 -1
  84. package/dist/outbound-body-CckPA5gc.mjs +83 -0
  85. package/dist/outbound-capture-DVgnRzlf.mjs +184 -0
  86. package/dist/outbound-document-BMgwLXTY.mjs +179 -0
  87. package/dist/{owner-C1-csjTo.mjs → owner-CKlRIkeF.mjs} +3 -3
  88. package/dist/{portable-collection-C0MNEEED.mjs → portable-collection-B7RBHVGl.mjs} +2 -2
  89. package/dist/{portable-collection-DkTLVfoM.js → portable-collection-CByyPjLc.js} +2 -2
  90. package/dist/{portable-collection-w6Qn-vJ3.cjs → portable-collection-CmLjeKsP.cjs} +2 -2
  91. package/dist/{portable-key-jtaxB7TD.mjs → portable-key-Clg0IH8C.mjs} +1 -1
  92. package/dist/{proof-CzWCRhnC.mjs → proof-tAb5_Dq4.mjs} +3 -3
  93. package/dist/{send-C9-dwpEH.mjs → send-DzfFREML.mjs} +153 -40
  94. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  95. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  96. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  97. package/dist/sig/compound-proof.test.mjs +2 -2
  98. package/dist/sig/http.test.mjs +38 -2
  99. package/dist/sig/key.test.mjs +1 -1
  100. package/dist/sig/ld.test.mjs +1 -1
  101. package/dist/sig/mitra-receive-interop.test.mjs +4 -4
  102. package/dist/sig/mitra-send-interop.test.mjs +3 -3
  103. package/dist/sig/mod.cjs +2 -2
  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 +3 -3
  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-lDCl8Zxn.mjs → temporal-D9Nt8Fm4.mjs} +1 -1
  115. package/dist/testing/kv.test.mjs +1 -1
  116. package/dist/testing/mod.d.mts +1030 -412
  117. package/dist/utils/docloader.test.mjs +2 -2
  118. package/dist/utils/kv-cache.test.mjs +1 -1
  119. package/dist/utils/mod.cjs +1 -1
  120. package/dist/utils/mod.d.ts +1 -1
  121. package/dist/utils/mod.js +1 -1
  122. package/package.json +6 -6
  123. package/skills/fedify/SKILL.md +60 -1
@@ -1,9 +1,9 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { getLogger } from "@logtape/logtape";
4
+ import { FetchError, UrlError, canonicalizePortableUri, encodeMultibase, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, isGatewayUrl, isTransientFetchError, parseDidKeyVerificationMethod, parseGatewayUrl, parseIri, preloadedContexts, toCompatibleEf61Id } from "@fedify/vocab-runtime";
4
5
  import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, PUBLIC_COLLECTION, getTypeId, isActor } from "@fedify/vocab";
5
6
  import { SpanKind, SpanStatusCode, metrics, trace } from "@opentelemetry/api";
6
- import { FetchError, UrlError, canonicalizePortableUri, encodeMultibase, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, isGatewayUrl, isTransientFetchError, parseDidKeyVerificationMethod, parseGatewayUrl, parseIri, preloadedContexts, toCompatibleEf61Id } from "@fedify/vocab-runtime";
7
7
  import { getPortableGatewayCandidates, isCompatibleEf61Iri } from "@fedify/vocab-runtime/internal/portable-dereference";
8
8
  import { encodeHex } from "byte-encodings/hex";
9
9
  import jsonld from "@fedify/vocab-runtime/jsonld";
@@ -15,7 +15,7 @@ import serialize from "json-canon";
15
15
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
16
16
  //#region deno.json
17
17
  var name = "@fedify/fedify";
18
- var version = "2.5.0-dev.2597+7bed9e2b";
18
+ var version = "2.5.0-dev.2614+a776599e";
19
19
  //#endregion
20
20
  //#region src/sig/portable-key-id.ts
21
21
  const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
@@ -6595,13 +6595,29 @@ async function createRedirectRequest(request, location, body, validateRedirect)
6595
6595
  cache: request.cache
6596
6596
  });
6597
6597
  }
6598
- async function fetchDoubleKnockRequest(session, request, signedRequest, signal) {
6598
+ function observeDoubleKnockOperation(observation, phase, operation) {
6599
+ if (observation == null) return operation();
6600
+ try {
6601
+ return Promise.resolve(operation()).catch((error) => {
6602
+ observation.error(phase, error);
6603
+ throw error;
6604
+ });
6605
+ } catch (error) {
6606
+ observation.error(phase, error);
6607
+ throw error;
6608
+ }
6609
+ }
6610
+ function submitDoubleKnockRequest(session, request, signal, observation) {
6611
+ const submit = () => session.fetch(request, {
6612
+ redirect: "manual",
6613
+ signal
6614
+ });
6615
+ return observation == null ? submit() : observation.fetch(request, submit);
6616
+ }
6617
+ async function fetchDoubleKnockRequest(session, request, signedRequest, signal, observation) {
6599
6618
  const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
6600
6619
  for (let attempt = 1;; attempt++) try {
6601
- return await session.fetch(signedRequest, {
6602
- redirect: "manual",
6603
- signal
6604
- });
6620
+ return await submitDoubleKnockRequest(session, signedRequest, signal, observation);
6605
6621
  } catch (error) {
6606
6622
  const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
6607
6623
  if (abortedSignal != null) throw getAbortReason(abortedSignal);
@@ -6660,10 +6676,11 @@ function getAbortReason(signal) {
6660
6676
  * @param openHop The function to open a session for each hop. The session of
6661
6677
  * a hop is closed before the next hop is opened.
6662
6678
  * @param consume The function to consume the final response.
6679
+ * @param observation The in-process transport/finality hooks, if registered.
6663
6680
  * @returns The value returned by `consume`.
6664
6681
  */
6665
- async function doubleKnockScoped(request, identity, options, openHop, consume) {
6666
- const { response, session } = await doubleKnockCore(request, identity, options, openHop);
6682
+ async function doubleKnockScoped(request, identity, options, openHop, consume, observation) {
6683
+ const { response, session } = await doubleKnockCore(request, identity, options, openHop, observation);
6667
6684
  try {
6668
6685
  return await consume(response);
6669
6686
  } catch (error) {
@@ -6702,7 +6719,7 @@ function cancelResponseBody(response, url) {
6702
6719
  });
6703
6720
  });
6704
6721
  }
6705
- async function doubleKnockCore(request, identity, options, openHop) {
6722
+ async function doubleKnockCore(request, identity, options, openHop, observation) {
6706
6723
  const { specDeterminer, log, tracerProvider, signal } = options;
6707
6724
  signal?.throwIfAborted();
6708
6725
  const maximumRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
@@ -6713,16 +6730,16 @@ async function doubleKnockCore(request, identity, options, openHop) {
6713
6730
  for (let redirected = 0;; redirected++) {
6714
6731
  visited.add(request.url);
6715
6732
  const origin = new URL(request.url).origin;
6716
- const firstTrySpec = specDeterminer == null ? "rfc9421" : await specDeterminer.determineSpec(origin);
6733
+ const firstTrySpec = specDeterminer == null ? "rfc9421" : await observeDoubleKnockOperation(observation, "spec-lookup", () => specDeterminer.determineSpec(origin));
6717
6734
  signal?.throwIfAborted();
6718
- let signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
6735
+ let signedRequest = await observeDoubleKnockOperation(observation, "signing", () => signRequest(request, identity.privateKey, identity.keyId, {
6719
6736
  spec: firstTrySpec,
6720
6737
  tracerProvider,
6721
6738
  body
6722
- });
6739
+ }));
6723
6740
  signal?.throwIfAborted();
6724
6741
  log?.(signedRequest);
6725
- let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
6742
+ let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal, observation);
6726
6743
  const firstRedirected = isRedirectResponse(response);
6727
6744
  if (!firstRedirected && (response.status === 400 || response.status === 401 || response.status > 401)) {
6728
6745
  const logger = getLogger([
@@ -6761,30 +6778,33 @@ async function doubleKnockCore(request, identity, options, openHop) {
6761
6778
  }
6762
6779
  }
6763
6780
  if (fulfilled && challengeRequest != null) {
6781
+ observation?.response(response, "intermediate");
6764
6782
  signal?.throwIfAborted();
6765
6783
  cancelResponseBody(response, request.url);
6766
6784
  signedRequest = challengeRequest;
6767
6785
  log?.(signedRequest);
6768
- response = await session.fetch(signedRequest, {
6769
- redirect: "manual",
6770
- signal
6771
- });
6786
+ response = await submitDoubleKnockRequest(session, signedRequest, signal, observation);
6772
6787
  }
6773
6788
  if (fulfilled && !isRedirectResponse(response)) {
6774
6789
  if (response.status < 300) {
6775
- await specDeterminer?.rememberSpec(origin, "rfc9421");
6790
+ observation?.response(response, "final");
6791
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, "rfc9421") ?? Promise.resolve());
6792
+ return {
6793
+ response,
6794
+ session
6795
+ };
6796
+ }
6797
+ if (response.status !== 400 && response.status !== 401) {
6798
+ observation?.response(response, "final");
6776
6799
  return {
6777
6800
  response,
6778
6801
  session
6779
6802
  };
6780
6803
  }
6781
- if (response.status !== 400 && response.status !== 401) return {
6782
- response,
6783
- session
6784
- };
6785
6804
  }
6786
6805
  }
6787
6806
  if (!isRedirectResponse(response)) {
6807
+ observation?.response(response, "intermediate");
6788
6808
  const spec = firstTrySpec === "draft-cavage-http-signatures-12" ? "rfc9421" : "draft-cavage-http-signatures-12";
6789
6809
  getLogger([
6790
6810
  "fedify",
@@ -6798,21 +6818,31 @@ async function doubleKnockCore(request, identity, options, openHop) {
6798
6818
  });
6799
6819
  cancelResponseBody(response, request.url);
6800
6820
  signal?.throwIfAborted();
6801
- signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
6821
+ signedRequest = await observeDoubleKnockOperation(observation, "signing", () => signRequest(request, identity.privateKey, identity.keyId, {
6802
6822
  spec,
6803
6823
  tracerProvider,
6804
6824
  body
6805
- });
6825
+ }));
6806
6826
  signal?.throwIfAborted();
6807
6827
  log?.(signedRequest);
6808
- response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
6809
- if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) await specDeterminer?.rememberSpec(origin, spec);
6828
+ response = await fetchDoubleKnockRequest(session, request, signedRequest, signal, observation);
6829
+ if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) {
6830
+ observation?.response(response, "final");
6831
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, spec) ?? Promise.resolve());
6832
+ }
6810
6833
  }
6811
- } else if (!firstRedirected) await specDeterminer?.rememberSpec(origin, firstTrySpec);
6812
- if (!isRedirectResponse(response)) return {
6813
- response,
6814
- session
6815
- };
6834
+ } else if (!firstRedirected) {
6835
+ observation?.response(response, "final");
6836
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, firstTrySpec) ?? Promise.resolve());
6837
+ }
6838
+ if (!isRedirectResponse(response)) {
6839
+ observation?.response(response, "final");
6840
+ return {
6841
+ response,
6842
+ session
6843
+ };
6844
+ }
6845
+ observation?.response(response, "intermediate");
6816
6846
  cancelResponseBody(response, request.url);
6817
6847
  await session.close();
6818
6848
  if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
@@ -1,9 +1,9 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-Dmm3t92W.cjs");
3
3
  let _logtape_logtape = require("@logtape/logtape");
4
+ let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
4
5
  let _fedify_vocab = require("@fedify/vocab");
5
6
  let _opentelemetry_api = require("@opentelemetry/api");
6
- let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
7
7
  let _fedify_vocab_runtime_internal_portable_dereference = require("@fedify/vocab-runtime/internal/portable-dereference");
8
8
  let byte_encodings_hex = require("byte-encodings/hex");
9
9
  let _fedify_vocab_runtime_jsonld = require("@fedify/vocab-runtime/jsonld");
@@ -17,7 +17,7 @@ json_canon = require_rolldown_runtime.__toESM(json_canon, 1);
17
17
  let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
18
18
  //#region deno.json
19
19
  var name = "@fedify/fedify";
20
- var version = "2.5.0-dev.2597+7bed9e2b";
20
+ var version = "2.5.0-dev.2614+a776599e";
21
21
  //#endregion
22
22
  //#region src/sig/portable-key-id.ts
23
23
  const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
@@ -10165,13 +10165,29 @@ async function createRedirectRequest(request, location, body, validateRedirect)
10165
10165
  cache: request.cache
10166
10166
  });
10167
10167
  }
10168
- async function fetchDoubleKnockRequest(session, request, signedRequest, signal) {
10168
+ function observeDoubleKnockOperation(observation, phase, operation) {
10169
+ if (observation == null) return operation();
10170
+ try {
10171
+ return Promise.resolve(operation()).catch((error) => {
10172
+ observation.error(phase, error);
10173
+ throw error;
10174
+ });
10175
+ } catch (error) {
10176
+ observation.error(phase, error);
10177
+ throw error;
10178
+ }
10179
+ }
10180
+ function submitDoubleKnockRequest(session, request, signal, observation) {
10181
+ const submit = () => session.fetch(request, {
10182
+ redirect: "manual",
10183
+ signal
10184
+ });
10185
+ return observation == null ? submit() : observation.fetch(request, submit);
10186
+ }
10187
+ async function fetchDoubleKnockRequest(session, request, signedRequest, signal, observation) {
10169
10188
  const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
10170
10189
  for (let attempt = 1;; attempt++) try {
10171
- return await session.fetch(signedRequest, {
10172
- redirect: "manual",
10173
- signal
10174
- });
10190
+ return await submitDoubleKnockRequest(session, signedRequest, signal, observation);
10175
10191
  } catch (error) {
10176
10192
  const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
10177
10193
  if (abortedSignal != null) throw getAbortReason(abortedSignal);
@@ -10230,10 +10246,11 @@ function getAbortReason(signal) {
10230
10246
  * @param openHop The function to open a session for each hop. The session of
10231
10247
  * a hop is closed before the next hop is opened.
10232
10248
  * @param consume The function to consume the final response.
10249
+ * @param observation The in-process transport/finality hooks, if registered.
10233
10250
  * @returns The value returned by `consume`.
10234
10251
  */
10235
- async function doubleKnockScoped(request, identity, options, openHop, consume) {
10236
- const { response, session } = await doubleKnockCore(request, identity, options, openHop);
10252
+ async function doubleKnockScoped(request, identity, options, openHop, consume, observation) {
10253
+ const { response, session } = await doubleKnockCore(request, identity, options, openHop, observation);
10237
10254
  try {
10238
10255
  return await consume(response);
10239
10256
  } catch (error) {
@@ -10272,7 +10289,7 @@ function cancelResponseBody(response, url) {
10272
10289
  });
10273
10290
  });
10274
10291
  }
10275
- async function doubleKnockCore(request, identity, options, openHop) {
10292
+ async function doubleKnockCore(request, identity, options, openHop, observation) {
10276
10293
  const { specDeterminer, log, tracerProvider, signal } = options;
10277
10294
  signal?.throwIfAborted();
10278
10295
  const maximumRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
@@ -10283,16 +10300,16 @@ async function doubleKnockCore(request, identity, options, openHop) {
10283
10300
  for (let redirected = 0;; redirected++) {
10284
10301
  visited.add(request.url);
10285
10302
  const origin = new URL(request.url).origin;
10286
- const firstTrySpec = specDeterminer == null ? "rfc9421" : await specDeterminer.determineSpec(origin);
10303
+ const firstTrySpec = specDeterminer == null ? "rfc9421" : await observeDoubleKnockOperation(observation, "spec-lookup", () => specDeterminer.determineSpec(origin));
10287
10304
  signal?.throwIfAborted();
10288
- let signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
10305
+ let signedRequest = await observeDoubleKnockOperation(observation, "signing", () => signRequest(request, identity.privateKey, identity.keyId, {
10289
10306
  spec: firstTrySpec,
10290
10307
  tracerProvider,
10291
10308
  body
10292
- });
10309
+ }));
10293
10310
  signal?.throwIfAborted();
10294
10311
  log?.(signedRequest);
10295
- let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
10312
+ let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal, observation);
10296
10313
  const firstRedirected = isRedirectResponse(response);
10297
10314
  if (!firstRedirected && (response.status === 400 || response.status === 401 || response.status > 401)) {
10298
10315
  const logger = (0, _logtape_logtape.getLogger)([
@@ -10331,30 +10348,33 @@ async function doubleKnockCore(request, identity, options, openHop) {
10331
10348
  }
10332
10349
  }
10333
10350
  if (fulfilled && challengeRequest != null) {
10351
+ observation?.response(response, "intermediate");
10334
10352
  signal?.throwIfAborted();
10335
10353
  cancelResponseBody(response, request.url);
10336
10354
  signedRequest = challengeRequest;
10337
10355
  log?.(signedRequest);
10338
- response = await session.fetch(signedRequest, {
10339
- redirect: "manual",
10340
- signal
10341
- });
10356
+ response = await submitDoubleKnockRequest(session, signedRequest, signal, observation);
10342
10357
  }
10343
10358
  if (fulfilled && !isRedirectResponse(response)) {
10344
10359
  if (response.status < 300) {
10345
- await specDeterminer?.rememberSpec(origin, "rfc9421");
10360
+ observation?.response(response, "final");
10361
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, "rfc9421") ?? Promise.resolve());
10362
+ return {
10363
+ response,
10364
+ session
10365
+ };
10366
+ }
10367
+ if (response.status !== 400 && response.status !== 401) {
10368
+ observation?.response(response, "final");
10346
10369
  return {
10347
10370
  response,
10348
10371
  session
10349
10372
  };
10350
10373
  }
10351
- if (response.status !== 400 && response.status !== 401) return {
10352
- response,
10353
- session
10354
- };
10355
10374
  }
10356
10375
  }
10357
10376
  if (!isRedirectResponse(response)) {
10377
+ observation?.response(response, "intermediate");
10358
10378
  const spec = firstTrySpec === "draft-cavage-http-signatures-12" ? "rfc9421" : "draft-cavage-http-signatures-12";
10359
10379
  (0, _logtape_logtape.getLogger)([
10360
10380
  "fedify",
@@ -10368,21 +10388,31 @@ async function doubleKnockCore(request, identity, options, openHop) {
10368
10388
  });
10369
10389
  cancelResponseBody(response, request.url);
10370
10390
  signal?.throwIfAborted();
10371
- signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
10391
+ signedRequest = await observeDoubleKnockOperation(observation, "signing", () => signRequest(request, identity.privateKey, identity.keyId, {
10372
10392
  spec,
10373
10393
  tracerProvider,
10374
10394
  body
10375
- });
10395
+ }));
10376
10396
  signal?.throwIfAborted();
10377
10397
  log?.(signedRequest);
10378
- response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
10379
- if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) await specDeterminer?.rememberSpec(origin, spec);
10398
+ response = await fetchDoubleKnockRequest(session, request, signedRequest, signal, observation);
10399
+ if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) {
10400
+ observation?.response(response, "final");
10401
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, spec) ?? Promise.resolve());
10402
+ }
10380
10403
  }
10381
- } else if (!firstRedirected) await specDeterminer?.rememberSpec(origin, firstTrySpec);
10382
- if (!isRedirectResponse(response)) return {
10383
- response,
10384
- session
10385
- };
10404
+ } else if (!firstRedirected) {
10405
+ observation?.response(response, "final");
10406
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, firstTrySpec) ?? Promise.resolve());
10407
+ }
10408
+ if (!isRedirectResponse(response)) {
10409
+ observation?.response(response, "final");
10410
+ return {
10411
+ response,
10412
+ session
10413
+ };
10414
+ }
10415
+ observation?.response(response, "intermediate");
10386
10416
  cancelResponseBody(response, request.url);
10387
10417
  await session.close();
10388
10418
  if (redirected >= maximumRedirection) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
@@ -3,12 +3,12 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { m as parseKeyIdString } 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-4cGKg59R.mjs";
7
- import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BvV60TwE.mjs";
6
+ import { n as version, t as name } from "./deno-CRXki9-m.mjs";
7
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-CTteRnEr.mjs";
8
8
  import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPVqki78.mjs";
9
9
  import { a as promoteKeyOwnerEvidence } from "./key-owner-evidence-APB6NpSk.mjs";
10
- import { D as validateCryptoKey, b as bypassKeyCacheReads, w as fetchKeyDetailed } from "./ld-CmAQYDWE.mjs";
11
- import { n as resolvePortableActorKey, r as verifyPortableGatewayKeyDocument } from "./portable-key-jtaxB7TD.mjs";
10
+ import { D as validateCryptoKey, b as bypassKeyCacheReads, w as fetchKeyDetailed } from "./ld-C5JOBBFj.mjs";
11
+ import { n as resolvePortableActorKey, r as verifyPortableGatewayKeyDocument } from "./portable-key-Clg0IH8C.mjs";
12
12
  import { getLogger } from "@logtape/logtape";
13
13
  import { CryptographicKey } from "@fedify/vocab";
14
14
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -1116,13 +1116,29 @@ async function createRedirectRequest(request, location, body, validateRedirect)
1116
1116
  cache: request.cache
1117
1117
  });
1118
1118
  }
1119
- async function fetchDoubleKnockRequest(session, request, signedRequest, signal) {
1119
+ function observeDoubleKnockOperation(observation, phase, operation) {
1120
+ if (observation == null) return operation();
1121
+ try {
1122
+ return Promise.resolve(operation()).catch((error) => {
1123
+ observation.error(phase, error);
1124
+ throw error;
1125
+ });
1126
+ } catch (error) {
1127
+ observation.error(phase, error);
1128
+ throw error;
1129
+ }
1130
+ }
1131
+ function submitDoubleKnockRequest(session, request, signal, observation) {
1132
+ const submit = () => session.fetch(request, {
1133
+ redirect: "manual",
1134
+ signal
1135
+ });
1136
+ return observation == null ? submit() : observation.fetch(request, submit);
1137
+ }
1138
+ async function fetchDoubleKnockRequest(session, request, signedRequest, signal, observation) {
1120
1139
  const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
1121
1140
  for (let attempt = 1;; attempt++) try {
1122
- return await session.fetch(signedRequest, {
1123
- redirect: "manual",
1124
- signal
1125
- });
1141
+ return await submitDoubleKnockRequest(session, signedRequest, signal, observation);
1126
1142
  } catch (error) {
1127
1143
  const abortedSignal = getAbortedSignal(signal, request.signal, signedRequest.signal);
1128
1144
  if (abortedSignal != null) throw getAbortReason(abortedSignal);
@@ -1195,10 +1211,11 @@ async function doubleKnock(request, identity, options = {}) {
1195
1211
  * @param openHop The function to open a session for each hop. The session of
1196
1212
  * a hop is closed before the next hop is opened.
1197
1213
  * @param consume The function to consume the final response.
1214
+ * @param observation The in-process transport/finality hooks, if registered.
1198
1215
  * @returns The value returned by `consume`.
1199
1216
  */
1200
- async function doubleKnockScoped(request, identity, options, openHop, consume) {
1201
- const { response, session } = await doubleKnockCore(request, identity, options, openHop);
1217
+ async function doubleKnockScoped(request, identity, options, openHop, consume, observation) {
1218
+ const { response, session } = await doubleKnockCore(request, identity, options, openHop, observation);
1202
1219
  try {
1203
1220
  return await consume(response);
1204
1221
  } catch (error) {
@@ -1252,7 +1269,7 @@ function cancelResponseBody(response, url) {
1252
1269
  });
1253
1270
  });
1254
1271
  }
1255
- async function doubleKnockCore(request, identity, options, openHop) {
1272
+ async function doubleKnockCore(request, identity, options, openHop, observation) {
1256
1273
  const { specDeterminer, log, tracerProvider, signal } = options;
1257
1274
  signal?.throwIfAborted();
1258
1275
  const maximumRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
@@ -1263,16 +1280,16 @@ async function doubleKnockCore(request, identity, options, openHop) {
1263
1280
  for (let redirected = 0;; redirected++) {
1264
1281
  visited.add(request.url);
1265
1282
  const origin = new URL(request.url).origin;
1266
- const firstTrySpec = specDeterminer == null ? "rfc9421" : await specDeterminer.determineSpec(origin);
1283
+ const firstTrySpec = specDeterminer == null ? "rfc9421" : await observeDoubleKnockOperation(observation, "spec-lookup", () => specDeterminer.determineSpec(origin));
1267
1284
  signal?.throwIfAborted();
1268
- let signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
1285
+ let signedRequest = await observeDoubleKnockOperation(observation, "signing", () => signRequest(request, identity.privateKey, identity.keyId, {
1269
1286
  spec: firstTrySpec,
1270
1287
  tracerProvider,
1271
1288
  body
1272
- });
1289
+ }));
1273
1290
  signal?.throwIfAborted();
1274
1291
  log?.(signedRequest);
1275
- let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
1292
+ let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal, observation);
1276
1293
  const firstRedirected = isRedirectResponse(response);
1277
1294
  if (!firstRedirected && (response.status === 400 || response.status === 401 || response.status > 401)) {
1278
1295
  const logger = getLogger([
@@ -1311,30 +1328,33 @@ async function doubleKnockCore(request, identity, options, openHop) {
1311
1328
  }
1312
1329
  }
1313
1330
  if (fulfilled && challengeRequest != null) {
1331
+ observation?.response(response, "intermediate");
1314
1332
  signal?.throwIfAborted();
1315
1333
  cancelResponseBody(response, request.url);
1316
1334
  signedRequest = challengeRequest;
1317
1335
  log?.(signedRequest);
1318
- response = await session.fetch(signedRequest, {
1319
- redirect: "manual",
1320
- signal
1321
- });
1336
+ response = await submitDoubleKnockRequest(session, signedRequest, signal, observation);
1322
1337
  }
1323
1338
  if (fulfilled && !isRedirectResponse(response)) {
1324
1339
  if (response.status < 300) {
1325
- await specDeterminer?.rememberSpec(origin, "rfc9421");
1340
+ observation?.response(response, "final");
1341
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, "rfc9421") ?? Promise.resolve());
1342
+ return {
1343
+ response,
1344
+ session
1345
+ };
1346
+ }
1347
+ if (response.status !== 400 && response.status !== 401) {
1348
+ observation?.response(response, "final");
1326
1349
  return {
1327
1350
  response,
1328
1351
  session
1329
1352
  };
1330
1353
  }
1331
- if (response.status !== 400 && response.status !== 401) return {
1332
- response,
1333
- session
1334
- };
1335
1354
  }
1336
1355
  }
1337
1356
  if (!isRedirectResponse(response)) {
1357
+ observation?.response(response, "intermediate");
1338
1358
  const spec = firstTrySpec === "draft-cavage-http-signatures-12" ? "rfc9421" : "draft-cavage-http-signatures-12";
1339
1359
  getLogger([
1340
1360
  "fedify",
@@ -1348,21 +1368,31 @@ async function doubleKnockCore(request, identity, options, openHop) {
1348
1368
  });
1349
1369
  cancelResponseBody(response, request.url);
1350
1370
  signal?.throwIfAborted();
1351
- signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
1371
+ signedRequest = await observeDoubleKnockOperation(observation, "signing", () => signRequest(request, identity.privateKey, identity.keyId, {
1352
1372
  spec,
1353
1373
  tracerProvider,
1354
1374
  body
1355
- });
1375
+ }));
1356
1376
  signal?.throwIfAborted();
1357
1377
  log?.(signedRequest);
1358
- response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
1359
- if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) await specDeterminer?.rememberSpec(origin, spec);
1378
+ response = await fetchDoubleKnockRequest(session, request, signedRequest, signal, observation);
1379
+ if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) {
1380
+ observation?.response(response, "final");
1381
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, spec) ?? Promise.resolve());
1382
+ }
1360
1383
  }
1361
- } else if (!firstRedirected) await specDeterminer?.rememberSpec(origin, firstTrySpec);
1362
- if (!isRedirectResponse(response)) return {
1363
- response,
1364
- session
1365
- };
1384
+ } else if (!firstRedirected) {
1385
+ observation?.response(response, "final");
1386
+ await observeDoubleKnockOperation(observation, "post-response", () => specDeterminer?.rememberSpec(origin, firstTrySpec) ?? Promise.resolve());
1387
+ }
1388
+ if (!isRedirectResponse(response)) {
1389
+ observation?.response(response, "final");
1390
+ return {
1391
+ response,
1392
+ session
1393
+ };
1394
+ }
1395
+ observation?.response(response, "intermediate");
1366
1396
  cancelResponseBody(response, request.url);
1367
1397
  await session.close();
1368
1398
  if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
@@ -3,11 +3,97 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as getAuthenticationOrigin } from "./portable-key-id-Ca30-hOa.mjs";
5
5
  import { o as serializeAuthentication, r as getEffectivePrincipals } from "./inbox-authentication-CgonVRkg.mjs";
6
- import { n as version, t as name } from "./deno-4cGKg59R.mjs";
7
- import { g as recordInboxActivity, n as getDurationMs, r as getFederationMetrics } from "./metrics-BvV60TwE.mjs";
6
+ import { n as version, t as name } from "./deno-CRXki9-m.mjs";
7
+ import { g as recordInboxActivity, n as getDurationMs, r as getFederationMetrics } from "./metrics-CTteRnEr.mjs";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { getTypeId } from "@fedify/vocab";
10
10
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
11
+ //#region src/federation/outbound-provenance.ts
12
+ const outboundProvenance = Symbol("outboundProvenance");
13
+ const emptyProvenance = Object.freeze({});
14
+ function getOutboundProvenance(context) {
15
+ return context[outboundProvenance] ?? emptyProvenance;
16
+ }
17
+ function snapshotLocalContext(context) {
18
+ return Object.freeze({
19
+ origin: context.origin,
20
+ host: context.host,
21
+ hostname: context.hostname,
22
+ canonicalOrigin: context.canonicalOrigin
23
+ });
24
+ }
25
+ function createInboxRequestSource(request, requestId, canonicalOrigin) {
26
+ const url = new URL(request.url);
27
+ return Object.freeze({
28
+ inboxRequestId: crypto.randomUUID(),
29
+ requestId,
30
+ context: snapshotLocalContext({
31
+ origin: url.origin,
32
+ host: url.host,
33
+ hostname: url.hostname,
34
+ canonicalOrigin: canonicalOrigin ?? url.origin
35
+ })
36
+ });
37
+ }
38
+ /** The same exact-string budget applies to public input and queued metadata. */
39
+ function validateDispatchId(value) {
40
+ if (value === void 0) return;
41
+ if (typeof value !== "string") throw new TypeError("dispatchId must be a string.");
42
+ if (value.length > 1024 || new TextEncoder().encode(value).byteLength > 1024) throw new RangeError("dispatchId must not exceed 1,024 UTF-8 bytes.");
43
+ }
44
+ /** A new public invocation keeps its HTTP source, with its own dispatch ID. */
45
+ function invocationProvenance(context, dispatchId) {
46
+ validateDispatchId(dispatchId);
47
+ const { dispatchId: _previous, ...source } = getOutboundProvenance(context);
48
+ return Object.freeze({
49
+ ...source,
50
+ ...dispatchId === void 0 ? {} : { dispatchId }
51
+ });
52
+ }
53
+ /** Restore only explicit source facts; never infer them from queue/trace IDs. */
54
+ function restoreProvenance(value) {
55
+ if (value === void 0) return emptyProvenance;
56
+ const record = (v) => v != null && typeof v === "object" && !Array.isArray(v);
57
+ const invalid = () => /* @__PURE__ */ new TypeError("Invalid provenance in queue metadata.");
58
+ if (!record(value)) throw invalid();
59
+ validateDispatchId(value.dispatchId);
60
+ if (value.originatingRequestId !== void 0 && typeof value.originatingRequestId !== "string") throw invalid();
61
+ let inboxRequest;
62
+ if (value.inboxRequest !== void 0) {
63
+ const source = value.inboxRequest;
64
+ if (!record(source) || typeof source.inboxRequestId !== "string" || source.inboxRequestId.length < 1 || typeof source.requestId !== "string" || !record(source.context)) throw invalid();
65
+ const facts = source.context;
66
+ if (typeof facts.origin !== "string" || typeof facts.host !== "string" || typeof facts.hostname !== "string" || typeof facts.canonicalOrigin !== "string") throw invalid();
67
+ inboxRequest = Object.freeze({
68
+ inboxRequestId: source.inboxRequestId,
69
+ requestId: source.requestId,
70
+ context: Object.freeze({
71
+ origin: facts.origin,
72
+ host: facts.host,
73
+ hostname: facts.hostname,
74
+ canonicalOrigin: facts.canonicalOrigin
75
+ })
76
+ });
77
+ }
78
+ return Object.freeze({
79
+ ...value.dispatchId === void 0 ? {} : { dispatchId: value.dispatchId },
80
+ ...inboxRequest == null ? {} : { inboxRequest },
81
+ ...value.originatingRequestId === void 0 ? {} : { originatingRequestId: value.originatingRequestId }
82
+ });
83
+ }
84
+ /** Omit absent provenance on legacy and independent producers. */
85
+ function serializeProvenance(value) {
86
+ const provenance = restoreProvenance(value);
87
+ return provenance.dispatchId === void 0 && provenance.inboxRequest == null && provenance.originatingRequestId == null ? {} : { provenance };
88
+ }
89
+ function sourceLogContext(source) {
90
+ return {
91
+ dispatchId: source.dispatchId,
92
+ sourceInboxRequestId: source.inboxRequest?.inboxRequestId,
93
+ sourceRequestId: source.inboxRequest?.requestId ?? source.originatingRequestId
94
+ };
95
+ }
96
+ //#endregion
11
97
  //#region src/federation/inbox.ts
12
98
  /**
13
99
  * Checks whether an activity's ID and all of its actor IDs have the same
@@ -188,6 +274,7 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
188
274
  propagation.inject(context.active(), carrier);
189
275
  message = {
190
276
  type: "inbox",
277
+ ...serializeProvenance(getOutboundProvenance(ctx)),
191
278
  id: crypto.randomUUID(),
192
279
  baseUrl: ctx.origin,
193
280
  activity: originalJson ?? json,
@@ -309,4 +396,4 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
309
396
  });
310
397
  }
311
398
  //#endregion
312
- export { isActorlessActivityAuthenticated as a, getInboxIdempotencyKey as i, checkActorlessActivity as n, isInboxActivityProcessed as o, estimateQueuedMessageSize as r, routeActivity as s, actorsHaveSameOrigin as t };
399
+ export { isActorlessActivityAuthenticated as a, createInboxRequestSource as c, invocationProvenance as d, outboundProvenance as f, sourceLogContext as g, snapshotLocalContext as h, getInboxIdempotencyKey as i, emptyProvenance as l, serializeProvenance as m, checkActorlessActivity as n, isInboxActivityProcessed as o, restoreProvenance as p, estimateQueuedMessageSize as r, routeActivity as s, actorsHaveSameOrigin as t, getOutboundProvenance as u };