@fedify/fedify 2.3.0-dev.1347 → 2.3.0-dev.1361

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 (104) hide show
  1. package/dist/{assert-OguE97r2.mjs → assert-DikXweDx.mjs} +1 -1
  2. package/dist/{assert_instance_of-DBC5X09g.mjs → assert_instance_of-C4Ri6VuN.mjs} +1 -1
  3. package/dist/{assert_not_equals-DkVK8oqV.mjs → assert_not_equals--wG9hV7u.mjs} +1 -1
  4. package/dist/{assert_rejects-DN60FHPX.mjs → assert_rejects-DQP-q39h.mjs} +2 -2
  5. package/dist/{assert_strict_equals-XEgZAlrj.mjs → assert_strict_equals-Dmjbg-bA.mjs} +1 -1
  6. package/dist/{assert_throws-BOkhLGYc.mjs → assert_throws-4NwKEy2q.mjs} +1 -1
  7. package/dist/{builder-D-PxAS3Y.mjs → builder-Ec1dUgEm.mjs} +23 -3
  8. package/dist/codec-Bf-rTqks.mjs +94 -0
  9. package/dist/compat/mod.d.cts +1 -1
  10. package/dist/compat/mod.d.ts +1 -1
  11. package/dist/compat/outgoing-jsonld.test.mjs +3 -3
  12. package/dist/compat/public-audience.test.mjs +3 -3
  13. package/dist/compat/transformers.test.mjs +5 -5
  14. package/dist/{context-DVoTs_wM.mjs → context-BrIOaBSs.mjs} +7 -1
  15. package/dist/{context-BBVLF7lx.d.cts → context-BuGH_Vft.d.cts} +286 -70
  16. package/dist/{context-BU6jSQdo.d.ts → context-CLtZxCu6.d.ts} +285 -70
  17. package/dist/{deno-wajDuaHn.mjs → deno-C1j4CMgo.mjs} +1 -1
  18. package/dist/{docloader-Bin3zbMc.mjs → docloader-DLb-Mj7i.mjs} +2 -2
  19. package/dist/federation/builder.test.mjs +5 -5
  20. package/dist/federation/circuit-breaker.test.mjs +5 -5
  21. package/dist/federation/collection.test.mjs +3 -3
  22. package/dist/federation/handler.test.mjs +13 -13
  23. package/dist/federation/idempotency.test.mjs +6 -6
  24. package/dist/federation/inbox.test.mjs +3 -3
  25. package/dist/federation/keycache.test.mjs +5 -5
  26. package/dist/federation/kv.test.mjs +3 -3
  27. package/dist/federation/metrics.test.mjs +4 -4
  28. package/dist/federation/middleware.test.mjs +200 -19
  29. package/dist/federation/mod.cjs +1 -1
  30. package/dist/federation/mod.d.cts +3 -3
  31. package/dist/federation/mod.d.ts +3 -3
  32. package/dist/federation/mod.js +1 -1
  33. package/dist/federation/mq.test.mjs +5 -260
  34. package/dist/federation/negotiation.test.mjs +4 -4
  35. package/dist/federation/retry.test.mjs +3 -3
  36. package/dist/federation/router.test.mjs +5 -5
  37. package/dist/federation/send.test.mjs +10 -10
  38. package/dist/federation/tasks/codec.test.d.mts +2 -0
  39. package/dist/federation/tasks/codec.test.mjs +292 -0
  40. package/dist/federation/tasks/tasks.test.d.mts +2 -0
  41. package/dist/federation/tasks/tasks.test.mjs +651 -0
  42. package/dist/federation/temporal.test.mjs +4 -4
  43. package/dist/federation/webfinger.test.mjs +6 -6
  44. package/dist/{http-CsNVLfp4.js → http-1oEzWsNL.js} +1 -1
  45. package/dist/{http-BvFNt9BS.cjs → http-DwM39C9Q.cjs} +1 -1
  46. package/dist/{http-B6oaElbG.mjs → http-pFZqYnR0.mjs} +4 -4
  47. package/dist/{key-CA2BN_6m.mjs → key-E-05ikaC.mjs} +2 -2
  48. package/dist/{kv-cache-m3c0gmw5.js → kv-cache-CgchQxpw.js} +1 -1
  49. package/dist/{kv-cache-CRtUoUhG.mjs → kv-cache-D-OZCnQz.mjs} +1 -1
  50. package/dist/{kv-cache-N5a4Fotc.cjs → kv-cache-enboxEhN.cjs} +1 -1
  51. package/dist/{ld-RzyPOaQk.mjs → ld-Bi8DPgxi.mjs} +3 -3
  52. package/dist/{metrics-CZgP4M5B.mjs → metrics-BC8TM85p.mjs} +1 -1
  53. package/dist/{middleware-CYAFQiq3.mjs → middleware-6R3zHHW0.mjs} +182 -23
  54. package/dist/{middleware-e4yXLOXb.mjs → middleware-B81UTyWc.mjs} +1 -1
  55. package/dist/{middleware-Bm9ePti9.cjs → middleware-TZyBWL4B.cjs} +277 -10
  56. package/dist/{middleware-CX6zA2uu.js → middleware-bEYsEa2y.js} +277 -10
  57. package/dist/{mod-C0F6kvgS.d.cts → mod-DRokcHeU.d.cts} +1 -1
  58. package/dist/{mod-vPYVoa5n.d.ts → mod-r-1xOW_C.d.ts} +1 -1
  59. package/dist/mod.cjs +4 -4
  60. package/dist/mod.d.cts +4 -4
  61. package/dist/mod.d.ts +4 -4
  62. package/dist/mod.js +4 -4
  63. package/dist/mq-CvJAzRz5.mjs +260 -0
  64. package/dist/nodeinfo/client.test.mjs +3 -3
  65. package/dist/nodeinfo/handler.test.mjs +5 -5
  66. package/dist/nodeinfo/types.test.mjs +4 -4
  67. package/dist/otel/exporter.test.mjs +3 -3
  68. package/dist/{outgoing-jsonld-L_DbOaFe.mjs → outgoing-jsonld-BgFLCJQ_.mjs} +1 -1
  69. package/dist/{owner-CIShDQPu.mjs → owner-9bbtWYCS.mjs} +2 -2
  70. package/dist/{proof-BS5IKYw6.cjs → proof-B45zHTY3.cjs} +1 -1
  71. package/dist/{proof-FZEAEjWp.js → proof-CA5R6h5L.js} +1 -1
  72. package/dist/{proof-D95Hjyca.mjs → proof-DS0QOtP2.mjs} +5 -5
  73. package/dist/{send-3jxZz1Ub.mjs → send-CyGRAWkX.mjs} +3 -3
  74. package/dist/sig/accept.test.mjs +1 -1
  75. package/dist/sig/http.test.mjs +8 -8
  76. package/dist/sig/key.test.mjs +6 -6
  77. package/dist/sig/ld.test.mjs +7 -7
  78. package/dist/sig/mod.cjs +2 -2
  79. package/dist/sig/mod.js +2 -2
  80. package/dist/sig/owner.test.mjs +6 -6
  81. package/dist/sig/proof.test.mjs +8 -8
  82. package/dist/{std__assert-BBjXFNOb.mjs → std__assert-BTEgfoJo.mjs} +4 -4
  83. package/dist/{temporal-Db7_Kjkb.mjs → temporal-B82PdoA8.mjs} +1 -1
  84. package/dist/testing/mod.d.mts +378 -7
  85. package/dist/testing/mod.mjs +3 -2
  86. package/dist/testing-CjYPStvE.mjs +55 -0
  87. package/dist/utils/docloader.test.mjs +6 -6
  88. package/dist/utils/kv-cache.test.mjs +1 -1
  89. package/dist/utils/mod.cjs +1 -1
  90. package/dist/utils/mod.js +1 -1
  91. package/package.json +9 -7
  92. /package/dist/{accept-CPkZzmGN.mjs → accept-CceiKpCy.mjs} +0 -0
  93. /package/dist/{activity-listener-tztVvlNb.mjs → activity-listener-BeTGV3wc.mjs} +0 -0
  94. /package/dist/{assert_equals-C-ZRDbaf.mjs → assert_equals-Ew3jOFa3.mjs} +0 -0
  95. /package/dist/{circuit-breaker-CSWsyoef.mjs → circuit-breaker-hJBB6jwA.mjs} +0 -0
  96. /package/dist/{client-ByXmQhYD.mjs → client-B_A6mfn3.mjs} +0 -0
  97. /package/dist/{collection-Cc3DVAhE.mjs → collection-Dp5ky45w.mjs} +0 -0
  98. /package/dist/{keycache-BeU0LCII.mjs → keycache-CaOR6NYg.mjs} +0 -0
  99. /package/dist/{keys-DGu1NFwu.mjs → keys-C3kae-6B.mjs} +0 -0
  100. /package/dist/{kv-rV3vodCc.mjs → kv-x2IvBUyq.mjs} +0 -0
  101. /package/dist/{negotiation-DDstyBvc.mjs → negotiation-m_L2nyS3.mjs} +0 -0
  102. /package/dist/{public-audience-Cvbr2Gzt.mjs → public-audience-N3pyOx2p.mjs} +0 -0
  103. /package/dist/{retry-CXg_MBI-.mjs → retry-DI4O-zYl.mjs} +0 -0
  104. /package/dist/{types-J53Kw7so.mjs → types-BFowWFTT.mjs} +0 -0
@@ -1,10 +1,10 @@
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-wajDuaHn.mjs";
5
- import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-CZgP4M5B.mjs";
6
- import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPkZzmGN.mjs";
7
- import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-CA2BN_6m.mjs";
4
+ import { n as version, t as name } from "./deno-C1j4CMgo.mjs";
5
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BC8TM85p.mjs";
6
+ import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CceiKpCy.mjs";
7
+ import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-E-05ikaC.mjs";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { CryptographicKey } from "@fedify/vocab";
10
10
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-wajDuaHn.mjs";
5
- import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-CZgP4M5B.mjs";
4
+ import { n as version, t as name } from "./deno-C1j4CMgo.mjs";
5
+ import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-BC8TM85p.mjs";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { C as recordDocumentCache, d as validateCryptoKey, t as doubleKnock } from "./http-CsNVLfp4.js";
3
+ import { C as recordDocumentCache, d as validateCryptoKey, t as doubleKnock } from "./http-1oEzWsNL.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,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { p as recordDocumentCache } from "./metrics-CZgP4M5B.mjs";
4
+ import { p as recordDocumentCache } from "./metrics-BC8TM85p.mjs";
5
5
  import { getLogger } from "@logtape/logtape";
6
6
  import { preloadedContexts } from "@fedify/vocab-runtime";
7
7
  //#region src/utils/kv-cache.ts
@@ -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-BvFNt9BS.cjs");
4
+ const require_http = require("./http-DwM39C9Q.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,9 +1,9 @@
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-wajDuaHn.mjs";
5
- import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-CZgP4M5B.mjs";
6
- import { n as fetchKey, o as validateCryptoKey } from "./key-CA2BN_6m.mjs";
4
+ import { n as version, t as name } from "./deno-C1j4CMgo.mjs";
5
+ import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BC8TM85p.mjs";
6
+ import { n as fetchKey, o as validateCryptoKey } from "./key-E-05ikaC.mjs";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
9
9
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -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-wajDuaHn.mjs";
4
+ import { n as version, t as name } from "./deno-C1j4CMgo.mjs";
5
5
  import { metrics } from "@opentelemetry/api";
6
6
  import { FetchError } from "@fedify/vocab-runtime";
7
7
  //#region src/federation/metrics.ts
@@ -1,27 +1,28 @@
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-wajDuaHn.mjs";
5
- import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-CZgP4M5B.mjs";
6
- import { t as formatAcceptSignature } from "./accept-CPkZzmGN.mjs";
7
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-CA2BN_6m.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-B6oaElbG.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-Bin3zbMc.mjs";
10
- import { n as kvCache } from "./kv-cache-CRtUoUhG.mjs";
11
- import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-RzyPOaQk.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-CIShDQPu.mjs";
13
- import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-L_DbOaFe.mjs";
14
- import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-D95Hjyca.mjs";
15
- import { t as getNodeInfo } from "./client-ByXmQhYD.mjs";
16
- import { t as nodeInfoToJson } from "./types-J53Kw7so.mjs";
17
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-3jxZz1Ub.mjs";
18
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-D-PxAS3Y.mjs";
19
- import { t as CircuitBreaker } from "./circuit-breaker-CSWsyoef.mjs";
20
- import { t as buildCollectionSynchronizationHeader } from "./collection-Cc3DVAhE.mjs";
21
- import { t as KvKeyCache } from "./keycache-BeU0LCII.mjs";
22
- import { t as acceptsJsonLd } from "./negotiation-DDstyBvc.mjs";
23
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-Db7_Kjkb.mjs";
24
- import { t as createExponentialBackoffPolicy } from "./retry-CXg_MBI-.mjs";
4
+ import { n as version, t as name } from "./deno-C1j4CMgo.mjs";
5
+ import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-BC8TM85p.mjs";
6
+ import { t as formatAcceptSignature } from "./accept-CceiKpCy.mjs";
7
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-E-05ikaC.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-pFZqYnR0.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-DLb-Mj7i.mjs";
10
+ import { n as kvCache } from "./kv-cache-D-OZCnQz.mjs";
11
+ import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-Bi8DPgxi.mjs";
12
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-9bbtWYCS.mjs";
13
+ import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-BgFLCJQ_.mjs";
14
+ import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-DS0QOtP2.mjs";
15
+ import { t as getNodeInfo } from "./client-B_A6mfn3.mjs";
16
+ import { t as nodeInfoToJson } from "./types-BFowWFTT.mjs";
17
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CyGRAWkX.mjs";
18
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-Ec1dUgEm.mjs";
19
+ import { t as CircuitBreaker } from "./circuit-breaker-hJBB6jwA.mjs";
20
+ import { t as buildCollectionSynchronizationHeader } from "./collection-Dp5ky45w.mjs";
21
+ import { t as KvKeyCache } from "./keycache-CaOR6NYg.mjs";
22
+ import { t as acceptsJsonLd } from "./negotiation-m_L2nyS3.mjs";
23
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-B82PdoA8.mjs";
24
+ import { t as createExponentialBackoffPolicy } from "./retry-DI4O-zYl.mjs";
25
+ import { t as TaskCodec } from "./codec-Bf-rTqks.mjs";
25
26
  import { getLogger, withContext } from "@logtape/logtape";
26
27
  import { RouterError } from "@fedify/uri-template";
27
28
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
@@ -2409,9 +2410,12 @@ var FederationImpl = class extends FederationBuilderImpl {
2409
2410
  inboxQueue;
2410
2411
  outboxQueue;
2411
2412
  fanoutQueue;
2413
+ taskQueue;
2412
2414
  inboxQueueStarted;
2413
2415
  outboxQueueStarted;
2414
2416
  fanoutQueueStarted;
2417
+ taskQueueStarted;
2418
+ startedTaskQueues;
2415
2419
  manuallyStartQueue;
2416
2420
  origin;
2417
2421
  documentLoaderFactory;
@@ -2425,6 +2429,8 @@ var FederationImpl = class extends FederationBuilderImpl {
2425
2429
  skipSignatureVerification;
2426
2430
  outboxRetryPolicy;
2427
2431
  inboxRetryPolicy;
2432
+ taskRetryPolicy;
2433
+ taskQueueResolution;
2428
2434
  circuitBreaker;
2429
2435
  activityTransformers;
2430
2436
  _tracerProvider;
@@ -2470,14 +2476,17 @@ var FederationImpl = class extends FederationBuilderImpl {
2470
2476
  this.inboxQueue = void 0;
2471
2477
  this.outboxQueue = void 0;
2472
2478
  this.fanoutQueue = void 0;
2479
+ this.taskQueue = void 0;
2473
2480
  } else if ("enqueue" in options.queue && "listen" in options.queue) {
2474
2481
  this.inboxQueue = options.queue;
2475
2482
  this.outboxQueue = options.queue;
2476
2483
  this.fanoutQueue = options.queue;
2484
+ this.taskQueue = void 0;
2477
2485
  } else {
2478
2486
  this.inboxQueue = options.queue.inbox;
2479
2487
  this.outboxQueue = options.queue.outbox;
2480
2488
  this.fanoutQueue = options.queue.fanout;
2489
+ this.taskQueue = options.queue.task;
2481
2490
  }
2482
2491
  if (options.circuitBreaker !== false && this.outboxQueue != null) {
2483
2492
  this.circuitBreaker = new CircuitBreaker({
@@ -2501,6 +2510,8 @@ var FederationImpl = class extends FederationBuilderImpl {
2501
2510
  this.inboxQueueStarted = false;
2502
2511
  this.outboxQueueStarted = false;
2503
2512
  this.fanoutQueueStarted = false;
2513
+ this.taskQueueStarted = false;
2514
+ this.startedTaskQueues = /* @__PURE__ */ new Set();
2504
2515
  this.manuallyStartQueue = options.manuallyStartQueue ?? false;
2505
2516
  if (options.origin != null) if (typeof options.origin === "string") {
2506
2517
  if (!URL.canParse(options.origin) || !options.origin.match(/^https?:\/\//)) throw new TypeError(`Invalid origin: ${JSON.stringify(options.origin)}`);
@@ -2582,6 +2593,8 @@ var FederationImpl = class extends FederationBuilderImpl {
2582
2593
  this.inboxChallengePolicy = options.inboxChallengePolicy;
2583
2594
  this.outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy();
2584
2595
  this.inboxRetryPolicy = options.inboxRetryPolicy ?? createExponentialBackoffPolicy();
2596
+ this.taskRetryPolicy = options.taskRetryPolicy ?? createExponentialBackoffPolicy();
2597
+ this.taskQueueResolution = options.taskQueueResolution ?? "fallback";
2585
2598
  this.activityTransformers = options.activityTransformers ?? getDefaultActivityTransformers();
2586
2599
  this._tracerProvider = options.tracerProvider;
2587
2600
  if (benchmarkMode) {
@@ -2630,8 +2643,14 @@ var FederationImpl = class extends FederationBuilderImpl {
2630
2643
  _getTracer() {
2631
2644
  return this.tracerProvider.getTracer(name, version);
2632
2645
  }
2646
+ resolveTaskQueue(taskName) {
2647
+ const resolved = this.taskDefinitions.get(taskName)?.queue ?? this.taskQueue;
2648
+ if (resolved != null) return resolved;
2649
+ return this.taskQueueResolution === "strict" ? void 0 : this.outboxQueue;
2650
+ }
2633
2651
  async _startQueueInternal(ctxData, signal, queue) {
2634
- if (this.inboxQueue == null && this.outboxQueue == null) return;
2652
+ const hasDedicatedTaskQueue = [...this.taskDefinitions.values()].some((def) => def.queue != null);
2653
+ if (this.inboxQueue == null && this.outboxQueue == null && this.fanoutQueue == null && this.taskQueue == null && !hasDedicatedTaskQueue) return;
2635
2654
  const logger = getLogger([
2636
2655
  "fedify",
2637
2656
  "federation",
@@ -2653,6 +2672,26 @@ var FederationImpl = class extends FederationBuilderImpl {
2653
2672
  this.fanoutQueueStarted = true;
2654
2673
  promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2655
2674
  }
2675
+ if (this.taskQueue != null && this.taskQueue !== this.inboxQueue && this.taskQueue !== this.outboxQueue && this.taskQueue !== this.fanoutQueue && (queue == null || queue === "task") && !this.taskQueueStarted) {
2676
+ logger.debug("Starting a task worker.");
2677
+ this.taskQueueStarted = true;
2678
+ promises.push(this.taskQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2679
+ }
2680
+ if (queue == null || queue === "task") {
2681
+ const standardQueues = new Set([
2682
+ this.inboxQueue,
2683
+ this.outboxQueue,
2684
+ this.fanoutQueue,
2685
+ this.taskQueue
2686
+ ].filter((q) => q != null));
2687
+ for (const def of this.taskDefinitions.values()) {
2688
+ const taskQueue = def.queue;
2689
+ if (taskQueue == null || standardQueues.has(taskQueue) || this.startedTaskQueues.has(taskQueue)) continue;
2690
+ logger.debug("Starting a worker for a dedicated per-task queue.");
2691
+ this.startedTaskQueues.add(taskQueue);
2692
+ promises.push(taskQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2693
+ }
2694
+ }
2656
2695
  await Promise.all(promises);
2657
2696
  }
2658
2697
  processQueuedTask(contextData, message) {
@@ -2774,7 +2813,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2774
2813
  }
2775
2814
  });
2776
2815
  });
2777
- }
2816
+ } else if (message.type === "task") await this.#listenTaskMessage(contextData, message);
2778
2817
  });
2779
2818
  }
2780
2819
  async #listenFanoutMessage(data, message) {
@@ -3338,6 +3377,77 @@ var FederationImpl = class extends FederationBuilderImpl {
3338
3377
  listenerSpan.end();
3339
3378
  });
3340
3379
  }
3380
+ async #listenTaskMessage(contextData, message) {
3381
+ const logger = getLogger([
3382
+ "fedify",
3383
+ "federation",
3384
+ "task"
3385
+ ]);
3386
+ const def = this.taskDefinitions.get(message.taskName);
3387
+ if (def == null) {
3388
+ logger.warn("Received a custom task {taskName} with no registered handler; dropping.", { taskName: message.taskName });
3389
+ return;
3390
+ }
3391
+ const context = this.#createContext(new URL(message.baseUrl), contextData);
3392
+ let data;
3393
+ try {
3394
+ data = await context.codec.decode(def.schema, message.data);
3395
+ } catch (error) {
3396
+ logger.error("Custom task {taskName} payload could not be decoded or validated; dropping:\n{error}", {
3397
+ taskName: message.taskName,
3398
+ error
3399
+ });
3400
+ return;
3401
+ }
3402
+ try {
3403
+ await def.handler(context, data);
3404
+ } catch (error) {
3405
+ if (def.onError != null) try {
3406
+ await def.onError(context, error, data);
3407
+ } catch (onErrorError) {
3408
+ logger.error("onError for custom task {taskName} threw:\n{error}", {
3409
+ taskName: message.taskName,
3410
+ error: onErrorError
3411
+ });
3412
+ }
3413
+ const queue = this.resolveTaskQueue(def.name);
3414
+ if (queue?.nativeRetrial) throw error;
3415
+ const retryPolicy = def.retryPolicy ?? this.taskRetryPolicy;
3416
+ let elapsedTime = Temporal.Duration.from({ seconds: 0 });
3417
+ try {
3418
+ elapsedTime = Temporal.Instant.from(message.started).until(Temporal.Now.instant());
3419
+ } catch (parseError) {
3420
+ logger.error("Custom task {taskName} has an unparsable started time {started}; treating elapsedTime as zero:\n{error}", {
3421
+ taskName: message.taskName,
3422
+ started: message.started,
3423
+ error: parseError
3424
+ });
3425
+ }
3426
+ const delay = retryPolicy({
3427
+ elapsedTime,
3428
+ attempts: message.attempt
3429
+ });
3430
+ if (delay != null && queue != null) {
3431
+ logger.error("Custom task {taskName} failed (attempt #{attempt}); retry...:\n{error}", {
3432
+ taskName: message.taskName,
3433
+ attempt: message.attempt,
3434
+ error
3435
+ });
3436
+ const retryMessage = {
3437
+ ...message,
3438
+ attempt: message.attempt + 1
3439
+ };
3440
+ await queue.enqueue(retryMessage, {
3441
+ delay: clampNegativeDelay(delay),
3442
+ orderingKey: message.orderingKey
3443
+ });
3444
+ } else logger.error("Custom task {taskName} failed after {attempt} attempts; giving up:\n{error}", {
3445
+ taskName: message.taskName,
3446
+ attempt: message.attempt,
3447
+ error
3448
+ });
3449
+ }
3450
+ }
3341
3451
  startQueue(contextData, options = {}) {
3342
3452
  return this._startQueueInternal(contextData, options.signal, options.queue);
3343
3453
  }
@@ -3914,6 +4024,7 @@ var ContextImpl = class ContextImpl {
3914
4024
  documentLoader;
3915
4025
  contextLoader;
3916
4026
  invokedFromActorKeyPairsDispatcher;
4027
+ #codec;
3917
4028
  constructor({ url, federation, data, documentLoader, contextLoader, invokedFromActorKeyPairsDispatcher }) {
3918
4029
  this.url = url;
3919
4030
  this.federation = federation;
@@ -3922,6 +4033,15 @@ var ContextImpl = class ContextImpl {
3922
4033
  this.contextLoader = contextLoader;
3923
4034
  this.invokedFromActorKeyPairsDispatcher = invokedFromActorKeyPairsDispatcher;
3924
4035
  }
4036
+ /**
4037
+ * A {@link TaskCodec} bound to this context's loaders, used to encode
4038
+ * and decode custom task payloads. Lazily created and cached so a context
4039
+ * that never enqueues or dispatches a task pays nothing.
4040
+ * @internal
4041
+ */
4042
+ get codec() {
4043
+ return this.#codec ??= new TaskCodec(this);
4044
+ }
3925
4045
  clone(data) {
3926
4046
  return new ContextImpl({
3927
4047
  url: this.url,
@@ -4240,6 +4360,45 @@ var ContextImpl = class ContextImpl {
4240
4360
  allowPrivateAddress: this.federation.allowPrivateAddress
4241
4361
  });
4242
4362
  }
4363
+ async enqueueTask(task, data, options = {}) {
4364
+ await this.#enqueueTasks(task, [data], options);
4365
+ }
4366
+ async enqueueTaskMany(task, payloads, options = {}) {
4367
+ await this.#enqueueTasks(task, payloads, options);
4368
+ }
4369
+ async #enqueueTasks(task, items, options) {
4370
+ const def = this.federation.taskDefinitions.get(task.name);
4371
+ if (def == null || def.handle !== task) throw new TypeError(`Task ${JSON.stringify(task.name)} is not defined on this federation; pass a handle returned by its defineTask().`);
4372
+ const queue = this.federation.resolveTaskQueue(task.name);
4373
+ if (queue == null) throw new TypeError("No message queue is configured for tasks; pass `queue` to createFederation() or to defineTask().");
4374
+ if (items.length < 1) return;
4375
+ const delay = options.delay == null ? void 0 : Temporal.Duration.from(options.delay);
4376
+ const messages = await Promise.all(items.map(this.#encodeTaskMessage(task, options)));
4377
+ if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
4378
+ const enqueueOptions = {
4379
+ delay,
4380
+ orderingKey: options.orderingKey
4381
+ };
4382
+ if (messages.length === 1) await queue.enqueue(messages[0], enqueueOptions);
4383
+ else if (queue.enqueueMany != null) await queue.enqueueMany(messages, enqueueOptions);
4384
+ else await Promise.all(messages.map((m) => queue.enqueue(m, enqueueOptions)));
4385
+ }
4386
+ #encodeTaskMessage = (task, options) => async (data) => {
4387
+ const encoded = await this.codec.encode(task.schema, data);
4388
+ const carrier = {};
4389
+ propagation.inject(context.active(), carrier);
4390
+ return {
4391
+ type: "task",
4392
+ id: crypto.randomUUID(),
4393
+ baseUrl: this.origin,
4394
+ taskName: task.name,
4395
+ data: encoded,
4396
+ started: Temporal.Now.instant().toString(),
4397
+ attempt: 0,
4398
+ orderingKey: options.orderingKey,
4399
+ traceContext: carrier
4400
+ };
4401
+ };
4243
4402
  sendActivity(sender, recipients, activity, options = {}) {
4244
4403
  return this.tracerProvider.getTracer(name, version).startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
4245
4404
  kind: this.federation.outboxQueue == null || options.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
@@ -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-CYAFQiq3.mjs";
4
+ import { n as FederationImpl } from "./middleware-6R3zHHW0.mjs";
5
5
  export { FederationImpl };