@fedify/fedify 2.3.0-dev.1048 → 2.3.0-dev.1069

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 (43) hide show
  1. package/dist/{builder-BhiIuyGK.mjs → builder-DQ2zYTeA.mjs} +2 -2
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-D9LpbVQR.mjs → deno-CFXqOz6w.mjs} +1 -1
  4. package/dist/{docloader-y2viZ2Tx.mjs → docloader-QNtAtTZF.mjs} +2 -2
  5. package/dist/federation/builder.test.mjs +1 -1
  6. package/dist/federation/handler.test.mjs +2 -2
  7. package/dist/federation/idempotency.test.mjs +2 -2
  8. package/dist/federation/middleware.test.mjs +199 -6
  9. package/dist/federation/mod.cjs +1 -1
  10. package/dist/federation/mod.js +1 -1
  11. package/dist/federation/send.test.mjs +3 -3
  12. package/dist/federation/webfinger.test.mjs +1 -1
  13. package/dist/{http-CA4xKsSY.js → http-D2EDlTr2.js} +1 -1
  14. package/dist/{http-D6yvDhyL.mjs → http-QHJGzUe8.mjs} +2 -2
  15. package/dist/{http-Bj0uN6d-.cjs → http-e1wtIlFo.cjs} +1 -1
  16. package/dist/{key-BPjHWwyv.mjs → key-CpAxygvh.mjs} +1 -1
  17. package/dist/{kv-cache-BdSTsjLb.cjs → kv-cache-B3GfB70S.cjs} +1 -1
  18. package/dist/{kv-cache-DarvCOHt.js → kv-cache-KLjvIlKt.js} +1 -1
  19. package/dist/{ld-D9yQwfkO.mjs → ld-Ce_vkKjG.mjs} +2 -2
  20. package/dist/{middleware-C5ao_lvm.mjs → middleware-BJMPv7_l.mjs} +1 -1
  21. package/dist/{middleware-DTxZNOqy.cjs → middleware-CibncbiT.cjs} +1 -1
  22. package/dist/{middleware-Ccpokmfe.cjs → middleware-DOLrvK_b.cjs} +97 -8
  23. package/dist/{middleware-0n0ctSu_.js → middleware-De241etq.js} +96 -7
  24. package/dist/{middleware-THfK90u_.mjs → middleware-DsGmXfXz.mjs} +50 -13
  25. package/dist/mod.cjs +4 -4
  26. package/dist/mod.js +4 -4
  27. package/dist/nodeinfo/handler.test.mjs +1 -1
  28. package/dist/{owner-CebIXUof.mjs → owner-DmgzyItA.mjs} +2 -2
  29. package/dist/{proof-C2QsttUL.cjs → proof-BU1TpFYI.cjs} +1 -1
  30. package/dist/{proof-UXZOysVc.mjs → proof-C3q2IhUr.mjs} +2 -2
  31. package/dist/{proof-Cdxbeq4n.js → proof-DLDsFYfD.js} +1 -1
  32. package/dist/{send-_8qtDYZA.mjs → send-CTi2iPXp.mjs} +54 -2
  33. package/dist/sig/http.test.mjs +2 -2
  34. package/dist/sig/key.test.mjs +1 -1
  35. package/dist/sig/ld.test.mjs +2 -2
  36. package/dist/sig/mod.cjs +2 -2
  37. package/dist/sig/mod.js +2 -2
  38. package/dist/sig/owner.test.mjs +1 -1
  39. package/dist/sig/proof.test.mjs +1 -1
  40. package/dist/utils/docloader.test.mjs +2 -2
  41. package/dist/utils/mod.cjs +1 -1
  42. package/dist/utils/mod.js +1 -1
  43. package/package.json +5 -5
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./chunk-nlSIicah.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-ve6e2xcg.js";
5
- import { _ as version, a as verifyRequestDetailed, d as validateCryptoKey, f as formatAcceptSignature, g as name, i as verifyRequest, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, u as importJwk } from "./http-CA4xKsSY.js";
6
- import { c as getKeyOwner, d as detachSignature, f as hasSignatureLike, i as verifyObject, m as verifyJsonLd, n as hasProofLike, o as normalizeOutgoingActivityJsonLd, p as signJsonLd, r as signObject, s as doesActorOwnKey } from "./proof-Cdxbeq4n.js";
5
+ import { _ as version, a as verifyRequestDetailed, d as validateCryptoKey, f as formatAcceptSignature, g as name, i as verifyRequest, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, u as importJwk } from "./http-D2EDlTr2.js";
6
+ import { c as getKeyOwner, d as detachSignature, f as hasSignatureLike, i as verifyObject, m as verifyJsonLd, n as hasProofLike, o as normalizeOutgoingActivityJsonLd, p as signJsonLd, r as signObject, s as doesActorOwnKey } from "./proof-DLDsFYfD.js";
7
7
  import { n as getNodeInfo, t as nodeInfoToJson } from "./types-hvL8ElAs.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DarvCOHt.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-KLjvIlKt.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
11
11
  import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "@opentelemetry/api";
@@ -786,6 +786,8 @@ var FederationMetrics = class {
786
786
  signatureVerificationFailure;
787
787
  deliveryDuration;
788
788
  inboxProcessingDuration;
789
+ httpServerRequestCount;
790
+ httpServerRequestDuration;
789
791
  constructor(meterProvider) {
790
792
  const meter = meterProvider.getMeter(name, version);
791
793
  this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
@@ -808,6 +810,30 @@ var FederationMetrics = class {
808
810
  description: "Duration of ActivityPub inbox listener processing.",
809
811
  unit: "ms"
810
812
  });
813
+ this.httpServerRequestCount = meter.createCounter("fedify.http.server.request.count", {
814
+ description: "HTTP requests handled by Federation.fetch().",
815
+ unit: "{request}"
816
+ });
817
+ this.httpServerRequestDuration = meter.createHistogram("fedify.http.server.request.duration", {
818
+ description: "Duration of HTTP requests handled by Federation.fetch().",
819
+ unit: "ms",
820
+ advice: { explicitBucketBoundaries: [
821
+ 5,
822
+ 10,
823
+ 25,
824
+ 50,
825
+ 75,
826
+ 100,
827
+ 250,
828
+ 500,
829
+ 750,
830
+ 1e3,
831
+ 2500,
832
+ 5e3,
833
+ 7500,
834
+ 1e4
835
+ ] }
836
+ });
811
837
  }
812
838
  recordDelivery(inbox, durationMs, success, activityType) {
813
839
  const deliveryAttributes = {
@@ -832,7 +858,33 @@ var FederationMetrics = class {
832
858
  recordInboxProcessingDuration(activityType, durationMs) {
833
859
  this.inboxProcessingDuration.record(durationMs, { "activitypub.activity.type": activityType });
834
860
  }
861
+ recordHttpServerRequest(method, endpoint, durationMs, options = {}) {
862
+ const attributes = {
863
+ "http.request.method": normalizeHttpMethod(method),
864
+ "fedify.endpoint": endpoint
865
+ };
866
+ if (options.statusCode != null) attributes["http.response.status_code"] = options.statusCode;
867
+ if (options.routeTemplate != null) attributes["fedify.route.template"] = options.routeTemplate;
868
+ this.httpServerRequestCount.add(1, attributes);
869
+ this.httpServerRequestDuration.record(durationMs, attributes);
870
+ }
835
871
  };
872
+ const KNOWN_HTTP_METHODS = new Set([
873
+ "CONNECT",
874
+ "DELETE",
875
+ "GET",
876
+ "HEAD",
877
+ "OPTIONS",
878
+ "PATCH",
879
+ "POST",
880
+ "PUT",
881
+ "QUERY",
882
+ "TRACE"
883
+ ]);
884
+ function normalizeHttpMethod(method) {
885
+ const upper = method.toUpperCase();
886
+ return KNOWN_HTTP_METHODS.has(upper) ? upper : "_OTHER";
887
+ }
836
888
  const federationMetrics = /* @__PURE__ */ new WeakMap();
837
889
  /**
838
890
  * Gets the cached Fedify metric instruments for a meter provider.
@@ -3577,6 +3629,8 @@ var FederationImpl = class extends FederationBuilderImpl {
3577
3629
  fetch(request, options) {
3578
3630
  return withContext({ requestId: getRequestId(request) }, async () => {
3579
3631
  const tracer = this._getTracer();
3632
+ const metricState = {};
3633
+ const metricStart = performance.now();
3580
3634
  return await tracer.startActiveSpan(request.method, {
3581
3635
  kind: SpanKind.SERVER,
3582
3636
  attributes: {
@@ -3600,10 +3654,12 @@ var FederationImpl = class extends FederationBuilderImpl {
3600
3654
  response = await this.#fetch(request, {
3601
3655
  ...options,
3602
3656
  span,
3603
- tracer
3657
+ tracer,
3658
+ metricState
3604
3659
  });
3605
3660
  if (acceptsJsonLd(request)) response.headers.set("Vary", "Accept");
3606
3661
  } catch (error) {
3662
+ getFederationMetrics(this.meterProvider).recordHttpServerRequest(request.method, metricState.endpoint ?? "error", getDurationMs(metricStart), { routeTemplate: metricState.routeTemplate });
3607
3663
  span.setStatus({
3608
3664
  code: SpanStatusCode.ERROR,
3609
3665
  message: `${error}`
@@ -3616,6 +3672,10 @@ var FederationImpl = class extends FederationBuilderImpl {
3616
3672
  });
3617
3673
  throw error;
3618
3674
  }
3675
+ getFederationMetrics(this.meterProvider).recordHttpServerRequest(request.method, metricState.endpoint ?? "error", getDurationMs(metricStart), {
3676
+ statusCode: response.status,
3677
+ routeTemplate: metricState.routeTemplate
3678
+ });
3619
3679
  if (span.isRecording()) {
3620
3680
  span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, response.status);
3621
3681
  for (const [k, v] of response.headers) span.setAttribute(ATTR_HTTP_RESPONSE_HEADER(k), [v]);
@@ -3641,13 +3701,18 @@ var FederationImpl = class extends FederationBuilderImpl {
3641
3701
  });
3642
3702
  });
3643
3703
  }
3644
- async #fetch(request, { onNotFound, onNotAcceptable, onUnauthorized, contextData, span, tracer }) {
3704
+ async #fetch(request, { onNotFound, onNotAcceptable, onUnauthorized, contextData, span, tracer, metricState }) {
3645
3705
  onNotFound ??= notFound;
3646
3706
  onNotAcceptable ??= notAcceptable;
3647
3707
  onUnauthorized ??= unauthorized;
3648
3708
  const url = new URL(request.url);
3649
3709
  const route = this.router.route(url.pathname);
3650
- if (route == null) return await onNotFound(request);
3710
+ if (route == null) {
3711
+ metricState.endpoint = "not_found";
3712
+ return await onNotFound(request);
3713
+ }
3714
+ metricState.routeTemplate = route.template;
3715
+ metricState.endpoint = getEndpointCategory(route.name);
3651
3716
  span.updateName(`${request.method} ${route.template}`);
3652
3717
  let context = this.#createContext(request, contextData);
3653
3718
  const routeName = route.name.replace(/:.*$/, "");
@@ -3668,7 +3733,10 @@ var FederationImpl = class extends FederationBuilderImpl {
3668
3733
  nodeInfoDispatcher: this.nodeInfoDispatcher
3669
3734
  });
3670
3735
  }
3671
- if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
3736
+ if (request.method !== "POST" && !acceptsJsonLd(request)) {
3737
+ metricState.endpoint = "not_acceptable";
3738
+ return await onNotAcceptable(request);
3739
+ }
3672
3740
  switch (routeName) {
3673
3741
  case "actor":
3674
3742
  case "actorAlias": {
@@ -3859,12 +3927,33 @@ var FederationImpl = class extends FederationBuilderImpl {
3859
3927
  });
3860
3928
  }
3861
3929
  default: {
3930
+ metricState.endpoint = "not_found";
3862
3931
  const response = onNotFound(request);
3863
3932
  return response instanceof Promise ? await response : response;
3864
3933
  }
3865
3934
  }
3866
3935
  }
3867
3936
  };
3937
+ function getEndpointCategory(routeName) {
3938
+ if (routeName.startsWith("object:")) return "object";
3939
+ if (routeName.startsWith("collection:") || routeName.startsWith("orderedCollection:")) return "collection";
3940
+ if (routeName.startsWith("actorAlias:")) return "actor";
3941
+ switch (routeName) {
3942
+ case "webfinger": return "webfinger";
3943
+ case "nodeInfoJrd":
3944
+ case "nodeInfo": return "nodeinfo";
3945
+ case "actor": return "actor";
3946
+ case "inbox": return "inbox";
3947
+ case "sharedInbox": return "shared_inbox";
3948
+ case "outbox": return "outbox";
3949
+ case "following": return "following";
3950
+ case "followers": return "followers";
3951
+ case "liked": return "liked";
3952
+ case "featured": return "featured";
3953
+ case "featuredTags": return "featured_tags";
3954
+ default: return "not_found";
3955
+ }
3956
+ }
3868
3957
  const FANOUT_THRESHOLD = 5;
3869
3958
  var ContextImpl = class ContextImpl {
3870
3959
  url;
@@ -2,21 +2,21 @@ 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-D9LpbVQR.mjs";
5
+ import { n as version, t as name } from "./deno-CFXqOz6w.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-CceiKpCy.mjs";
7
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-BPjHWwyv.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-D6yvDhyL.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-y2viZ2Tx.mjs";
7
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-CpAxygvh.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-QHJGzUe8.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-QNtAtTZF.mjs";
10
10
  import { n as kvCache } from "./kv-cache-Bmv7tUzz.mjs";
11
- import { a as signJsonLd, i as hasSignatureLike, o as verifyJsonLd, r as detachSignature } from "./ld-D9yQwfkO.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-CebIXUof.mjs";
11
+ import { a as signJsonLd, i as hasSignatureLike, o as verifyJsonLd, r as detachSignature } from "./ld-Ce_vkKjG.mjs";
12
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DmgzyItA.mjs";
13
13
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-Bi7n-dEy.mjs";
14
- import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-UXZOysVc.mjs";
14
+ import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-C3q2IhUr.mjs";
15
15
  import { t as getNodeInfo } from "./client-CIiz1WX7.mjs";
16
16
  import { t as nodeInfoToJson } from "./types-BFowWFTT.mjs";
17
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-BhiIuyGK.mjs";
17
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-DQ2zYTeA.mjs";
18
18
  import { t as buildCollectionSynchronizationHeader } from "./collection-CA3V5zyK.mjs";
19
- import { a as getFederationMetrics, i as getDurationMs, n as extractInboxes, o as getRemoteHost, r as sendActivity, t as SendActivityError } from "./send-_8qtDYZA.mjs";
19
+ import { a as getFederationMetrics, i as getDurationMs, n as extractInboxes, o as getRemoteHost, r as sendActivity, t as SendActivityError } from "./send-CTi2iPXp.mjs";
20
20
  import { t as KvKeyCache } from "./keycache-BeU0LCII.mjs";
21
21
  import { t as acceptsJsonLd } from "./negotiation-VnHNB0Q5.mjs";
22
22
  import { t as createExponentialBackoffPolicy } from "./retry-_VvV0h9f.mjs";
@@ -2425,6 +2425,8 @@ var FederationImpl = class extends FederationBuilderImpl {
2425
2425
  fetch(request, options) {
2426
2426
  return withContext({ requestId: getRequestId(request) }, async () => {
2427
2427
  const tracer = this._getTracer();
2428
+ const metricState = {};
2429
+ const metricStart = performance.now();
2428
2430
  return await tracer.startActiveSpan(request.method, {
2429
2431
  kind: SpanKind.SERVER,
2430
2432
  attributes: {
@@ -2448,10 +2450,12 @@ var FederationImpl = class extends FederationBuilderImpl {
2448
2450
  response = await this.#fetch(request, {
2449
2451
  ...options,
2450
2452
  span,
2451
- tracer
2453
+ tracer,
2454
+ metricState
2452
2455
  });
2453
2456
  if (acceptsJsonLd(request)) response.headers.set("Vary", "Accept");
2454
2457
  } catch (error) {
2458
+ getFederationMetrics(this.meterProvider).recordHttpServerRequest(request.method, metricState.endpoint ?? "error", getDurationMs(metricStart), { routeTemplate: metricState.routeTemplate });
2455
2459
  span.setStatus({
2456
2460
  code: SpanStatusCode.ERROR,
2457
2461
  message: `${error}`
@@ -2464,6 +2468,10 @@ var FederationImpl = class extends FederationBuilderImpl {
2464
2468
  });
2465
2469
  throw error;
2466
2470
  }
2471
+ getFederationMetrics(this.meterProvider).recordHttpServerRequest(request.method, metricState.endpoint ?? "error", getDurationMs(metricStart), {
2472
+ statusCode: response.status,
2473
+ routeTemplate: metricState.routeTemplate
2474
+ });
2467
2475
  if (span.isRecording()) {
2468
2476
  span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, response.status);
2469
2477
  for (const [k, v] of response.headers) span.setAttribute(ATTR_HTTP_RESPONSE_HEADER(k), [v]);
@@ -2489,13 +2497,18 @@ var FederationImpl = class extends FederationBuilderImpl {
2489
2497
  });
2490
2498
  });
2491
2499
  }
2492
- async #fetch(request, { onNotFound, onNotAcceptable, onUnauthorized, contextData, span, tracer }) {
2500
+ async #fetch(request, { onNotFound, onNotAcceptable, onUnauthorized, contextData, span, tracer, metricState }) {
2493
2501
  onNotFound ??= notFound;
2494
2502
  onNotAcceptable ??= notAcceptable;
2495
2503
  onUnauthorized ??= unauthorized;
2496
2504
  const url = new URL(request.url);
2497
2505
  const route = this.router.route(url.pathname);
2498
- if (route == null) return await onNotFound(request);
2506
+ if (route == null) {
2507
+ metricState.endpoint = "not_found";
2508
+ return await onNotFound(request);
2509
+ }
2510
+ metricState.routeTemplate = route.template;
2511
+ metricState.endpoint = getEndpointCategory(route.name);
2499
2512
  span.updateName(`${request.method} ${route.template}`);
2500
2513
  let context = this.#createContext(request, contextData);
2501
2514
  const routeName = route.name.replace(/:.*$/, "");
@@ -2516,7 +2529,10 @@ var FederationImpl = class extends FederationBuilderImpl {
2516
2529
  nodeInfoDispatcher: this.nodeInfoDispatcher
2517
2530
  });
2518
2531
  }
2519
- if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
2532
+ if (request.method !== "POST" && !acceptsJsonLd(request)) {
2533
+ metricState.endpoint = "not_acceptable";
2534
+ return await onNotAcceptable(request);
2535
+ }
2520
2536
  switch (routeName) {
2521
2537
  case "actor":
2522
2538
  case "actorAlias": {
@@ -2707,12 +2723,33 @@ var FederationImpl = class extends FederationBuilderImpl {
2707
2723
  });
2708
2724
  }
2709
2725
  default: {
2726
+ metricState.endpoint = "not_found";
2710
2727
  const response = onNotFound(request);
2711
2728
  return response instanceof Promise ? await response : response;
2712
2729
  }
2713
2730
  }
2714
2731
  }
2715
2732
  };
2733
+ function getEndpointCategory(routeName) {
2734
+ if (routeName.startsWith("object:")) return "object";
2735
+ if (routeName.startsWith("collection:") || routeName.startsWith("orderedCollection:")) return "collection";
2736
+ if (routeName.startsWith("actorAlias:")) return "actor";
2737
+ switch (routeName) {
2738
+ case "webfinger": return "webfinger";
2739
+ case "nodeInfoJrd":
2740
+ case "nodeInfo": return "nodeinfo";
2741
+ case "actor": return "actor";
2742
+ case "inbox": return "inbox";
2743
+ case "sharedInbox": return "shared_inbox";
2744
+ case "outbox": return "outbox";
2745
+ case "following": return "following";
2746
+ case "followers": return "followers";
2747
+ case "liked": return "liked";
2748
+ case "featured": return "featured";
2749
+ case "featuredTags": return "featured_tags";
2750
+ default: return "not_found";
2751
+ }
2752
+ }
2716
2753
  const FANOUT_THRESHOLD = 5;
2717
2754
  var ContextImpl = class ContextImpl {
2718
2755
  url;
package/dist/mod.cjs CHANGED
@@ -4,11 +4,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
4
  require("./chunk-DDcVe30Y.cjs");
5
5
  const require_transformers = require("./transformers-NeAONrAq.cjs");
6
6
  require("./compat/mod.cjs");
7
- const require_http = require("./http-Bj0uN6d-.cjs");
8
- const require_middleware = require("./middleware-Ccpokmfe.cjs");
9
- const require_proof = require("./proof-C2QsttUL.cjs");
7
+ const require_http = require("./http-e1wtIlFo.cjs");
8
+ const require_middleware = require("./middleware-DOLrvK_b.cjs");
9
+ const require_proof = require("./proof-BU1TpFYI.cjs");
10
10
  const require_types = require("./types-KC4QAoxe.cjs");
11
- const require_kv_cache = require("./kv-cache-BdSTsjLb.cjs");
11
+ const require_kv_cache = require("./kv-cache-B3GfB70S.cjs");
12
12
  const require_federation_mod = require("./federation/mod.cjs");
13
13
  require("./nodeinfo/mod.cjs");
14
14
  require("./runtime/mod.cjs");
package/dist/mod.js CHANGED
@@ -3,11 +3,11 @@ import "urlpattern-polyfill";
3
3
  import "./chunk-nlSIicah.js";
4
4
  import { n as autoIdAssigner, r as getDefaultActivityTransformers, t as actorDehydrator } from "./transformers-ve6e2xcg.js";
5
5
  import "./compat/mod.js";
6
- import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "./http-CA4xKsSY.js";
7
- import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "./middleware-0n0ctSu_.js";
8
- import { a as verifyProof, c as getKeyOwner, d as detachSignature, f as hasSignatureLike, h as verifySignature, i as verifyObject, l as attachSignature, m as verifyJsonLd, n as hasProofLike, p as signJsonLd, r as signObject, s as doesActorOwnKey, t as createProof, u as createSignature } from "./proof-Cdxbeq4n.js";
6
+ import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "./http-D2EDlTr2.js";
7
+ import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "./middleware-De241etq.js";
8
+ import { a as verifyProof, c as getKeyOwner, d as detachSignature, f as hasSignatureLike, h as verifySignature, i as verifyObject, l as attachSignature, m as verifyJsonLd, n as hasProofLike, p as signJsonLd, r as signObject, s as doesActorOwnKey, t as createProof, u as createSignature } from "./proof-DLDsFYfD.js";
9
9
  import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "./types-hvL8ElAs.js";
10
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DarvCOHt.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-KLjvIlKt.js";
11
11
  import { InProcessMessageQueue, MemoryKvStore, ParallelMessageQueue } from "./federation/mod.js";
12
12
  import "./nodeinfo/mod.js";
13
13
  import "./runtime/mod.js";
@@ -5,7 +5,7 @@ import { r as createRequestContext } from "../context-7Azky82W.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-CRDpx_HF.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-x2IvBUyq.mjs";
8
- import { _ as handleNodeInfoJrd, g as handleNodeInfo, o as createFederation } from "../middleware-THfK90u_.mjs";
8
+ import { _ as handleNodeInfoJrd, g as handleNodeInfo, o as createFederation } from "../middleware-DsGmXfXz.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  //#region src/nodeinfo/handler.test.ts
11
11
  test("handleNodeInfo()", async () => {
@@ -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-D9LpbVQR.mjs";
5
- import "./key-BPjHWwyv.mjs";
4
+ import { n as version, t as name } from "./deno-CFXqOz6w.mjs";
5
+ import "./key-CpAxygvh.mjs";
6
6
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
7
7
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-Bj0uN6d-.cjs");
4
+ const require_http = require("./http-e1wtIlFo.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let _fedify_vocab = require("@fedify/vocab");
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -1,8 +1,8 @@
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-D9LpbVQR.mjs";
5
- import { n as fetchKey, o as validateCryptoKey } from "./key-BPjHWwyv.mjs";
4
+ import { n as version, t as name } from "./deno-CFXqOz6w.mjs";
5
+ import { n as fetchKey, o as validateCryptoKey } from "./key-CpAxygvh.mjs";
6
6
  import { n as preloadedOnlyDocumentLoader } from "./public-audience-PVTwU_Ex.mjs";
7
7
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-Bi7n-dEy.mjs";
8
8
  import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { _ as version, d as validateCryptoKey, g as name, s as fetchKey } from "./http-CA4xKsSY.js";
3
+ import { _ as version, d as validateCryptoKey, g as name, s as fetchKey } from "./http-D2EDlTr2.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, PUBLIC_COLLECTION, getTypeId, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -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-D9LpbVQR.mjs";
5
- import { n as doubleKnock } from "./http-D6yvDhyL.mjs";
4
+ import { n as version, t as name } from "./deno-CFXqOz6w.mjs";
5
+ import { n as doubleKnock } from "./http-QHJGzUe8.mjs";
6
6
  import { SpanKind, SpanStatusCode, metrics, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  //#region src/federation/metrics.ts
@@ -12,6 +12,8 @@ var FederationMetrics = class {
12
12
  signatureVerificationFailure;
13
13
  deliveryDuration;
14
14
  inboxProcessingDuration;
15
+ httpServerRequestCount;
16
+ httpServerRequestDuration;
15
17
  constructor(meterProvider) {
16
18
  const meter = meterProvider.getMeter(name, version);
17
19
  this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
@@ -34,6 +36,30 @@ var FederationMetrics = class {
34
36
  description: "Duration of ActivityPub inbox listener processing.",
35
37
  unit: "ms"
36
38
  });
39
+ this.httpServerRequestCount = meter.createCounter("fedify.http.server.request.count", {
40
+ description: "HTTP requests handled by Federation.fetch().",
41
+ unit: "{request}"
42
+ });
43
+ this.httpServerRequestDuration = meter.createHistogram("fedify.http.server.request.duration", {
44
+ description: "Duration of HTTP requests handled by Federation.fetch().",
45
+ unit: "ms",
46
+ advice: { explicitBucketBoundaries: [
47
+ 5,
48
+ 10,
49
+ 25,
50
+ 50,
51
+ 75,
52
+ 100,
53
+ 250,
54
+ 500,
55
+ 750,
56
+ 1e3,
57
+ 2500,
58
+ 5e3,
59
+ 7500,
60
+ 1e4
61
+ ] }
62
+ });
37
63
  }
38
64
  recordDelivery(inbox, durationMs, success, activityType) {
39
65
  const deliveryAttributes = {
@@ -58,7 +84,33 @@ var FederationMetrics = class {
58
84
  recordInboxProcessingDuration(activityType, durationMs) {
59
85
  this.inboxProcessingDuration.record(durationMs, { "activitypub.activity.type": activityType });
60
86
  }
87
+ recordHttpServerRequest(method, endpoint, durationMs, options = {}) {
88
+ const attributes = {
89
+ "http.request.method": normalizeHttpMethod(method),
90
+ "fedify.endpoint": endpoint
91
+ };
92
+ if (options.statusCode != null) attributes["http.response.status_code"] = options.statusCode;
93
+ if (options.routeTemplate != null) attributes["fedify.route.template"] = options.routeTemplate;
94
+ this.httpServerRequestCount.add(1, attributes);
95
+ this.httpServerRequestDuration.record(durationMs, attributes);
96
+ }
61
97
  };
98
+ const KNOWN_HTTP_METHODS = new Set([
99
+ "CONNECT",
100
+ "DELETE",
101
+ "GET",
102
+ "HEAD",
103
+ "OPTIONS",
104
+ "PATCH",
105
+ "POST",
106
+ "PUT",
107
+ "QUERY",
108
+ "TRACE"
109
+ ]);
110
+ function normalizeHttpMethod(method) {
111
+ const upper = method.toUpperCase();
112
+ return KNOWN_HTTP_METHODS.has(upper) ? upper : "_OTHER";
113
+ }
62
114
  const federationMetrics = /* @__PURE__ */ new WeakMap();
63
115
  /**
64
116
  * Gets the cached Fedify metric instruments for a meter provider.
@@ -7,8 +7,8 @@ import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z
7
7
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
8
8
  import { t as assert } from "../assert-DikXweDx.mjs";
9
9
  import { t as esm_default } from "../esm-DhnRLoG9.mjs";
10
- import { t as exportJwk } from "../key-BPjHWwyv.mjs";
11
- import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase, u as verifyRequestDetailed } from "../http-D6yvDhyL.mjs";
10
+ import { t as exportJwk } from "../key-CpAxygvh.mjs";
11
+ import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase, u as verifyRequestDetailed } from "../http-QHJGzUe8.mjs";
12
12
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-C3kae-6B.mjs";
13
13
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { FetchError, exportSpki } from "@fedify/vocab-runtime";
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-CRDpx_HF.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
8
- import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-BPjHWwyv.mjs";
8
+ import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-CpAxygvh.mjs";
9
9
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-C3kae-6B.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";
@@ -5,9 +5,9 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
7
7
  import { t as assert } from "../assert-DikXweDx.mjs";
8
- import { i as generateCryptoKeyPair } from "../key-BPjHWwyv.mjs";
8
+ import { i as generateCryptoKeyPair } from "../key-CpAxygvh.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-C3kae-6B.mjs";
10
- import { a as signJsonLd, i as hasSignatureLike, n as createSignature, o as verifyJsonLd, r as detachSignature, s as verifySignature, t as attachSignature } from "../ld-D9yQwfkO.mjs";
10
+ import { a as signJsonLd, i as hasSignatureLike, n as createSignature, o as verifyJsonLd, r as detachSignature, s as verifySignature, t as attachSignature } from "../ld-Ce_vkKjG.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { CryptographicKey } from "@fedify/vocab";
13
13
  import { encodeBase64 } from "byte-encodings/base64";
package/dist/sig/mod.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const require_http = require("../http-Bj0uN6d-.cjs");
5
- const require_proof = require("../proof-C2QsttUL.cjs");
4
+ const require_http = require("../http-e1wtIlFo.cjs");
5
+ const require_proof = require("../proof-BU1TpFYI.cjs");
6
6
  exports.attachSignature = require_proof.attachSignature;
7
7
  exports.createProof = require_proof.createProof;
8
8
  exports.createSignature = require_proof.createSignature;
package/dist/sig/mod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "../http-CA4xKsSY.js";
4
- import { a as verifyProof, c as getKeyOwner, d as detachSignature, f as hasSignatureLike, h as verifySignature, i as verifyObject, l as attachSignature, m as verifyJsonLd, n as hasProofLike, p as signJsonLd, r as signObject, s as doesActorOwnKey, t as createProof, u as createSignature } from "../proof-Cdxbeq4n.js";
3
+ import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "../http-D2EDlTr2.js";
4
+ import { a as verifyProof, c as getKeyOwner, d as detachSignature, f as hasSignatureLike, h as verifySignature, i as verifyObject, l as attachSignature, m as verifyJsonLd, n as hasProofLike, p as signJsonLd, r as signObject, s as doesActorOwnKey, t as createProof, u as createSignature } from "../proof-DLDsFYfD.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
@@ -6,7 +6,7 @@ import "../std__assert-CRDpx_HF.mjs";
6
6
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assert } from "../assert-DikXweDx.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-C3kae-6B.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-CebIXUof.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-DmgzyItA.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
12
12
  //#region src/sig/owner.test.ts
@@ -8,7 +8,7 @@ import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
8
8
  import { t as assert } from "../assert-DikXweDx.mjs";
9
9
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-C3kae-6B.mjs";
10
10
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-Bi7n-dEy.mjs";
11
- import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-UXZOysVc.mjs";
11
+ import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-C3q2IhUr.mjs";
12
12
  import { mockDocumentLoader, test } from "@fedify/fixture";
13
13
  import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
14
14
  import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
@@ -5,9 +5,9 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-CRDpx_HF.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as esm_default } from "../esm-DhnRLoG9.mjs";
8
- import { l as verifyRequest } from "../http-D6yvDhyL.mjs";
8
+ import { l as verifyRequest } from "../http-QHJGzUe8.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-C3kae-6B.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-y2viZ2Tx.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-QNtAtTZF.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { UrlError } from "@fedify/vocab-runtime";
13
13
  //#region src/utils/docloader.test.ts
@@ -1,6 +1,6 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const require_kv_cache = require("../kv-cache-BdSTsjLb.cjs");
4
+ const require_kv_cache = require("../kv-cache-B3GfB70S.cjs");
5
5
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
6
6
  exports.kvCache = require_kv_cache.kvCache;
package/dist/utils/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-DarvCOHt.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-KLjvIlKt.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.3.0-dev.1048+2da74497",
3
+ "version": "2.3.0-dev.1069+81e910ce",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -153,9 +153,9 @@
153
153
  "uri-template-router": "^1.0.0",
154
154
  "url-template": "^3.1.1",
155
155
  "urlpattern-polyfill": "^10.1.0",
156
- "@fedify/webfinger": "2.3.0-dev.1048+2da74497",
157
- "@fedify/vocab-runtime": "2.3.0-dev.1048+2da74497",
158
- "@fedify/vocab": "2.3.0-dev.1048+2da74497"
156
+ "@fedify/vocab": "2.3.0-dev.1069+81e910ce",
157
+ "@fedify/vocab-runtime": "2.3.0-dev.1069+81e910ce",
158
+ "@fedify/webfinger": "2.3.0-dev.1069+81e910ce"
159
159
  },
160
160
  "devDependencies": {
161
161
  "@opentelemetry/sdk-metrics": "2.5.0",
@@ -169,7 +169,7 @@
169
169
  "typescript": "^5.9.2",
170
170
  "wrangler": "^4.17.0",
171
171
  "@fedify/fixture": "2.0.0",
172
- "@fedify/vocab-tools": "^2.3.0-dev.1048+2da74497"
172
+ "@fedify/vocab-tools": "^2.3.0-dev.1069+81e910ce"
173
173
  },
174
174
  "scripts": {
175
175
  "build:self": "tsdown",