@fedify/fedify 2.3.0-dev.1021 → 2.3.0-dev.1034

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 (95) hide show
  1. package/dist/{builder-Nn2r1dKd.mjs → builder-y06Dq5bp.mjs} +3 -3
  2. package/dist/chunk-QSgtlS85.mjs +29 -0
  3. package/dist/compat/mod.d.cts +1 -1
  4. package/dist/compat/mod.d.ts +1 -1
  5. package/dist/compat/outgoing-jsonld.test.mjs +1 -1
  6. package/dist/compat/public-audience.test.mjs +1 -1
  7. package/dist/compat/transformers.test.mjs +2 -2
  8. package/dist/{context-Dk_tacqz.mjs → context-7Azky82W.mjs} +3 -2
  9. package/dist/{context-Bxs4cdIZ.d.cts → context-BKLGj9QO.d.cts} +12 -1
  10. package/dist/{context-CVNXcFHR.d.ts → context-DrNqYkPw.d.ts} +12 -1
  11. package/dist/{deno-BnQyJ03o.mjs → deno-DB1H1VHx.mjs} +1 -1
  12. package/dist/{docloader-mEJ3hsMB.mjs → docloader-3HwiWeYL.mjs} +2 -2
  13. package/dist/{esm-DVILvP5e.mjs → esm-DhnRLoG9.mjs} +1 -24
  14. package/dist/execAsync-eck5rbtb.mjs +13 -0
  15. package/dist/federation/builder.test.mjs +2 -2
  16. package/dist/federation/collection.test.mjs +1 -1
  17. package/dist/federation/handler.test.mjs +48 -11
  18. package/dist/federation/idempotency.test.mjs +4 -4
  19. package/dist/federation/inbox.test.mjs +1 -1
  20. package/dist/federation/keycache.test.mjs +2 -2
  21. package/dist/federation/kv.test.mjs +1 -1
  22. package/dist/federation/middleware.test.mjs +103 -12
  23. package/dist/federation/mod.cjs +1 -1
  24. package/dist/federation/mod.d.cts +2 -2
  25. package/dist/federation/mod.d.ts +2 -2
  26. package/dist/federation/mod.js +1 -1
  27. package/dist/federation/negotiation.test.mjs +1 -1
  28. package/dist/federation/retry.test.mjs +1 -1
  29. package/dist/federation/send.test.mjs +4540 -11
  30. package/dist/federation/webfinger.test.mjs +3 -3
  31. package/dist/getMachineId-bsd-DqZ4QRFp.mjs +29 -0
  32. package/dist/getMachineId-darwin-DMbbW3m7.mjs +26 -0
  33. package/dist/getMachineId-linux-lyeD2ug3.mjs +22 -0
  34. package/dist/getMachineId-unsupported-JuKr57jY.mjs +17 -0
  35. package/dist/getMachineId-win-Dxyf5pJq.mjs +28 -0
  36. package/dist/{http-BJ-t29n_.js → http-BUr93aO6.js} +1 -1
  37. package/dist/{http-CfToB_iu.mjs → http-D9zG-L9N.mjs} +3 -3
  38. package/dist/{http-D4xMqSqO.cjs → http-FnUTcdMf.cjs} +1 -1
  39. package/dist/{key-CeANlo1H.mjs → key-CV57mOYH.mjs} +1 -1
  40. package/dist/{kv-cache-DRwOjOkl.cjs → kv-cache-BG9O8wVV.cjs} +1 -1
  41. package/dist/{kv-cache-B142kDZL.js → kv-cache-C3esyJFP.js} +1 -1
  42. package/dist/{ld-CUlVC-TS.mjs → ld-sUf94RJ8.mjs} +2 -2
  43. package/dist/{middleware-I5XEZ_pZ.cjs → middleware-CKkBrsOD.cjs} +185 -27
  44. package/dist/{middleware-Cgy7UwfR.mjs → middleware-cMxbPxDe.mjs} +1 -1
  45. package/dist/{middleware-CysDkaXo.js → middleware-fAuUxD9-.js} +185 -27
  46. package/dist/{middleware-ASvK22Do.cjs → middleware-ohzkLsW4.cjs} +1 -1
  47. package/dist/{middleware-BPZEcrMG.mjs → middleware-pb2EqN_r.mjs} +67 -22
  48. package/dist/{mod-Bc6p4npy.d.ts → mod-B8Z8mBLk.d.ts} +1 -1
  49. package/dist/{mod-zA6NZHUG.d.cts → mod-DClCOv0M.d.cts} +1 -1
  50. package/dist/mod.cjs +4 -4
  51. package/dist/mod.d.cts +2 -2
  52. package/dist/mod.d.ts +2 -2
  53. package/dist/mod.js +4 -4
  54. package/dist/nodeinfo/client.test.mjs +2 -2
  55. package/dist/nodeinfo/handler.test.mjs +3 -3
  56. package/dist/nodeinfo/types.test.mjs +1 -1
  57. package/dist/otel/exporter.test.mjs +25 -22
  58. package/dist/otel/mod.cjs +6 -5
  59. package/dist/otel/mod.d.cts +3 -2
  60. package/dist/otel/mod.d.ts +3 -2
  61. package/dist/otel/mod.js +6 -5
  62. package/dist/{outgoing-jsonld-CNmZLixq.mjs → outgoing-jsonld-Bi7n-dEy.mjs} +1 -1
  63. package/dist/{owner-CuW0S2XY.mjs → owner-DsPgl527.mjs} +2 -2
  64. package/dist/{proof-oGiWJkX0.cjs → proof-BhJpq_J9.cjs} +1 -1
  65. package/dist/{proof-CFPGr1xC.mjs → proof-iVfYyJpY.mjs} +4 -4
  66. package/dist/{proof-CtMmqa09.js → proof-k4mEvvdS.js} +1 -1
  67. package/dist/send-D-vYdfC6.mjs +306 -0
  68. package/dist/sig/accept.test.mjs +1 -1
  69. package/dist/sig/http.test.mjs +4 -4
  70. package/dist/sig/key.test.mjs +2 -2
  71. package/dist/sig/ld.test.mjs +3 -3
  72. package/dist/sig/mod.cjs +2 -2
  73. package/dist/sig/mod.js +2 -2
  74. package/dist/sig/owner.test.mjs +2 -2
  75. package/dist/sig/proof.test.mjs +3 -3
  76. package/dist/testing/mod.d.mts +6 -1
  77. package/dist/testing/mod.mjs +1 -1
  78. package/dist/utils/docloader.test.mjs +4 -4
  79. package/dist/utils/kv-cache.test.mjs +1 -1
  80. package/dist/utils/mod.cjs +1 -1
  81. package/dist/utils/mod.js +1 -1
  82. package/package.json +7 -6
  83. package/dist/send-dhl-s8G0.mjs +0 -193
  84. /package/dist/{accept-CPkZzmGN.mjs → accept-CceiKpCy.mjs} +0 -0
  85. /package/dist/{activity-listener-ell7W1s9.mjs → activity-listener-tztVvlNb.mjs} +0 -0
  86. /package/dist/{client-D_1QpnWt.mjs → client-CIiz1WX7.mjs} +0 -0
  87. /package/dist/{collection-D-HqUuA2.mjs → collection-CA3V5zyK.mjs} +0 -0
  88. /package/dist/{keycache-EGATflN-.mjs → keycache-BeU0LCII.mjs} +0 -0
  89. /package/dist/{keys-DGu1NFwu.mjs → keys-C3kae-6B.mjs} +0 -0
  90. /package/dist/{kv-cache-U__xU4qR.mjs → kv-cache-Bmv7tUzz.mjs} +0 -0
  91. /package/dist/{kv-rV3vodCc.mjs → kv-x2IvBUyq.mjs} +0 -0
  92. /package/dist/{negotiation-SQvQgUqe.mjs → negotiation-VnHNB0Q5.mjs} +0 -0
  93. /package/dist/{public-audience-DYFHzm_c.mjs → public-audience-PVTwU_Ex.mjs} +0 -0
  94. /package/dist/{retry-bMXBL97A.mjs → retry-_VvV0h9f.mjs} +0 -0
  95. /package/dist/{types-J53Kw7so.mjs → types-BFowWFTT.mjs} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { r as createRequestContext } from "../context-Dk_tacqz.mjs";
4
+ 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
- import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
8
- import { o as createFederation, s as handleWebFinger } from "../middleware-BPZEcrMG.mjs";
7
+ import { t as MemoryKvStore } from "../kv-x2IvBUyq.mjs";
8
+ import { o as createFederation, s as handleWebFinger } from "../middleware-pb2EqN_r.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Image, Link, Person, Tombstone } from "@fedify/vocab";
11
11
  //#region src/federation/webfinger.test.ts
@@ -0,0 +1,29 @@
1
+ import "@js-temporal/polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as __require, t as __commonJSMin } from "./chunk-QSgtlS85.mjs";
5
+ import { t as require_execAsync } from "./execAsync-eck5rbtb.mjs";
6
+ //#region ../../node_modules/.pnpm/@opentelemetry+resources@2.5.0_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-bsd.js
7
+ var require_getMachineId_bsd = /* @__PURE__ */ __commonJSMin(((exports) => {
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getMachineId = void 0;
10
+ const fs_1 = __require("fs");
11
+ const execAsync_1 = require_execAsync();
12
+ const api_1 = __require("@opentelemetry/api");
13
+ async function getMachineId() {
14
+ try {
15
+ return (await fs_1.promises.readFile("/etc/hostid", { encoding: "utf8" })).trim();
16
+ } catch (e) {
17
+ api_1.diag.debug(`error reading machine id: ${e}`);
18
+ }
19
+ try {
20
+ return (await (0, execAsync_1.execAsync)("kenv -q smbios.system.uuid")).stdout.trim();
21
+ } catch (e) {
22
+ api_1.diag.debug(`error reading machine id: ${e}`);
23
+ }
24
+ }
25
+ exports.getMachineId = getMachineId;
26
+ }));
27
+ //#endregion
28
+ export default require_getMachineId_bsd();
29
+ export {};
@@ -0,0 +1,26 @@
1
+ import "@js-temporal/polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as __require, t as __commonJSMin } from "./chunk-QSgtlS85.mjs";
5
+ import { t as require_execAsync } from "./execAsync-eck5rbtb.mjs";
6
+ //#region ../../node_modules/.pnpm/@opentelemetry+resources@2.5.0_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-darwin.js
7
+ var require_getMachineId_darwin = /* @__PURE__ */ __commonJSMin(((exports) => {
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getMachineId = void 0;
10
+ const execAsync_1 = require_execAsync();
11
+ const api_1 = __require("@opentelemetry/api");
12
+ async function getMachineId() {
13
+ try {
14
+ const idLine = (await (0, execAsync_1.execAsync)("ioreg -rd1 -c \"IOPlatformExpertDevice\"")).stdout.split("\n").find((line) => line.includes("IOPlatformUUID"));
15
+ if (!idLine) return;
16
+ const parts = idLine.split("\" = \"");
17
+ if (parts.length === 2) return parts[1].slice(0, -1);
18
+ } catch (e) {
19
+ api_1.diag.debug(`error reading machine id: ${e}`);
20
+ }
21
+ }
22
+ exports.getMachineId = getMachineId;
23
+ }));
24
+ //#endregion
25
+ export default require_getMachineId_darwin();
26
+ export {};
@@ -0,0 +1,22 @@
1
+ import "@js-temporal/polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as __require, t as __commonJSMin } from "./chunk-QSgtlS85.mjs";
5
+ //#region ../../node_modules/.pnpm/@opentelemetry+resources@2.5.0_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-linux.js
6
+ var require_getMachineId_linux = /* @__PURE__ */ __commonJSMin(((exports) => {
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getMachineId = void 0;
9
+ const fs_1 = __require("fs");
10
+ const api_1 = __require("@opentelemetry/api");
11
+ async function getMachineId() {
12
+ for (const path of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) try {
13
+ return (await fs_1.promises.readFile(path, { encoding: "utf8" })).trim();
14
+ } catch (e) {
15
+ api_1.diag.debug(`error reading machine id: ${e}`);
16
+ }
17
+ }
18
+ exports.getMachineId = getMachineId;
19
+ }));
20
+ //#endregion
21
+ export default require_getMachineId_linux();
22
+ export {};
@@ -0,0 +1,17 @@
1
+ import "@js-temporal/polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as __require, t as __commonJSMin } from "./chunk-QSgtlS85.mjs";
5
+ //#region ../../node_modules/.pnpm/@opentelemetry+resources@2.5.0_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-unsupported.js
6
+ var require_getMachineId_unsupported = /* @__PURE__ */ __commonJSMin(((exports) => {
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getMachineId = void 0;
9
+ const api_1 = __require("@opentelemetry/api");
10
+ async function getMachineId() {
11
+ api_1.diag.debug("could not read machine-id: unsupported platform");
12
+ }
13
+ exports.getMachineId = getMachineId;
14
+ }));
15
+ //#endregion
16
+ export default require_getMachineId_unsupported();
17
+ export {};
@@ -0,0 +1,28 @@
1
+ import "@js-temporal/polyfill";
2
+ import "urlpattern-polyfill";
3
+ globalThis.addEventListener = () => {};
4
+ import { n as __require, t as __commonJSMin } from "./chunk-QSgtlS85.mjs";
5
+ import { t as require_execAsync } from "./execAsync-eck5rbtb.mjs";
6
+ //#region ../../node_modules/.pnpm/@opentelemetry+resources@2.5.0_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/resources/build/src/detectors/platform/node/machine-id/getMachineId-win.js
7
+ var require_getMachineId_win = /* @__PURE__ */ __commonJSMin(((exports) => {
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getMachineId = void 0;
10
+ const process = __require("process");
11
+ const execAsync_1 = require_execAsync();
12
+ const api_1 = __require("@opentelemetry/api");
13
+ async function getMachineId() {
14
+ const args = "QUERY HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid";
15
+ let command = "%windir%\\System32\\REG.exe";
16
+ if (process.arch === "ia32" && "PROCESSOR_ARCHITEW6432" in process.env) command = "%windir%\\sysnative\\cmd.exe /c " + command;
17
+ try {
18
+ const parts = (await (0, execAsync_1.execAsync)(`${command} ${args}`)).stdout.split("REG_SZ");
19
+ if (parts.length === 2) return parts[1].trim();
20
+ } catch (e) {
21
+ api_1.diag.debug(`error reading machine id: ${e}`);
22
+ }
23
+ }
24
+ exports.getMachineId = getMachineId;
25
+ }));
26
+ //#endregion
27
+ export default require_getMachineId_win();
28
+ export {};
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
10
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.3.0-dev.1021+ab2fa4a9";
13
+ var version = "2.3.0-dev.1034+b85b5daa";
14
14
  //#endregion
15
15
  //#region src/sig/accept.ts
16
16
  /**
@@ -1,9 +1,9 @@
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-BnQyJ03o.mjs";
5
- import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPkZzmGN.mjs";
6
- import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-CeANlo1H.mjs";
4
+ import { n as version, t as name } from "./deno-DB1H1VHx.mjs";
5
+ import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CceiKpCy.mjs";
6
+ import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-CV57mOYH.mjs";
7
7
  import { CryptographicKey } from "@fedify/vocab";
8
8
  import { SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { FetchError } from "@fedify/vocab-runtime";
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
11
11
  let byte_encodings_base64 = require("byte-encodings/base64");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.3.0-dev.1021+ab2fa4a9";
14
+ var version = "2.3.0-dev.1034+b85b5daa";
15
15
  //#endregion
16
16
  //#region src/sig/accept.ts
17
17
  /**
@@ -1,7 +1,7 @@
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-BnQyJ03o.mjs";
4
+ import { n as version, t as name } from "./deno-DB1H1VHx.mjs";
5
5
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { FetchError, 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
  require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-D4xMqSqO.cjs");
4
+ const require_http = require("./http-FnUTcdMf.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { d as validateCryptoKey, t as doubleKnock } from "./http-BJ-t29n_.js";
3
+ import { d as validateCryptoKey, t as doubleKnock } from "./http-BUr93aO6.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BnQyJ03o.mjs";
5
- import { n as fetchKey, o as validateCryptoKey } from "./key-CeANlo1H.mjs";
4
+ import { n as version, t as name } from "./deno-DB1H1VHx.mjs";
5
+ import { n as fetchKey, o as validateCryptoKey } from "./key-CV57mOYH.mjs";
6
6
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
4
  const require_transformers = require("./transformers-NeAONrAq.cjs");
5
- const require_http = require("./http-D4xMqSqO.cjs");
6
- const require_proof = require("./proof-oGiWJkX0.cjs");
5
+ const require_http = require("./http-FnUTcdMf.cjs");
6
+ const require_proof = require("./proof-BhJpq_J9.cjs");
7
7
  const require_types = require("./types-KC4QAoxe.cjs");
8
- const require_kv_cache = require("./kv-cache-DRwOjOkl.cjs");
8
+ const require_kv_cache = require("./kv-cache-BG9O8wVV.cjs");
9
9
  let _logtape_logtape = require("@logtape/logtape");
10
10
  let _fedify_vocab = require("@fedify/vocab");
11
11
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -211,7 +211,7 @@ var FederationBuilderImpl = class {
211
211
  this.collectionTypeIds = {};
212
212
  }
213
213
  async build(options) {
214
- const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-ASvK22Do.cjs"));
214
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-ohzkLsW4.cjs"));
215
215
  const f = new FederationImpl(options);
216
216
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
217
217
  f.router = this.router.clone();
@@ -779,8 +779,90 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
779
779
  return `collectionId="${collectionId}", url="${url}", digest="${(0, byte_encodings_hex.encodeHex)(await digest(actorIds))}"`;
780
780
  }
781
781
  //#endregion
782
+ //#region src/federation/metrics.ts
783
+ var FederationMetrics = class {
784
+ deliverySent;
785
+ deliveryPermanentFailure;
786
+ signatureVerificationFailure;
787
+ deliveryDuration;
788
+ inboxProcessingDuration;
789
+ constructor(meterProvider) {
790
+ const meter = meterProvider.getMeter(require_http.name, require_http.version);
791
+ this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
792
+ description: "ActivityPub delivery attempts.",
793
+ unit: "{attempt}"
794
+ });
795
+ this.deliveryPermanentFailure = meter.createCounter("activitypub.delivery.permanent_failure", {
796
+ description: "ActivityPub deliveries abandoned as permanent failures.",
797
+ unit: "{failure}"
798
+ });
799
+ this.signatureVerificationFailure = meter.createCounter("activitypub.signature.verification_failure", {
800
+ description: "ActivityPub signature verification failures.",
801
+ unit: "{failure}"
802
+ });
803
+ this.deliveryDuration = meter.createHistogram("activitypub.delivery.duration", {
804
+ description: "Duration of ActivityPub delivery attempts.",
805
+ unit: "ms"
806
+ });
807
+ this.inboxProcessingDuration = meter.createHistogram("activitypub.inbox.processing_duration", {
808
+ description: "Duration of ActivityPub inbox listener processing.",
809
+ unit: "ms"
810
+ });
811
+ }
812
+ recordDelivery(inbox, durationMs, success, activityType) {
813
+ const deliveryAttributes = {
814
+ "activitypub.remote.host": getRemoteHost(inbox),
815
+ "activitypub.delivery.success": success
816
+ };
817
+ if (activityType != null) deliveryAttributes["activitypub.activity.type"] = activityType;
818
+ this.deliverySent.add(1, deliveryAttributes);
819
+ this.deliveryDuration.record(durationMs, deliveryAttributes);
820
+ }
821
+ recordPermanentFailure(inbox, statusCode) {
822
+ this.deliveryPermanentFailure.add(1, {
823
+ "activitypub.remote.host": getRemoteHost(inbox),
824
+ "http.response.status_code": statusCode
825
+ });
826
+ }
827
+ recordSignatureVerificationFailure(reason, remoteHost) {
828
+ const attributes = { "activitypub.verification.failure_reason": reason };
829
+ if (remoteHost != null) attributes["activitypub.remote.host"] = remoteHost;
830
+ this.signatureVerificationFailure.add(1, attributes);
831
+ }
832
+ recordInboxProcessingDuration(activityType, durationMs) {
833
+ this.inboxProcessingDuration.record(durationMs, { "activitypub.activity.type": activityType });
834
+ }
835
+ };
836
+ const federationMetrics = /* @__PURE__ */ new WeakMap();
837
+ /**
838
+ * Gets the cached Fedify metric instruments for a meter provider.
839
+ * @since 2.3.0
840
+ */
841
+ function getFederationMetrics(meterProvider = _opentelemetry_api.metrics.getMeterProvider()) {
842
+ let instruments = federationMetrics.get(meterProvider);
843
+ if (instruments == null) {
844
+ instruments = new FederationMetrics(meterProvider);
845
+ federationMetrics.set(meterProvider, instruments);
846
+ }
847
+ return instruments;
848
+ }
849
+ /**
850
+ * Gets the bounded remote host attribute value for a URL.
851
+ * @since 2.3.0
852
+ */
853
+ function getRemoteHost(url) {
854
+ return url.hostname;
855
+ }
856
+ /**
857
+ * Gets an elapsed duration in milliseconds from a `performance.now()` value.
858
+ * @since 2.3.0
859
+ */
860
+ function getDurationMs(start) {
861
+ return Math.max(0, performance.now() - start);
862
+ }
863
+ //#endregion
782
864
  //#region src/federation/inbox.ts
783
- async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
865
+ async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
784
866
  const logger = (0, _logtape_logtape.getLogger)([
785
867
  "fedify",
786
868
  "federation",
@@ -881,7 +963,13 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
881
963
  const { class: cls, listener } = dispatched;
882
964
  span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
883
965
  try {
884
- await listener(inboxContextFactory(recipient, json, activity?.id?.href, (0, _fedify_vocab.getTypeId)(activity).href), activity);
966
+ const activityType = (0, _fedify_vocab.getTypeId)(activity).href;
967
+ const started = performance.now();
968
+ try {
969
+ await listener(inboxContextFactory(recipient, json, activity?.id?.href, activityType), activity);
970
+ } finally {
971
+ getFederationMetrics(meterProvider).recordInboxProcessingDuration(activityType, getDurationMs(started));
972
+ }
885
973
  } catch (error) {
886
974
  try {
887
975
  await inboxErrorHandler?.(ctx, error);
@@ -1691,6 +1779,8 @@ async function handleInboxInternal(request, parameters, span) {
1691
1779
  });
1692
1780
  if (verification.verified === false) {
1693
1781
  const reason = verification.reason;
1782
+ const remoteHost = "keyId" in reason && reason.keyId != null ? getRemoteHost(reason.keyId) : void 0;
1783
+ getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure(reason.type, remoteHost);
1694
1784
  logger.error("Failed to verify the request's HTTP Signatures.", {
1695
1785
  recipient,
1696
1786
  reason: reason.type,
@@ -1777,6 +1867,7 @@ async function handleInboxInternal(request, parameters, span) {
1777
1867
  "http_signatures.key_id": httpSigKey?.id?.href ?? ""
1778
1868
  });
1779
1869
  if (httpSigKey != null && !await require_proof.doesActorOwnKey(activity, httpSigKey, ctx)) {
1870
+ getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("actorKeyMismatch", httpSigKey.id == null ? void 0 : getRemoteHost(httpSigKey.id));
1780
1871
  logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
1781
1872
  activity: json,
1782
1873
  recipient,
@@ -1794,6 +1885,7 @@ async function handleInboxInternal(request, parameters, span) {
1794
1885
  }
1795
1886
  if (pendingNonceLabel != null) {
1796
1887
  if (!await verifySignatureNonce(request, kv, kvPrefixes.acceptSignatureNonce, pendingNonceLabel)) {
1888
+ getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("invalidNonce", httpSigKey?.id == null ? void 0 : getRemoteHost(httpSigKey.id));
1797
1889
  logger.error("Signature nonce verification failed (missing, expired, or replayed).", { recipient });
1798
1890
  return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
1799
1891
  }
@@ -1810,6 +1902,7 @@ async function handleInboxInternal(request, parameters, span) {
1810
1902
  kvPrefixes,
1811
1903
  queue,
1812
1904
  span,
1905
+ meterProvider: parameters.meterProvider,
1813
1906
  tracerProvider,
1814
1907
  idempotencyStrategy: parameters.idempotencyStrategy
1815
1908
  });
@@ -2457,6 +2550,25 @@ function sendActivity(options) {
2457
2550
  });
2458
2551
  }
2459
2552
  const MAX_ERROR_RESPONSE_BODY_BYTES = 1024;
2553
+ function getActivityActorId(activity) {
2554
+ if (!isRecord(activity)) return void 0;
2555
+ return getIdValue(activity.actor);
2556
+ }
2557
+ function getIdValue(value) {
2558
+ if (typeof value === "string" && value !== "") return value;
2559
+ if (value instanceof URL) return value.href;
2560
+ if (Array.isArray(value)) {
2561
+ for (const item of value) {
2562
+ const id = getIdValue(item);
2563
+ if (id != null) return id;
2564
+ }
2565
+ return;
2566
+ }
2567
+ if (isRecord(value)) return getIdValue(value.id);
2568
+ }
2569
+ function isRecord(value) {
2570
+ return typeof value === "object" && value != null;
2571
+ }
2460
2572
  async function readLimitedResponseBody(response, maxBytes) {
2461
2573
  if (response.body == null) return "";
2462
2574
  const reader = response.body.getReader();
@@ -2484,12 +2596,15 @@ async function readLimitedResponseBody(response, maxBytes) {
2484
2596
  if (truncated) result += "… (truncated)";
2485
2597
  return result;
2486
2598
  }
2487
- async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }, span) {
2599
+ async function sendActivityInternal({ activity, activityId, activityType, keys, inbox, headers, specDeterminer, meterProvider, tracerProvider }, span) {
2488
2600
  const logger = (0, _logtape_logtape.getLogger)([
2489
2601
  "fedify",
2490
2602
  "federation",
2491
2603
  "outbox"
2492
2604
  ]);
2605
+ const federationMetrics = getFederationMetrics(meterProvider);
2606
+ const started = performance.now();
2607
+ let deliverySuccess = false;
2493
2608
  headers = new Headers(headers);
2494
2609
  headers.set("Content-Type", "application/activity+json");
2495
2610
  const request = new Request(inbox, {
@@ -2521,29 +2636,38 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2521
2636
  inbox: inbox.href,
2522
2637
  error
2523
2638
  });
2639
+ federationMetrics.recordDelivery(inbox, getDurationMs(started), false, activityType);
2524
2640
  throw error;
2525
2641
  }
2526
- if (!response.ok) {
2527
- let error;
2528
- try {
2529
- error = await readLimitedResponseBody(response, MAX_ERROR_RESPONSE_BODY_BYTES);
2530
- } catch (_) {
2531
- error = "";
2642
+ try {
2643
+ if (!response.ok) {
2644
+ let error;
2645
+ try {
2646
+ error = await readLimitedResponseBody(response, MAX_ERROR_RESPONSE_BODY_BYTES);
2647
+ } catch (_) {
2648
+ error = "";
2649
+ }
2650
+ logger.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
2651
+ activityId,
2652
+ inbox: inbox.href,
2653
+ status: response.status,
2654
+ statusText: response.statusText,
2655
+ error
2656
+ });
2657
+ throw new SendActivityError(inbox, response.status, `Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`, error);
2532
2658
  }
2533
- logger.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
2534
- activityId,
2535
- inbox: inbox.href,
2536
- status: response.status,
2537
- statusText: response.statusText,
2538
- error
2539
- });
2540
- throw new SendActivityError(inbox, response.status, `Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`, error);
2659
+ deliverySuccess = true;
2660
+ const eventAttributes = {
2661
+ "activitypub.inbox.url": inbox.href,
2662
+ "activitypub.activity.id": activityId ?? ""
2663
+ };
2664
+ if (activityType != null) eventAttributes["activitypub.activity.type"] = activityType;
2665
+ const actorId = getActivityActorId(activity);
2666
+ if (actorId != null) eventAttributes["activitypub.actor.id"] = actorId;
2667
+ span.addEvent("activitypub.activity.sent", eventAttributes);
2668
+ } finally {
2669
+ federationMetrics.recordDelivery(inbox, getDurationMs(started), deliverySuccess, activityType);
2541
2670
  }
2542
- span.addEvent("activitypub.activity.sent", {
2543
- "activitypub.activity.json": JSON.stringify(activity),
2544
- "activitypub.inbox.url": inbox.href,
2545
- "activitypub.activity.id": activityId ?? ""
2546
- });
2547
2671
  }
2548
2672
  /**
2549
2673
  * An error that is thrown when an activity fails to send to a remote inbox.
@@ -2753,6 +2877,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2753
2877
  inboxRetryPolicy;
2754
2878
  activityTransformers;
2755
2879
  _tracerProvider;
2880
+ _meterProvider;
2756
2881
  firstKnock;
2757
2882
  inboxChallengePolicy;
2758
2883
  constructor(options) {
@@ -2838,11 +2963,15 @@ var FederationImpl = class extends FederationBuilderImpl {
2838
2963
  this.inboxRetryPolicy = options.inboxRetryPolicy ?? createExponentialBackoffPolicy();
2839
2964
  this.activityTransformers = options.activityTransformers ?? require_transformers.getDefaultActivityTransformers();
2840
2965
  this._tracerProvider = options.tracerProvider;
2966
+ this._meterProvider = options.meterProvider;
2841
2967
  this.firstKnock = options.firstKnock;
2842
2968
  }
2843
2969
  get tracerProvider() {
2844
2970
  return this._tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
2845
2971
  }
2972
+ get meterProvider() {
2973
+ return this._meterProvider ?? _opentelemetry_api.metrics.getMeterProvider();
2974
+ }
2846
2975
  _initializeRouter() {
2847
2976
  this.router.add("/.well-known/webfinger", "webfinger");
2848
2977
  this.router.add("/.well-known/nodeinfo", "nodeInfoJrd");
@@ -3021,6 +3150,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3021
3150
  sharedInbox: message.sharedInbox,
3022
3151
  headers: new Headers(message.headers),
3023
3152
  specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
3153
+ meterProvider: this.meterProvider,
3024
3154
  tracerProvider: this.tracerProvider
3025
3155
  });
3026
3156
  } catch (error) {
@@ -3028,6 +3158,21 @@ var FederationImpl = class extends FederationBuilderImpl {
3028
3158
  code: _opentelemetry_api.SpanStatusCode.ERROR,
3029
3159
  message: String(error)
3030
3160
  });
3161
+ const remoteHost = (() => {
3162
+ if (error instanceof SendActivityError) return getRemoteHost(error.inbox);
3163
+ try {
3164
+ return getRemoteHost(new URL(message.inbox));
3165
+ } catch (_) {
3166
+ logger.warn("Invalid inbox URL in queued outbox message: {inbox}", logData);
3167
+ return;
3168
+ }
3169
+ })();
3170
+ span.addEvent("activitypub.delivery.failed", {
3171
+ ...remoteHost == null ? {} : { "activitypub.remote.host": remoteHost },
3172
+ "activitypub.delivery.attempt": message.attempt,
3173
+ "activitypub.delivery.permanent_failure": error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode),
3174
+ ...error instanceof SendActivityError ? { "http.response.status_code": error.statusCode } : {}
3175
+ });
3031
3176
  const loaderOptions = this.#getLoaderOptions(message.baseUrl);
3032
3177
  const activity = await _fedify_vocab.Activity.fromJsonLd(message.activity, {
3033
3178
  contextLoader: this.contextLoaderFactory(loaderOptions),
@@ -3043,6 +3188,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3043
3188
  });
3044
3189
  }
3045
3190
  if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
3191
+ getFederationMetrics(this.meterProvider).recordPermanentFailure(error.inbox, error.statusCode);
3046
3192
  logger.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
3047
3193
  ...logData,
3048
3194
  status: error.statusCode
@@ -3151,7 +3297,13 @@ var FederationImpl = class extends FederationBuilderImpl {
3151
3297
  const { class: cls, listener } = dispatched;
3152
3298
  span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
3153
3299
  try {
3154
- await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, (0, _fedify_vocab.getTypeId)(activity).href), activity);
3300
+ const activityType = (0, _fedify_vocab.getTypeId)(activity).href;
3301
+ const started = performance.now();
3302
+ try {
3303
+ await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
3304
+ } finally {
3305
+ getFederationMetrics(this.meterProvider).recordInboxProcessingDuration(activityType, getDurationMs(started));
3306
+ }
3155
3307
  } catch (error) {
3156
3308
  try {
3157
3309
  await this.inboxErrorHandler?.(context, error);
@@ -3334,6 +3486,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3334
3486
  sharedInbox: inboxes[inbox].sharedInbox,
3335
3487
  headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
3336
3488
  specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
3489
+ meterProvider: this.meterProvider,
3337
3490
  tracerProvider: this.tracerProvider
3338
3491
  }));
3339
3492
  await Promise.all(promises);
@@ -3603,6 +3756,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3603
3756
  signatureTimeWindow: this.signatureTimeWindow,
3604
3757
  skipSignatureVerification: this.skipSignatureVerification,
3605
3758
  inboxChallengePolicy: this.inboxChallengePolicy,
3759
+ meterProvider: this.meterProvider,
3606
3760
  tracerProvider: this.tracerProvider,
3607
3761
  idempotencyStrategy: this.idempotencyStrategy
3608
3762
  });
@@ -3764,6 +3918,9 @@ var ContextImpl = class ContextImpl {
3764
3918
  get tracerProvider() {
3765
3919
  return this.federation.tracerProvider;
3766
3920
  }
3921
+ get meterProvider() {
3922
+ return this.federation.meterProvider;
3923
+ }
3767
3924
  getNodeInfoUri() {
3768
3925
  const path = this.federation.router.build("nodeInfo", {});
3769
3926
  if (path == null) throw new RouterError("No NodeInfo dispatcher registered.");
@@ -4513,6 +4670,7 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
4513
4670
  activityType: ctx.activityType,
4514
4671
  inbox: new URL(inbox),
4515
4672
  sharedInbox: inboxes[inbox].sharedInbox,
4673
+ meterProvider: ctx.meterProvider,
4516
4674
  tracerProvider: ctx.tracerProvider,
4517
4675
  specDeterminer: new KvSpecDeterminer(ctx.federation.kv, ctx.federation.kvPrefixes.httpMessageSignaturesSpec, ctx.federation.firstKnock)
4518
4676
  }));
@@ -1,5 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as FederationImpl } from "./middleware-BPZEcrMG.mjs";
4
+ import { n as FederationImpl } from "./middleware-pb2EqN_r.mjs";
5
5
  export { FederationImpl };