@fedify/fedify 2.3.0-dev.1079 → 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 (86) hide show
  1. package/dist/{builder-DqT-OPZ8.mjs → builder-BkRRjxzb.mjs} +2 -2
  2. package/dist/{chunk-nlSIicah.js → chunk-CRNNMoPX.js} +2 -2
  3. package/dist/{client-z-8dc-e1.d.cts → client-CAM_bQXx.d.cts} +1 -0
  4. package/dist/{client-AtlibPOU.d.ts → client-CSddvgWN.d.ts} +1 -2
  5. package/dist/compat/mod.d.cts +2 -1
  6. package/dist/compat/mod.d.ts +2 -3
  7. package/dist/compat/mod.js +3 -3
  8. package/dist/compat/transformers.test.mjs +1 -1
  9. package/dist/{context-DrNqYkPw.d.ts → context-C0C_sRha.d.cts} +6 -7
  10. package/dist/{context-BKLGj9QO.d.cts → context-Dqgt8saU.d.ts} +6 -5
  11. package/dist/{deno-BxqkYxIf.mjs → deno-DBabeupC.mjs} +1 -1
  12. package/dist/{docloader-vsZP01ww.mjs → docloader-DA5FzJOR.mjs} +2 -2
  13. package/dist/federation/builder.test.mjs +1 -1
  14. package/dist/federation/handler.test.mjs +84 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/middleware.test.mjs +383 -16
  17. package/dist/federation/mod.cjs +1 -1
  18. package/dist/federation/mod.d.cts +4 -3
  19. package/dist/federation/mod.d.ts +4 -5
  20. package/dist/federation/mod.js +2 -2
  21. package/dist/federation/send.test.mjs +3 -3
  22. package/dist/federation/webfinger.test.mjs +1 -1
  23. package/dist/{http-DM4ZAFCe.mjs → http-5G18W3NP.mjs} +58 -10
  24. package/dist/{http-CrGuipxe.d.cts → http-BDZeS5om.d.ts} +2 -1
  25. package/dist/{http-aQzN9Ayi.d.ts → http-C87EWkO0.d.cts} +2 -3
  26. package/dist/{http-b__OS_rJ.js → http-Dzy5c472.js} +58 -10
  27. package/dist/{http-DQ25_ruv.cjs → http-W2u_KBoQ.cjs} +57 -9
  28. package/dist/{key-BNp_b9oE.mjs → key-D9dUsyow.mjs} +1 -1
  29. package/dist/{kv-CbLNp3zQ.d.cts → kv-D6hNiMTK.d.ts} +1 -0
  30. package/dist/{kv-cache-DzctboPD.cjs → kv-cache-BygrlQ1c.cjs} +2 -2
  31. package/dist/{kv-cache-D5vjOi5y.js → kv-cache-CBSgxEsZ.js} +2 -2
  32. package/dist/{kv-cache-EaVpV2xQ.mjs → kv-cache-CiiNwT6W.mjs} +1 -1
  33. package/dist/{kv-GFYnFoOl.d.ts → kv-gJ8LYbxX.d.cts} +1 -3
  34. package/dist/{ld-L9w529xq.mjs → ld-hbxDLO1k.mjs} +2 -2
  35. package/dist/{middleware-CTdNwf_s.mjs → middleware-BXnhAGF9.mjs} +188 -114
  36. package/dist/{middleware-CMF242Rg.cjs → middleware-Caj827xW.cjs} +305 -107
  37. package/dist/{middleware-CpCSD43m.mjs → middleware-DZQsPMZb.mjs} +1 -1
  38. package/dist/{middleware-DZNHpEbh.js → middleware-vCF_cKAq.js} +309 -111
  39. package/dist/{mod-CLgIXe9w.d.ts → mod-B0rWmfW5.d.cts} +4 -5
  40. package/dist/{mod-CMEbIaNh.d.cts → mod-BhU_H1I_.d.ts} +4 -3
  41. package/dist/{mod-B8Z8mBLk.d.ts → mod-CLPnQPsv.d.cts} +2 -3
  42. package/dist/{mod-Cr3f-ACa.d.cts → mod-DHO9lk3D.d.ts} +3 -2
  43. package/dist/{mod-CR8soWa9.d.ts → mod-DXY9JF28.d.cts} +3 -4
  44. package/dist/{mod-DClCOv0M.d.cts → mod-Dx3-hqyo.d.ts} +2 -1
  45. package/dist/mod.cjs +4 -4
  46. package/dist/mod.d.cts +9 -8
  47. package/dist/mod.d.ts +9 -10
  48. package/dist/mod.js +9 -9
  49. package/dist/nodeinfo/handler.test.mjs +1 -1
  50. package/dist/nodeinfo/mod.d.cts +2 -1
  51. package/dist/nodeinfo/mod.d.ts +2 -3
  52. package/dist/nodeinfo/mod.js +3 -3
  53. package/dist/otel/mod.d.cts +2 -1
  54. package/dist/otel/mod.d.ts +2 -3
  55. package/dist/otel/mod.js +2 -2
  56. package/dist/{owner-CptqhsOy.d.cts → owner-CnngXDNJ.d.ts} +2 -1
  57. package/dist/{owner-74ARJ5TL.d.ts → owner-DEvZuyOE.d.cts} +2 -3
  58. package/dist/{owner-C30LGgMz.mjs → owner-DwJe0BH9.mjs} +2 -2
  59. package/dist/{proof-zrLeLWgt.cjs → proof-CZCaAURh.cjs} +1 -1
  60. package/dist/{proof-CO1qAbN8.js → proof-DMJJZnKd.js} +2 -2
  61. package/dist/{proof-BjToRsXF.mjs → proof-erpV_J_n.mjs} +2 -2
  62. package/dist/runtime/mod.d.cts +1 -0
  63. package/dist/runtime/mod.d.ts +1 -2
  64. package/dist/runtime/mod.js +3 -3
  65. package/dist/{send-DzbMznU6.mjs → send-BOwz4Hw5.mjs} +127 -3
  66. package/dist/sig/http.test.mjs +120 -2
  67. package/dist/sig/key.test.mjs +1 -1
  68. package/dist/sig/ld.test.mjs +2 -2
  69. package/dist/sig/mod.cjs +2 -2
  70. package/dist/sig/mod.d.cts +4 -3
  71. package/dist/sig/mod.d.ts +4 -5
  72. package/dist/sig/mod.js +4 -4
  73. package/dist/sig/owner.test.mjs +1 -1
  74. package/dist/sig/proof.test.mjs +1 -1
  75. package/dist/{transformers-ve6e2xcg.js → transformers-BGMIq1cs.js} +2 -2
  76. package/dist/{types-hvL8ElAs.js → types-CAY3OdLq.js} +2 -2
  77. package/dist/utils/docloader.test.mjs +2 -2
  78. package/dist/utils/kv-cache.test.mjs +1 -1
  79. package/dist/utils/mod.cjs +1 -1
  80. package/dist/utils/mod.d.cts +2 -1
  81. package/dist/utils/mod.d.ts +2 -3
  82. package/dist/utils/mod.js +3 -3
  83. package/dist/vocab/mod.d.cts +1 -0
  84. package/dist/vocab/mod.d.ts +1 -2
  85. package/dist/vocab/mod.js +2 -2
  86. package/package.json +6 -6
@@ -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-BT_F5748.mjs";
5
- import { n as version, t as name } from "./deno-BxqkYxIf.mjs";
5
+ import { n as version, t as name } from "./deno-DBabeupC.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-CceiKpCy.mjs";
7
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-BNp_b9oE.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-DM4ZAFCe.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-vsZP01ww.mjs";
10
- import { n as kvCache } from "./kv-cache-EaVpV2xQ.mjs";
11
- import { a as signJsonLd, i as hasSignatureLike, o as verifyJsonLd, r as detachSignature } from "./ld-L9w529xq.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-C30LGgMz.mjs";
7
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-D9dUsyow.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-5G18W3NP.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-DA5FzJOR.mjs";
10
+ import { n as kvCache } from "./kv-cache-CiiNwT6W.mjs";
11
+ import { a as signJsonLd, i as hasSignatureLike, o as verifyJsonLd, r as detachSignature } from "./ld-hbxDLO1k.mjs";
12
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DwJe0BH9.mjs";
13
13
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-BgFLCJQ_.mjs";
14
- import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-BjToRsXF.mjs";
14
+ import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-erpV_J_n.mjs";
15
15
  import { t as getNodeInfo } from "./client-B_A6mfn3.mjs";
16
16
  import { t as nodeInfoToJson } from "./types-BFowWFTT.mjs";
17
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-DqT-OPZ8.mjs";
17
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-BkRRjxzb.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-DzbMznU6.mjs";
19
+ import { a as getFederationMetrics, c as recordOutboxEnqueue, i as getDurationMs, n as extractInboxes, o as getRemoteHost, r as sendActivity, s as isAbortError, t as SendActivityError } from "./send-BOwz4Hw5.mjs";
20
20
  import { t as KvKeyCache } from "./keycache-BeU0LCII.mjs";
21
21
  import { t as acceptsJsonLd } from "./negotiation-DDstyBvc.mjs";
22
22
  import { t as createExponentialBackoffPolicy } from "./retry-_VvV0h9f.mjs";
@@ -230,6 +230,11 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
230
230
  });
231
231
  throw error;
232
232
  }
233
+ getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
234
+ role: "inbox",
235
+ queue,
236
+ activityType: getTypeId(activity).href
237
+ }, 0);
233
238
  logger.info("Activity {activityId} is enqueued.", {
234
239
  activityId: activity.id?.href,
235
240
  activity: json,
@@ -1871,78 +1876,123 @@ var FederationImpl = class extends FederationBuilderImpl {
1871
1876
  processQueuedTask(contextData, message) {
1872
1877
  const tracer = this._getTracer();
1873
1878
  const extractedContext = propagation.extract(context.active(), message.traceContext);
1879
+ const meter = getFederationMetrics(this.meterProvider);
1874
1880
  return withContext({ messageId: message.id }, async () => {
1875
- if (message.type === "fanout") await tracer.startActiveSpan("activitypub.fanout", {
1876
- kind: SpanKind.CONSUMER,
1877
- attributes: { "activitypub.activity.type": message.activityType }
1878
- }, extractedContext, async (span) => {
1879
- const spanCtx = span.spanContext();
1880
- return await withContext({
1881
- traceId: spanCtx.traceId,
1882
- spanId: spanCtx.spanId
1883
- }, async () => {
1884
- if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
1885
- try {
1886
- await this.#listenFanoutMessage(contextData, message);
1887
- } catch (e) {
1888
- span.setStatus({
1889
- code: SpanStatusCode.ERROR,
1890
- message: String(e)
1891
- });
1892
- throw e;
1893
- } finally {
1894
- span.end();
1895
- }
1881
+ if (message.type === "fanout") {
1882
+ const common = {
1883
+ role: "fanout",
1884
+ queue: this.fanoutQueue,
1885
+ activityType: message.activityType
1886
+ };
1887
+ await tracer.startActiveSpan("activitypub.fanout", {
1888
+ kind: SpanKind.CONSUMER,
1889
+ attributes: { "activitypub.activity.type": message.activityType }
1890
+ }, extractedContext, async (span) => {
1891
+ const spanCtx = span.spanContext();
1892
+ return await withContext({
1893
+ traceId: spanCtx.traceId,
1894
+ spanId: spanCtx.spanId
1895
+ }, async () => {
1896
+ if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
1897
+ meter.recordQueueTaskStarted(common);
1898
+ meter.incrementQueueTaskInFlight(common);
1899
+ const startedAt = performance.now();
1900
+ let outcome = "completed";
1901
+ try {
1902
+ await this.#listenFanoutMessage(contextData, message);
1903
+ } catch (e) {
1904
+ const aborted = isAbortError(e);
1905
+ outcome = aborted ? "aborted" : "failed";
1906
+ if (!aborted) span.setStatus({
1907
+ code: SpanStatusCode.ERROR,
1908
+ message: String(e)
1909
+ });
1910
+ throw e;
1911
+ } finally {
1912
+ meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
1913
+ meter.decrementQueueTaskInFlight(common);
1914
+ span.end();
1915
+ }
1916
+ });
1896
1917
  });
1897
- });
1898
- else if (message.type === "outbox") await tracer.startActiveSpan("activitypub.outbox", {
1899
- kind: SpanKind.CONSUMER,
1900
- attributes: {
1901
- "activitypub.activity.type": message.activityType,
1902
- "activitypub.activity.retries": message.attempt
1903
- }
1904
- }, extractedContext, async (span) => {
1905
- const spanCtx = span.spanContext();
1906
- return await withContext({
1907
- traceId: spanCtx.traceId,
1908
- spanId: spanCtx.spanId
1909
- }, async () => {
1910
- if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
1911
- try {
1912
- await this.#listenOutboxMessage(contextData, message, span);
1913
- } catch (e) {
1914
- span.setStatus({
1915
- code: SpanStatusCode.ERROR,
1916
- message: String(e)
1917
- });
1918
- throw e;
1919
- } finally {
1920
- span.end();
1918
+ } else if (message.type === "outbox") {
1919
+ const common = {
1920
+ role: "outbox",
1921
+ queue: this.outboxQueue,
1922
+ activityType: message.activityType
1923
+ };
1924
+ await tracer.startActiveSpan("activitypub.outbox", {
1925
+ kind: SpanKind.CONSUMER,
1926
+ attributes: {
1927
+ "activitypub.activity.type": message.activityType,
1928
+ "activitypub.activity.retries": message.attempt
1921
1929
  }
1930
+ }, extractedContext, async (span) => {
1931
+ const spanCtx = span.spanContext();
1932
+ return await withContext({
1933
+ traceId: spanCtx.traceId,
1934
+ spanId: spanCtx.spanId
1935
+ }, async () => {
1936
+ if (message.activityId != null) span.setAttribute("activitypub.activity.id", message.activityId);
1937
+ meter.recordQueueTaskStarted(common);
1938
+ meter.incrementQueueTaskInFlight(common);
1939
+ const startedAt = performance.now();
1940
+ let outcome = "completed";
1941
+ try {
1942
+ await this.#listenOutboxMessage(contextData, message, span);
1943
+ } catch (e) {
1944
+ const aborted = isAbortError(e);
1945
+ outcome = aborted ? "aborted" : "failed";
1946
+ if (!aborted) span.setStatus({
1947
+ code: SpanStatusCode.ERROR,
1948
+ message: String(e)
1949
+ });
1950
+ throw e;
1951
+ } finally {
1952
+ meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
1953
+ meter.decrementQueueTaskInFlight(common);
1954
+ span.end();
1955
+ }
1956
+ });
1922
1957
  });
1923
- });
1924
- else if (message.type === "inbox") await tracer.startActiveSpan("activitypub.inbox", {
1925
- kind: SpanKind.CONSUMER,
1926
- attributes: { "activitypub.shared_inbox": message.identifier == null }
1927
- }, extractedContext, async (span) => {
1928
- const spanCtx = span.spanContext();
1929
- return await withContext({
1930
- traceId: spanCtx.traceId,
1931
- spanId: spanCtx.spanId
1932
- }, async () => {
1933
- try {
1934
- await this.#listenInboxMessage(contextData, message, span);
1935
- } catch (e) {
1936
- span.setStatus({
1937
- code: SpanStatusCode.ERROR,
1938
- message: String(e)
1939
- });
1940
- throw e;
1941
- } finally {
1942
- span.end();
1943
- }
1958
+ } else if (message.type === "inbox") {
1959
+ const common = {
1960
+ role: "inbox",
1961
+ queue: this.inboxQueue
1962
+ };
1963
+ await tracer.startActiveSpan("activitypub.inbox", {
1964
+ kind: SpanKind.CONSUMER,
1965
+ attributes: { "activitypub.shared_inbox": message.identifier == null }
1966
+ }, extractedContext, async (span) => {
1967
+ const spanCtx = span.spanContext();
1968
+ return await withContext({
1969
+ traceId: spanCtx.traceId,
1970
+ spanId: spanCtx.spanId
1971
+ }, async () => {
1972
+ meter.recordQueueTaskStarted(common);
1973
+ meter.incrementQueueTaskInFlight(common);
1974
+ const startedAt = performance.now();
1975
+ let outcome = "completed";
1976
+ try {
1977
+ await this.#listenInboxMessage(contextData, message, span, (activityType) => {
1978
+ common.activityType = activityType;
1979
+ });
1980
+ } catch (e) {
1981
+ const aborted = isAbortError(e);
1982
+ outcome = aborted ? "aborted" : "failed";
1983
+ if (!aborted) span.setStatus({
1984
+ code: SpanStatusCode.ERROR,
1985
+ message: String(e)
1986
+ });
1987
+ throw e;
1988
+ } finally {
1989
+ meter.recordQueueTaskOutcome(common, outcome, getDurationMs(startedAt));
1990
+ meter.decrementQueueTaskInFlight(common);
1991
+ span.end();
1992
+ }
1993
+ });
1944
1994
  });
1945
- });
1995
+ }
1946
1996
  });
1947
1997
  }
1948
1998
  async #listenFanoutMessage(data, message) {
@@ -2099,10 +2149,19 @@ var FederationImpl = class extends FederationBuilderImpl {
2099
2149
  ...logData,
2100
2150
  error
2101
2151
  });
2102
- await this.outboxQueue?.enqueue({
2152
+ const retryMessage = {
2103
2153
  ...message,
2104
2154
  attempt: message.attempt + 1
2105
- }, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
2155
+ };
2156
+ const { outboxQueue } = this;
2157
+ if (outboxQueue != null) {
2158
+ await outboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
2159
+ getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
2160
+ role: "outbox",
2161
+ queue: outboxQueue,
2162
+ activityType: retryMessage.activityType
2163
+ }, retryMessage.attempt);
2164
+ }
2106
2165
  } else logger.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
2107
2166
  ...logData,
2108
2167
  error
@@ -2111,7 +2170,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2111
2170
  }
2112
2171
  logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
2113
2172
  }
2114
- async #listenInboxMessage(ctxData, message, span) {
2173
+ async #listenInboxMessage(ctxData, message, span, onActivityType) {
2115
2174
  const logger = getLogger([
2116
2175
  "fedify",
2117
2176
  "federation",
@@ -2125,7 +2184,9 @@ var FederationImpl = class extends FederationBuilderImpl {
2125
2184
  if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
2126
2185
  }
2127
2186
  const activity = await Activity.fromJsonLd(message.activity, context);
2128
- span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
2187
+ const activityType = getTypeId(activity).href;
2188
+ span.setAttribute("activitypub.activity.type", activityType);
2189
+ onActivityType?.(activityType);
2129
2190
  if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
2130
2191
  const cacheKey = activity.id == null ? null : [
2131
2192
  ...this.kvPrefixes.activityIdempotence,
@@ -2153,7 +2214,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2153
2214
  });
2154
2215
  span.setStatus({
2155
2216
  code: SpanStatusCode.ERROR,
2156
- message: `Unsupported activity type: ${getTypeId(activity).href}`
2217
+ message: `Unsupported activity type: ${activityType}`
2157
2218
  });
2158
2219
  span.end();
2159
2220
  return;
@@ -2161,7 +2222,6 @@ var FederationImpl = class extends FederationBuilderImpl {
2161
2222
  const { class: cls, listener } = dispatched;
2162
2223
  span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
2163
2224
  try {
2164
- const activityType = getTypeId(activity).href;
2165
2225
  const started = performance.now();
2166
2226
  try {
2167
2227
  await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
@@ -2206,10 +2266,19 @@ var FederationImpl = class extends FederationBuilderImpl {
2206
2266
  activity: message.activity,
2207
2267
  recipient: message.identifier
2208
2268
  });
2209
- await this.inboxQueue?.enqueue({
2269
+ const retryMessage = {
2210
2270
  ...message,
2211
2271
  attempt: message.attempt + 1
2212
- }, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
2272
+ };
2273
+ const { inboxQueue } = this;
2274
+ if (inboxQueue != null) {
2275
+ await inboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
2276
+ getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
2277
+ role: "inbox",
2278
+ queue: inboxQueue,
2279
+ activityType
2280
+ }, retryMessage.attempt);
2281
+ }
2213
2282
  } else logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
2214
2283
  error,
2215
2284
  activityId: activity.id?.href,
@@ -2398,9 +2467,11 @@ var FederationImpl = class extends FederationBuilderImpl {
2398
2467
  });
2399
2468
  }
2400
2469
  const { outboxQueue } = this;
2401
- if (outboxQueue.enqueueMany == null) {
2402
- const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
2403
- const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
2470
+ if (outboxQueue.enqueueMany == null || orderingKey != null) {
2471
+ const errors = (await Promise.allSettled(messages.map(async (m) => {
2472
+ await outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey });
2473
+ recordOutboxEnqueue(this.meterProvider, outboxQueue, m.message);
2474
+ }))).filter((r) => r.status === "rejected").map((r) => r.reason);
2404
2475
  if (errors.length > 0) {
2405
2476
  logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
2406
2477
  activityId: activity.id.href,
@@ -2409,25 +2480,17 @@ var FederationImpl = class extends FederationBuilderImpl {
2409
2480
  if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
2410
2481
  throw errors[0];
2411
2482
  }
2412
- } else if (orderingKey != null) {
2413
- const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
2414
- const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
2415
- if (errors.length > 0) {
2416
- logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
2483
+ } else {
2484
+ try {
2485
+ await outboxQueue.enqueueMany(messages.map((m) => m.message));
2486
+ } catch (error) {
2487
+ logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
2417
2488
  activityId: activity.id.href,
2418
- errors
2489
+ error
2419
2490
  });
2420
- if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
2421
- throw errors[0];
2491
+ throw error;
2422
2492
  }
2423
- } else try {
2424
- await outboxQueue.enqueueMany(messages.map((m) => m.message));
2425
- } catch (error) {
2426
- logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
2427
- activityId: activity.id.href,
2428
- error
2429
- });
2430
- throw error;
2493
+ for (const m of messages) recordOutboxEnqueue(this.meterProvider, outboxQueue, m.message);
2431
2494
  }
2432
2495
  }
2433
2496
  fetch(request, options) {
@@ -3243,6 +3306,11 @@ var ContextImpl = class ContextImpl {
3243
3306
  };
3244
3307
  if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
3245
3308
  await this.federation.fanoutQueue.enqueue(message, { orderingKey: options.orderingKey });
3309
+ getFederationMetrics(this.federation.meterProvider).recordQueueTaskEnqueued({
3310
+ role: "fanout",
3311
+ queue: this.federation.fanoutQueue,
3312
+ activityType: message.activityType
3313
+ }, 0);
3246
3314
  return true;
3247
3315
  }
3248
3316
  async *getFollowers(identifier) {
@@ -3373,6 +3441,7 @@ var ContextImpl = class ContextImpl {
3373
3441
  kvPrefixes: this.federation.kvPrefixes,
3374
3442
  queue: this.federation.inboxQueue,
3375
3443
  span,
3444
+ meterProvider: this.federation.meterProvider,
3376
3445
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
3377
3446
  idempotencyStrategy: this.federation.idempotencyStrategy
3378
3447
  });
@@ -3622,8 +3691,10 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
3622
3691
  }
3623
3692
  const { outboxQueue } = ctx.federation;
3624
3693
  if (outboxQueue.enqueueMany == null || orderingKey != null) {
3625
- const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
3626
- const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
3694
+ const errors = (await Promise.allSettled(messages.map(async (m) => {
3695
+ await outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey });
3696
+ recordOutboxEnqueue(ctx.federation.meterProvider, outboxQueue, m.message);
3697
+ }))).filter((r) => r.status === "rejected").map((r) => r.reason);
3627
3698
  if (errors.length > 0) {
3628
3699
  logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
3629
3700
  activityId: ctx.activityId,
@@ -3632,14 +3703,17 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
3632
3703
  if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${ctx.activityId} to forward later.`);
3633
3704
  throw errors[0];
3634
3705
  }
3635
- } else try {
3636
- await outboxQueue.enqueueMany(messages.map((m) => m.message));
3637
- } catch (error) {
3638
- logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
3639
- activityId: ctx.activityId,
3640
- error
3641
- });
3642
- throw error;
3706
+ } else {
3707
+ try {
3708
+ await outboxQueue.enqueueMany(messages.map((m) => m.message));
3709
+ } catch (error) {
3710
+ logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
3711
+ activityId: ctx.activityId,
3712
+ error
3713
+ });
3714
+ throw error;
3715
+ }
3716
+ for (const m of messages) recordOutboxEnqueue(ctx.federation.meterProvider, outboxQueue, m.message);
3643
3717
  }
3644
3718
  return true;
3645
3719
  }