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

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 (113) hide show
  1. package/dist/{builder-DQ2zYTeA.mjs → builder-BkRRjxzb.mjs} +4 -4
  2. package/dist/{chunk-nlSIicah.js → chunk-CRNNMoPX.js} +2 -2
  3. package/dist/{chunk-QSgtlS85.mjs → chunk-DNRtMIoB.mjs} +1 -1
  4. package/dist/{client-z-8dc-e1.d.cts → client-CAM_bQXx.d.cts} +1 -0
  5. package/dist/{client-AtlibPOU.d.ts → client-CSddvgWN.d.ts} +1 -2
  6. package/dist/compat/mod.d.cts +2 -1
  7. package/dist/compat/mod.d.ts +2 -3
  8. package/dist/compat/mod.js +3 -3
  9. package/dist/compat/outgoing-jsonld.test.mjs +2 -2
  10. package/dist/compat/public-audience.test.mjs +2 -2
  11. package/dist/compat/transformers.test.mjs +2 -2
  12. package/dist/{context-7Azky82W.mjs → context-BAE7AKLA.mjs} +61 -3
  13. package/dist/{context-DrNqYkPw.d.ts → context-C0C_sRha.d.cts} +6 -7
  14. package/dist/{context-BKLGj9QO.d.cts → context-Dqgt8saU.d.ts} +6 -5
  15. package/dist/{deno-CFXqOz6w.mjs → deno-DBabeupC.mjs} +1 -1
  16. package/dist/{docloader-QNtAtTZF.mjs → docloader-DA5FzJOR.mjs} +3 -3
  17. package/dist/{esm-DhnRLoG9.mjs → esm-sdtqOUPu.mjs} +5 -7
  18. package/dist/{execAsync-eck5rbtb.mjs → execAsync-DCBrgFiV.mjs} +2 -2
  19. package/dist/federation/builder.test.mjs +3 -3
  20. package/dist/federation/handler.test.mjs +86 -4
  21. package/dist/federation/idempotency.test.mjs +3 -3
  22. package/dist/federation/inbox.test.mjs +1 -1
  23. package/dist/federation/keycache.test.mjs +1 -1
  24. package/dist/federation/middleware.test.mjs +387 -20
  25. package/dist/federation/mod.cjs +1 -1
  26. package/dist/federation/mod.d.cts +4 -3
  27. package/dist/federation/mod.d.ts +4 -5
  28. package/dist/federation/mod.js +2 -2
  29. package/dist/federation/mq.test.mjs +1 -1
  30. package/dist/federation/negotiation.test.mjs +1 -1
  31. package/dist/federation/router.test.mjs +1 -1
  32. package/dist/federation/send.test.mjs +133 -139
  33. package/dist/federation/webfinger.test.mjs +3 -3
  34. package/dist/{getMachineId-bsd-DqZ4QRFp.mjs → getMachineId-bsd-etIyxDet.mjs} +3 -3
  35. package/dist/{getMachineId-darwin-DMbbW3m7.mjs → getMachineId-darwin-D23zTf4g.mjs} +3 -3
  36. package/dist/{getMachineId-linux-lyeD2ug3.mjs → getMachineId-linux-ObI47Hql.mjs} +2 -2
  37. package/dist/{getMachineId-unsupported-JuKr57jY.mjs → getMachineId-unsupported-Ddu-PFeh.mjs} +2 -2
  38. package/dist/{getMachineId-win-Dxyf5pJq.mjs → getMachineId-win-Dpap6v5i.mjs} +3 -3
  39. package/dist/{http-QHJGzUe8.mjs → http-5G18W3NP.mjs} +59 -11
  40. package/dist/{http-CrGuipxe.d.cts → http-BDZeS5om.d.ts} +2 -1
  41. package/dist/{http-aQzN9Ayi.d.ts → http-C87EWkO0.d.cts} +2 -3
  42. package/dist/{http-D2EDlTr2.js → http-Dzy5c472.js} +58 -10
  43. package/dist/{http-e1wtIlFo.cjs → http-W2u_KBoQ.cjs} +57 -9
  44. package/dist/{key-CpAxygvh.mjs → key-D9dUsyow.mjs} +2 -2
  45. package/dist/{kv-CbLNp3zQ.d.cts → kv-D6hNiMTK.d.ts} +1 -0
  46. package/dist/{kv-cache-B3GfB70S.cjs → kv-cache-BygrlQ1c.cjs} +2 -2
  47. package/dist/{kv-cache-KLjvIlKt.js → kv-cache-CBSgxEsZ.js} +2 -2
  48. package/dist/{kv-cache-Bmv7tUzz.mjs → kv-cache-CiiNwT6W.mjs} +2 -2
  49. package/dist/{kv-GFYnFoOl.d.ts → kv-gJ8LYbxX.d.cts} +1 -3
  50. package/dist/{ld-Ce_vkKjG.mjs → ld-hbxDLO1k.mjs} +3 -3
  51. package/dist/{middleware-DsGmXfXz.mjs → middleware-BXnhAGF9.mjs} +201 -119
  52. package/dist/{middleware-DOLrvK_b.cjs → middleware-Caj827xW.cjs} +358 -139
  53. package/dist/{middleware-BJMPv7_l.mjs → middleware-DZQsPMZb.mjs} +1 -1
  54. package/dist/{middleware-De241etq.js → middleware-vCF_cKAq.js} +346 -111
  55. package/dist/{mod-CLgIXe9w.d.ts → mod-B0rWmfW5.d.cts} +4 -5
  56. package/dist/{mod-CMEbIaNh.d.cts → mod-BhU_H1I_.d.ts} +4 -3
  57. package/dist/{mod-B8Z8mBLk.d.ts → mod-CLPnQPsv.d.cts} +2 -3
  58. package/dist/{mod-Cr3f-ACa.d.cts → mod-DHO9lk3D.d.ts} +3 -2
  59. package/dist/{mod-CR8soWa9.d.ts → mod-DXY9JF28.d.cts} +3 -4
  60. package/dist/{mod-DClCOv0M.d.cts → mod-Dx3-hqyo.d.ts} +2 -1
  61. package/dist/mod.cjs +4 -4
  62. package/dist/mod.d.cts +9 -8
  63. package/dist/mod.d.ts +9 -10
  64. package/dist/mod.js +9 -9
  65. package/dist/{negotiation-VnHNB0Q5.mjs → negotiation-DDstyBvc.mjs} +29 -0
  66. package/dist/nodeinfo/client.test.mjs +2 -2
  67. package/dist/nodeinfo/handler.test.mjs +2 -2
  68. package/dist/nodeinfo/mod.d.cts +2 -1
  69. package/dist/nodeinfo/mod.d.ts +2 -3
  70. package/dist/nodeinfo/mod.js +3 -3
  71. package/dist/otel/exporter.test.mjs +2 -2
  72. package/dist/otel/mod.d.cts +2 -1
  73. package/dist/otel/mod.d.ts +2 -3
  74. package/dist/otel/mod.js +2 -2
  75. package/dist/{outgoing-jsonld-Bi7n-dEy.mjs → outgoing-jsonld-BgFLCJQ_.mjs} +2 -2
  76. package/dist/{owner-CptqhsOy.d.cts → owner-CnngXDNJ.d.ts} +2 -1
  77. package/dist/{owner-74ARJ5TL.d.ts → owner-DEvZuyOE.d.cts} +2 -3
  78. package/dist/{owner-DmgzyItA.mjs → owner-DwJe0BH9.mjs} +2 -2
  79. package/dist/{proof-BU1TpFYI.cjs → proof-CZCaAURh.cjs} +3 -3
  80. package/dist/{proof-DLDsFYfD.js → proof-DMJJZnKd.js} +2 -2
  81. package/dist/{proof-C3q2IhUr.mjs → proof-erpV_J_n.mjs} +5 -5
  82. package/dist/runtime/mod.d.cts +1 -0
  83. package/dist/runtime/mod.d.ts +1 -2
  84. package/dist/runtime/mod.js +3 -3
  85. package/dist/{send-CTi2iPXp.mjs → send-BOwz4Hw5.mjs} +128 -4
  86. package/dist/sig/http.test.mjs +140 -27
  87. package/dist/sig/key.test.mjs +2 -2
  88. package/dist/sig/ld.test.mjs +3 -3
  89. package/dist/sig/mod.cjs +2 -2
  90. package/dist/sig/mod.d.cts +4 -3
  91. package/dist/sig/mod.d.ts +4 -5
  92. package/dist/sig/mod.js +4 -4
  93. package/dist/sig/owner.test.mjs +2 -2
  94. package/dist/sig/proof.test.mjs +3 -3
  95. package/dist/testing/mod.d.mts +6 -1
  96. package/dist/testing/mod.mjs +1 -2
  97. package/dist/{transformers-ve6e2xcg.js → transformers-BGMIq1cs.js} +2 -2
  98. package/dist/{types-hvL8ElAs.js → types-CAY3OdLq.js} +2 -2
  99. package/dist/utils/docloader.test.mjs +3 -3
  100. package/dist/utils/kv-cache.test.mjs +2 -2
  101. package/dist/utils/mod.cjs +1 -1
  102. package/dist/utils/mod.d.cts +2 -1
  103. package/dist/utils/mod.d.ts +2 -3
  104. package/dist/utils/mod.js +3 -3
  105. package/dist/vocab/cjs.test.mjs +1 -1
  106. package/dist/vocab/mod.d.cts +1 -0
  107. package/dist/vocab/mod.d.ts +1 -2
  108. package/dist/vocab/mod.js +2 -2
  109. package/package.json +15 -15
  110. package/dist/middleware-CibncbiT.cjs +0 -4
  111. package/dist/{client-CIiz1WX7.mjs → client-B_A6mfn3.mjs} +1 -1
  112. package/dist/{public-audience-PVTwU_Ex.mjs → public-audience-N3pyOx2p.mjs} +1 -1
  113. /package/dist/{router-CrMLXoOr.mjs → router-BT_F5748.mjs} +0 -0
@@ -1,11 +1,11 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
- require("./chunk-DDcVe30Y.cjs");
3
+ const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
4
  const require_transformers = require("./transformers-NeAONrAq.cjs");
5
- const require_http = require("./http-e1wtIlFo.cjs");
6
- const require_proof = require("./proof-BU1TpFYI.cjs");
5
+ const require_http = require("./http-W2u_KBoQ.cjs");
6
+ const require_proof = require("./proof-CZCaAURh.cjs");
7
7
  const require_types = require("./types-KC4QAoxe.cjs");
8
- const require_kv_cache = require("./kv-cache-B3GfB70S.cjs");
8
+ const require_kv_cache = require("./kv-cache-BygrlQ1c.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-CibncbiT.cjs"));
214
+ const { FederationImpl } = await Promise.resolve().then(() => middleware_exports);
215
215
  const f = new FederationImpl(options);
216
216
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
217
217
  f.router = this.router.clone();
@@ -788,6 +788,12 @@ var FederationMetrics = class {
788
788
  inboxProcessingDuration;
789
789
  httpServerRequestCount;
790
790
  httpServerRequestDuration;
791
+ queueTaskEnqueued;
792
+ queueTaskStarted;
793
+ queueTaskCompleted;
794
+ queueTaskFailed;
795
+ queueTaskDuration;
796
+ queueTaskInFlight;
791
797
  constructor(meterProvider) {
792
798
  const meter = meterProvider.getMeter(require_http.name, require_http.version);
793
799
  this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
@@ -834,6 +840,46 @@ var FederationMetrics = class {
834
840
  1e4
835
841
  ] }
836
842
  });
843
+ this.queueTaskEnqueued = meter.createCounter("fedify.queue.task.enqueued", {
844
+ description: "Tasks Fedify enqueued for inbox, outbox, or fanout work.",
845
+ unit: "{task}"
846
+ });
847
+ this.queueTaskStarted = meter.createCounter("fedify.queue.task.started", {
848
+ description: "Tasks Fedify began processing as a queue worker.",
849
+ unit: "{task}"
850
+ });
851
+ this.queueTaskCompleted = meter.createCounter("fedify.queue.task.completed", {
852
+ description: "Queue tasks Fedify finished processing without throwing.",
853
+ unit: "{task}"
854
+ });
855
+ this.queueTaskFailed = meter.createCounter("fedify.queue.task.failed", {
856
+ description: "Queue tasks Fedify abandoned because processing threw.",
857
+ unit: "{task}"
858
+ });
859
+ this.queueTaskDuration = meter.createHistogram("fedify.queue.task.duration", {
860
+ description: "Duration of queue task processing in Fedify workers.",
861
+ unit: "ms",
862
+ advice: { explicitBucketBoundaries: [
863
+ 5,
864
+ 10,
865
+ 25,
866
+ 50,
867
+ 75,
868
+ 100,
869
+ 250,
870
+ 500,
871
+ 750,
872
+ 1e3,
873
+ 2500,
874
+ 5e3,
875
+ 7500,
876
+ 1e4
877
+ ] }
878
+ });
879
+ this.queueTaskInFlight = meter.createUpDownCounter("fedify.queue.task.in_flight", {
880
+ description: "Queue tasks currently being processed in this Fedify process.",
881
+ unit: "{task}"
882
+ });
837
883
  }
838
884
  recordDelivery(inbox, durationMs, success, activityType) {
839
885
  const deliveryAttributes = {
@@ -868,7 +914,85 @@ var FederationMetrics = class {
868
914
  this.httpServerRequestCount.add(1, attributes);
869
915
  this.httpServerRequestDuration.record(durationMs, attributes);
870
916
  }
917
+ recordQueueTaskEnqueued(common, attempt) {
918
+ const attributes = buildQueueTaskAttributes(common);
919
+ attributes["fedify.queue.task.attempt"] = attempt;
920
+ this.queueTaskEnqueued.add(1, attributes);
921
+ }
922
+ recordQueueTaskStarted(common) {
923
+ this.queueTaskStarted.add(1, buildQueueTaskAttributes(common));
924
+ }
925
+ incrementQueueTaskInFlight(common) {
926
+ this.queueTaskInFlight.add(1, buildQueueTaskInFlightAttributes(common));
927
+ }
928
+ decrementQueueTaskInFlight(common) {
929
+ this.queueTaskInFlight.add(-1, buildQueueTaskInFlightAttributes(common));
930
+ }
931
+ recordQueueTaskOutcome(common, result, durationMs) {
932
+ const attributes = buildQueueTaskAttributes(common);
933
+ attributes["fedify.queue.task.result"] = result;
934
+ if (result === "completed") this.queueTaskCompleted.add(1, attributes);
935
+ else if (result === "failed") this.queueTaskFailed.add(1, attributes);
936
+ this.queueTaskDuration.record(durationMs, attributes);
937
+ }
871
938
  };
939
+ function buildQueueTaskAttributes(common) {
940
+ const attributes = { "fedify.queue.role": common.role };
941
+ const backend = getQueueBackend(common.queue);
942
+ if (backend != null) attributes["fedify.queue.backend"] = backend;
943
+ const nativeRetrial = common.queue?.nativeRetrial;
944
+ if (typeof nativeRetrial === "boolean") attributes["fedify.queue.native_retrial"] = nativeRetrial;
945
+ if (common.activityType != null) attributes["activitypub.activity.type"] = common.activityType;
946
+ return attributes;
947
+ }
948
+ function buildQueueTaskInFlightAttributes(common) {
949
+ return buildQueueTaskAttributes({
950
+ role: common.role,
951
+ queue: common.queue
952
+ });
953
+ }
954
+ /**
955
+ * Returns the constructor name of the given message queue, when it is a
956
+ * meaningful identifier. Used as a best-effort `fedify.queue.backend`
957
+ * attribute on queue task metrics; returns `undefined` for plain object
958
+ * literals (whose constructor is `Object`) so the attribute does not appear
959
+ * with a non-informative value.
960
+ * @since 2.3.0
961
+ */
962
+ function getQueueBackend(queue) {
963
+ const name = queue?.constructor?.name;
964
+ if (name == null || name === "" || name === "Object") return void 0;
965
+ return name;
966
+ }
967
+ /**
968
+ * Records `fedify.queue.task.enqueued` for an outgoing outbox enqueue.
969
+ *
970
+ * Both `Context.sendActivity()` and `OutboxContext.forwardActivity()` enqueue
971
+ * outbox messages with the same metric attributes (role, queue, activity
972
+ * type, attempt), so they share this helper rather than each defining a local
973
+ * closure.
974
+ * @since 2.3.0
975
+ */
976
+ function recordOutboxEnqueue(meterProvider, outboxQueue, message) {
977
+ getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
978
+ role: "outbox",
979
+ queue: outboxQueue,
980
+ activityType: message.activityType
981
+ }, message.attempt);
982
+ }
983
+ /**
984
+ * Whether the given thrown value is an `AbortError`.
985
+ *
986
+ * `processQueuedTask` distinguishes aborted tasks (recorded as
987
+ * `fedify.queue.task.result=aborted`) from other failures so that backend
988
+ * shutdown signals do not inflate the `fedify.queue.task.failed` counter.
989
+ * @since 2.3.0
990
+ */
991
+ function isAbortError(error) {
992
+ if (error == null || typeof error !== "object") return false;
993
+ const name = error.name;
994
+ return typeof name === "string" && name === "AbortError";
995
+ }
872
996
  const KNOWN_HTTP_METHODS = new Set([
873
997
  "CONNECT",
874
998
  "DELETE",
@@ -990,6 +1114,11 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
990
1114
  });
991
1115
  throw error;
992
1116
  }
1117
+ getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
1118
+ role: "inbox",
1119
+ queue,
1120
+ activityType: (0, _fedify_vocab.getTypeId)(activity).href
1121
+ }, 0);
993
1122
  logger.info("Activity {activityId} is enqueued.", {
994
1123
  activityId: activity.id?.href,
995
1124
  activity: json,
@@ -1150,6 +1279,35 @@ var KvKeyCache = class {
1150
1279
  };
1151
1280
  //#endregion
1152
1281
  //#region src/federation/negotiation.ts
1282
+ /*!
1283
+ * Adapted directly from negotiator at https://github.com/jshttp/negotiator/
1284
+ * which is licensed as follows:
1285
+ *
1286
+ * (The MIT License)
1287
+ *
1288
+ * Copyright (c) 2012-2014 Federico Romero
1289
+ * Copyright (c) 2012-2014 Isaac Z. Schlueter
1290
+ * Copyright (c) 2014-2015 Douglas Christopher Wilson
1291
+ *
1292
+ * Permission is hereby granted, free of charge, to any person obtaining
1293
+ * a copy of this software and associated documentation files (the
1294
+ * 'Software'), to deal in the Software without restriction, including
1295
+ * without limitation the rights to use, copy, modify, merge, publish,
1296
+ * distribute, sublicense, and/or sell copies of the Software, and to
1297
+ * permit persons to whom the Software is furnished to do so, subject to
1298
+ * the following conditions:
1299
+ *
1300
+ * The above copyright notice and this permission notice shall be
1301
+ * included in all copies or substantial portions of the Software.
1302
+ *
1303
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
1304
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1305
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1306
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1307
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1308
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1309
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1310
+ */
1153
1311
  function compareSpecs(a, b) {
1154
1312
  return b.q - a.q || (b.s ?? 0) - (a.s ?? 0) || (a.o ?? 0) - (b.o ?? 0) || a.i - b.i || 0;
1155
1313
  }
@@ -2032,6 +2190,14 @@ async function _handleOrderedCollection(request, { name, values, context, tracer
2032
2190
  * @since 1.8.0
2033
2191
  */
2034
2192
  var CustomCollectionHandler = class {
2193
+ name;
2194
+ values;
2195
+ context;
2196
+ callbacks;
2197
+ tracerProvider;
2198
+ Collection;
2199
+ CollectionPage;
2200
+ filterPredicate;
2035
2201
  /**
2036
2202
  * The tracer for telemetry.
2037
2203
  * @type {Tracer}
@@ -2896,6 +3062,14 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
2896
3062
  }
2897
3063
  //#endregion
2898
3064
  //#region src/federation/middleware.ts
3065
+ var middleware_exports = /* @__PURE__ */ require_chunk.__exportAll({
3066
+ ContextImpl: () => ContextImpl,
3067
+ FederationImpl: () => FederationImpl,
3068
+ InboxContextImpl: () => InboxContextImpl,
3069
+ KvSpecDeterminer: () => KvSpecDeterminer,
3070
+ OutboxContextImpl: () => OutboxContextImpl,
3071
+ createFederation: () => createFederation
3072
+ });
2899
3073
  /**
2900
3074
  * Create a new {@link Federation} instance.
2901
3075
  * @param parameters Parameters for initializing the instance.
@@ -3059,78 +3233,123 @@ var FederationImpl = class extends FederationBuilderImpl {
3059
3233
  processQueuedTask(contextData, message) {
3060
3234
  const tracer = this._getTracer();
3061
3235
  const extractedContext = _opentelemetry_api.propagation.extract(_opentelemetry_api.context.active(), message.traceContext);
3236
+ const meter = getFederationMetrics(this.meterProvider);
3062
3237
  return (0, _logtape_logtape.withContext)({ messageId: message.id }, async () => {
3063
- if (message.type === "fanout") await tracer.startActiveSpan("activitypub.fanout", {
3064
- kind: _opentelemetry_api.SpanKind.CONSUMER,
3065
- attributes: { "activitypub.activity.type": message.activityType }
3066
- }, extractedContext, async (span) => {
3067
- const spanCtx = span.spanContext();
3068
- return await (0, _logtape_logtape.withContext)({
3069
- traceId: spanCtx.traceId,
3070
- spanId: spanCtx.spanId
3071
- }, async () => {
3072
- if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
3073
- try {
3074
- await this.#listenFanoutMessage(contextData, message);
3075
- } catch (e) {
3076
- span.setStatus({
3077
- code: _opentelemetry_api.SpanStatusCode.ERROR,
3078
- message: String(e)
3079
- });
3080
- throw e;
3081
- } finally {
3082
- span.end();
3083
- }
3238
+ if (message.type === "fanout") {
3239
+ const common = {
3240
+ role: "fanout",
3241
+ queue: this.fanoutQueue,
3242
+ activityType: message.activityType
3243
+ };
3244
+ await tracer.startActiveSpan("activitypub.fanout", {
3245
+ kind: _opentelemetry_api.SpanKind.CONSUMER,
3246
+ attributes: { "activitypub.activity.type": message.activityType }
3247
+ }, extractedContext, async (span) => {
3248
+ const spanCtx = span.spanContext();
3249
+ return await (0, _logtape_logtape.withContext)({
3250
+ traceId: spanCtx.traceId,
3251
+ spanId: spanCtx.spanId
3252
+ }, async () => {
3253
+ if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
3254
+ meter.recordQueueTaskStarted(common);
3255
+ meter.incrementQueueTaskInFlight(common);
3256
+ const startedAt = performance.now();
3257
+ let outcome = "completed";
3258
+ try {
3259
+ await this.#listenFanoutMessage(contextData, message);
3260
+ } catch (e) {
3261
+ const aborted = isAbortError(e);
3262
+ outcome = aborted ? "aborted" : "failed";
3263
+ if (!aborted) span.setStatus({
3264
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
3265
+ message: String(e)
3266
+ });
3267
+ throw e;
3268
+ } finally {
3269
+ meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
3270
+ meter.decrementQueueTaskInFlight(common);
3271
+ span.end();
3272
+ }
3273
+ });
3084
3274
  });
3085
- });
3086
- else if (message.type === "outbox") await tracer.startActiveSpan("activitypub.outbox", {
3087
- kind: _opentelemetry_api.SpanKind.CONSUMER,
3088
- attributes: {
3089
- "activitypub.activity.type": message.activityType,
3090
- "activitypub.activity.retries": message.attempt
3091
- }
3092
- }, extractedContext, async (span) => {
3093
- const spanCtx = span.spanContext();
3094
- return await (0, _logtape_logtape.withContext)({
3095
- traceId: spanCtx.traceId,
3096
- spanId: spanCtx.spanId
3097
- }, async () => {
3098
- if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
3099
- try {
3100
- await this.#listenOutboxMessage(contextData, message, span);
3101
- } catch (e) {
3102
- span.setStatus({
3103
- code: _opentelemetry_api.SpanStatusCode.ERROR,
3104
- message: String(e)
3105
- });
3106
- throw e;
3107
- } finally {
3108
- span.end();
3275
+ } else if (message.type === "outbox") {
3276
+ const common = {
3277
+ role: "outbox",
3278
+ queue: this.outboxQueue,
3279
+ activityType: message.activityType
3280
+ };
3281
+ await tracer.startActiveSpan("activitypub.outbox", {
3282
+ kind: _opentelemetry_api.SpanKind.CONSUMER,
3283
+ attributes: {
3284
+ "activitypub.activity.type": message.activityType,
3285
+ "activitypub.activity.retries": message.attempt
3109
3286
  }
3287
+ }, extractedContext, async (span) => {
3288
+ const spanCtx = span.spanContext();
3289
+ return await (0, _logtape_logtape.withContext)({
3290
+ traceId: spanCtx.traceId,
3291
+ spanId: spanCtx.spanId
3292
+ }, async () => {
3293
+ if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
3294
+ meter.recordQueueTaskStarted(common);
3295
+ meter.incrementQueueTaskInFlight(common);
3296
+ const startedAt = performance.now();
3297
+ let outcome = "completed";
3298
+ try {
3299
+ await this.#listenOutboxMessage(contextData, message, span);
3300
+ } catch (e) {
3301
+ const aborted = isAbortError(e);
3302
+ outcome = aborted ? "aborted" : "failed";
3303
+ if (!aborted) span.setStatus({
3304
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
3305
+ message: String(e)
3306
+ });
3307
+ throw e;
3308
+ } finally {
3309
+ meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
3310
+ meter.decrementQueueTaskInFlight(common);
3311
+ span.end();
3312
+ }
3313
+ });
3110
3314
  });
3111
- });
3112
- else if (message.type === "inbox") await tracer.startActiveSpan("activitypub.inbox", {
3113
- kind: _opentelemetry_api.SpanKind.CONSUMER,
3114
- attributes: { "activitypub.shared_inbox": message.identifier == null }
3115
- }, extractedContext, async (span) => {
3116
- const spanCtx = span.spanContext();
3117
- return await (0, _logtape_logtape.withContext)({
3118
- traceId: spanCtx.traceId,
3119
- spanId: spanCtx.spanId
3120
- }, async () => {
3121
- try {
3122
- await this.#listenInboxMessage(contextData, message, span);
3123
- } catch (e) {
3124
- span.setStatus({
3125
- code: _opentelemetry_api.SpanStatusCode.ERROR,
3126
- message: String(e)
3127
- });
3128
- throw e;
3129
- } finally {
3130
- span.end();
3131
- }
3315
+ } else if (message.type === "inbox") {
3316
+ const common = {
3317
+ role: "inbox",
3318
+ queue: this.inboxQueue
3319
+ };
3320
+ await tracer.startActiveSpan("activitypub.inbox", {
3321
+ kind: _opentelemetry_api.SpanKind.CONSUMER,
3322
+ attributes: { "activitypub.shared_inbox": message.identifier == null }
3323
+ }, extractedContext, async (span) => {
3324
+ const spanCtx = span.spanContext();
3325
+ return await (0, _logtape_logtape.withContext)({
3326
+ traceId: spanCtx.traceId,
3327
+ spanId: spanCtx.spanId
3328
+ }, async () => {
3329
+ meter.recordQueueTaskStarted(common);
3330
+ meter.incrementQueueTaskInFlight(common);
3331
+ const startedAt = performance.now();
3332
+ let outcome = "completed";
3333
+ try {
3334
+ await this.#listenInboxMessage(contextData, message, span, (activityType) => {
3335
+ common.activityType = activityType;
3336
+ });
3337
+ } catch (e) {
3338
+ const aborted = isAbortError(e);
3339
+ outcome = aborted ? "aborted" : "failed";
3340
+ if (!aborted) span.setStatus({
3341
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
3342
+ message: String(e)
3343
+ });
3344
+ throw e;
3345
+ } finally {
3346
+ meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
3347
+ meter.decrementQueueTaskInFlight(common);
3348
+ span.end();
3349
+ }
3350
+ });
3132
3351
  });
3133
- });
3352
+ }
3134
3353
  });
3135
3354
  }
3136
3355
  async #listenFanoutMessage(data, message) {
@@ -3287,10 +3506,19 @@ var FederationImpl = class extends FederationBuilderImpl {
3287
3506
  ...logData,
3288
3507
  error
3289
3508
  });
3290
- await this.outboxQueue?.enqueue({
3509
+ const retryMessage = {
3291
3510
  ...message,
3292
3511
  attempt: message.attempt + 1
3293
- }, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
3512
+ };
3513
+ const { outboxQueue } = this;
3514
+ if (outboxQueue != null) {
3515
+ await outboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
3516
+ getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
3517
+ role: "outbox",
3518
+ queue: outboxQueue,
3519
+ activityType: retryMessage.activityType
3520
+ }, retryMessage.attempt);
3521
+ }
3294
3522
  } else logger.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
3295
3523
  ...logData,
3296
3524
  error
@@ -3299,7 +3527,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3299
3527
  }
3300
3528
  logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
3301
3529
  }
3302
- async #listenInboxMessage(ctxData, message, span) {
3530
+ async #listenInboxMessage(ctxData, message, span, onActivityType) {
3303
3531
  const logger = (0, _logtape_logtape.getLogger)([
3304
3532
  "fedify",
3305
3533
  "federation",
@@ -3313,7 +3541,9 @@ var FederationImpl = class extends FederationBuilderImpl {
3313
3541
  if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
3314
3542
  }
3315
3543
  const activity = await _fedify_vocab.Activity.fromJsonLd(message.activity, context);
3316
- span.setAttribute("activitypub.activity.type", (0, _fedify_vocab.getTypeId)(activity).href);
3544
+ const activityType = (0, _fedify_vocab.getTypeId)(activity).href;
3545
+ span.setAttribute("activitypub.activity.type", activityType);
3546
+ onActivityType?.(activityType);
3317
3547
  if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
3318
3548
  const cacheKey = activity.id == null ? null : [
3319
3549
  ...this.kvPrefixes.activityIdempotence,
@@ -3341,7 +3571,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3341
3571
  });
3342
3572
  span.setStatus({
3343
3573
  code: _opentelemetry_api.SpanStatusCode.ERROR,
3344
- message: `Unsupported activity type: ${(0, _fedify_vocab.getTypeId)(activity).href}`
3574
+ message: `Unsupported activity type: ${activityType}`
3345
3575
  });
3346
3576
  span.end();
3347
3577
  return;
@@ -3349,7 +3579,6 @@ var FederationImpl = class extends FederationBuilderImpl {
3349
3579
  const { class: cls, listener } = dispatched;
3350
3580
  span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
3351
3581
  try {
3352
- const activityType = (0, _fedify_vocab.getTypeId)(activity).href;
3353
3582
  const started = performance.now();
3354
3583
  try {
3355
3584
  await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
@@ -3394,10 +3623,19 @@ var FederationImpl = class extends FederationBuilderImpl {
3394
3623
  activity: message.activity,
3395
3624
  recipient: message.identifier
3396
3625
  });
3397
- await this.inboxQueue?.enqueue({
3626
+ const retryMessage = {
3398
3627
  ...message,
3399
3628
  attempt: message.attempt + 1
3400
- }, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
3629
+ };
3630
+ const { inboxQueue } = this;
3631
+ if (inboxQueue != null) {
3632
+ await inboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
3633
+ getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
3634
+ role: "inbox",
3635
+ queue: inboxQueue,
3636
+ activityType
3637
+ }, retryMessage.attempt);
3638
+ }
3401
3639
  } else logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
3402
3640
  error,
3403
3641
  activityId: activity.id?.href,
@@ -3586,9 +3824,11 @@ var FederationImpl = class extends FederationBuilderImpl {
3586
3824
  });
3587
3825
  }
3588
3826
  const { outboxQueue } = this;
3589
- if (outboxQueue.enqueueMany == null) {
3590
- const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
3591
- const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
3827
+ if (outboxQueue.enqueueMany == null || orderingKey != null) {
3828
+ const errors = (await Promise.allSettled(messages.map(async (m) => {
3829
+ await outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey });
3830
+ recordOutboxEnqueue(this.meterProvider, outboxQueue, m.message);
3831
+ }))).filter((r) => r.status === "rejected").map((r) => r.reason);
3592
3832
  if (errors.length > 0) {
3593
3833
  logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
3594
3834
  activityId: activity.id.href,
@@ -3597,25 +3837,17 @@ var FederationImpl = class extends FederationBuilderImpl {
3597
3837
  if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
3598
3838
  throw errors[0];
3599
3839
  }
3600
- } else if (orderingKey != null) {
3601
- const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
3602
- const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
3603
- if (errors.length > 0) {
3604
- logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
3840
+ } else {
3841
+ try {
3842
+ await outboxQueue.enqueueMany(messages.map((m) => m.message));
3843
+ } catch (error) {
3844
+ logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
3605
3845
  activityId: activity.id.href,
3606
- errors
3846
+ error
3607
3847
  });
3608
- if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
3609
- throw errors[0];
3848
+ throw error;
3610
3849
  }
3611
- } else try {
3612
- await outboxQueue.enqueueMany(messages.map((m) => m.message));
3613
- } catch (error) {
3614
- logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
3615
- activityId: activity.id.href,
3616
- error
3617
- });
3618
- throw error;
3850
+ for (const m of messages) recordOutboxEnqueue(this.meterProvider, outboxQueue, m.message);
3619
3851
  }
3620
3852
  }
3621
3853
  fetch(request, options) {
@@ -4431,6 +4663,11 @@ var ContextImpl = class ContextImpl {
4431
4663
  };
4432
4664
  if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
4433
4665
  await this.federation.fanoutQueue.enqueue(message, { orderingKey: options.orderingKey });
4666
+ getFederationMetrics(this.federation.meterProvider).recordQueueTaskEnqueued({
4667
+ role: "fanout",
4668
+ queue: this.federation.fanoutQueue,
4669
+ activityType: message.activityType
4670
+ }, 0);
4434
4671
  return true;
4435
4672
  }
4436
4673
  async *getFollowers(identifier) {
@@ -4561,6 +4798,7 @@ var ContextImpl = class ContextImpl {
4561
4798
  kvPrefixes: this.federation.kvPrefixes,
4562
4799
  queue: this.federation.inboxQueue,
4563
4800
  span,
4801
+ meterProvider: this.federation.meterProvider,
4564
4802
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
4565
4803
  idempotencyStrategy: this.federation.idempotencyStrategy
4566
4804
  });
@@ -4810,8 +5048,10 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
4810
5048
  }
4811
5049
  const { outboxQueue } = ctx.federation;
4812
5050
  if (outboxQueue.enqueueMany == null || orderingKey != null) {
4813
- const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
4814
- const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
5051
+ const errors = (await Promise.allSettled(messages.map(async (m) => {
5052
+ await outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey });
5053
+ recordOutboxEnqueue(ctx.federation.meterProvider, outboxQueue, m.message);
5054
+ }))).filter((r) => r.status === "rejected").map((r) => r.reason);
4815
5055
  if (errors.length > 0) {
4816
5056
  logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
4817
5057
  activityId: ctx.activityId,
@@ -4820,14 +5060,17 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
4820
5060
  if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${ctx.activityId} to forward later.`);
4821
5061
  throw errors[0];
4822
5062
  }
4823
- } else try {
4824
- await outboxQueue.enqueueMany(messages.map((m) => m.message));
4825
- } catch (error) {
4826
- logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
4827
- activityId: ctx.activityId,
4828
- error
4829
- });
4830
- throw error;
5063
+ } else {
5064
+ try {
5065
+ await outboxQueue.enqueueMany(messages.map((m) => m.message));
5066
+ } catch (error) {
5067
+ logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
5068
+ activityId: ctx.activityId,
5069
+ error
5070
+ });
5071
+ throw error;
5072
+ }
5073
+ for (const m of messages) recordOutboxEnqueue(ctx.federation.meterProvider, outboxQueue, m.message);
4831
5074
  }
4832
5075
  return true;
4833
5076
  }
@@ -4965,36 +5208,6 @@ function getRequestId(request) {
4965
5208
  return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
4966
5209
  }
4967
5210
  //#endregion
4968
- Object.defineProperty(exports, "ContextImpl", {
4969
- enumerable: true,
4970
- get: function() {
4971
- return ContextImpl;
4972
- }
4973
- });
4974
- Object.defineProperty(exports, "FederationImpl", {
4975
- enumerable: true,
4976
- get: function() {
4977
- return FederationImpl;
4978
- }
4979
- });
4980
- Object.defineProperty(exports, "InboxContextImpl", {
4981
- enumerable: true,
4982
- get: function() {
4983
- return InboxContextImpl;
4984
- }
4985
- });
4986
- Object.defineProperty(exports, "KvSpecDeterminer", {
4987
- enumerable: true,
4988
- get: function() {
4989
- return KvSpecDeterminer;
4990
- }
4991
- });
4992
- Object.defineProperty(exports, "OutboxContextImpl", {
4993
- enumerable: true,
4994
- get: function() {
4995
- return OutboxContextImpl;
4996
- }
4997
- });
4998
5211
  Object.defineProperty(exports, "Router", {
4999
5212
  enumerable: true,
5000
5213
  get: function() {
@@ -5049,6 +5262,12 @@ Object.defineProperty(exports, "handleWebFinger", {
5049
5262
  return handleWebFinger;
5050
5263
  }
5051
5264
  });
5265
+ Object.defineProperty(exports, "middleware_exports", {
5266
+ enumerable: true,
5267
+ get: function() {
5268
+ return middleware_exports;
5269
+ }
5270
+ });
5052
5271
  Object.defineProperty(exports, "respondWithObject", {
5053
5272
  enumerable: true,
5054
5273
  get: function() {
@@ -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-DsGmXfXz.mjs";
4
+ import { n as FederationImpl } from "./middleware-BXnhAGF9.mjs";
5
5
  export { FederationImpl };