@fedify/fedify 2.4.0-dev.1508 → 2.4.0-dev.1531

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 (109) hide show
  1. package/README.md +0 -4
  2. package/dist/{assert-DvVHoIZ0.mjs → assert-OguE97r2.mjs} +1 -1
  3. package/dist/{assert_instance_of-CxoC8bVq.mjs → assert_instance_of-DBC5X09g.mjs} +1 -1
  4. package/dist/{assert_not_equals-C8vcTTA3.mjs → assert_not_equals-DkVK8oqV.mjs} +1 -1
  5. package/dist/{assert_rejects-DAdaaIWM.mjs → assert_rejects-DN60FHPX.mjs} +2 -2
  6. package/dist/{assert_strict_equals-BzqyKuYL.mjs → assert_strict_equals-XEgZAlrj.mjs} +1 -1
  7. package/dist/{assert_throws-zN79lgIC.mjs → assert_throws-BOkhLGYc.mjs} +1 -1
  8. package/dist/{builder-DlWCek6Z.mjs → builder-CmQLlEE1.mjs} +3 -23
  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-CYF8X0ft.d.cts → context-BBVLF7lx.d.cts} +272 -543
  15. package/dist/{context-BF5B4ZDk.d.ts → context-BU6jSQdo.d.ts} +272 -542
  16. package/dist/{context-BBRTgkrs.mjs → context-DVoTs_wM.mjs} +2 -8
  17. package/dist/{deno-nexucTAX.mjs → deno-bSDsva_4.mjs} +1 -1
  18. package/dist/{docloader-DAdEN549.mjs → docloader-DlmmTFJc.mjs} +3 -3
  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 +19 -200
  29. package/dist/federation/mod.cjs +259 -3
  30. package/dist/federation/mod.d.cts +4 -4
  31. package/dist/federation/mod.d.ts +4 -4
  32. package/dist/federation/mod.js +257 -1
  33. package/dist/federation/mq.test.mjs +261 -103
  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/temporal.test.mjs +4 -4
  39. package/dist/federation/webfinger.test.mjs +6 -6
  40. package/dist/{http-inQqS3yx.mjs → http-DwsK1LoE.mjs} +4 -4
  41. package/dist/{http-BCj9dlA_.cjs → http-bsrB-Tun.cjs} +1 -1
  42. package/dist/{http-Dv3147TL.js → http-yVXJ4RhY.js} +1 -1
  43. package/dist/{key-CGrr6-I2.mjs → key-C0aqQKRk.mjs} +2 -2
  44. package/dist/{kv-cache-C3qkFkbt.mjs → kv-cache-D3EQwzQ4.mjs} +1 -1
  45. package/dist/{kv-cache-c8X6svwE.cjs → kv-cache-Dv62PM2B.cjs} +1 -1
  46. package/dist/{kv-cache-C2oTEXyb.js → kv-cache-M2xxXg9M.js} +1 -1
  47. package/dist/{ld-fnWaNT8y.mjs → ld-CBIxjtov.mjs} +3 -3
  48. package/dist/{metrics-C5hMINAa.mjs → metrics-CwNvxtP6.mjs} +1 -1
  49. package/dist/{middleware-Dl2nyVgB.mjs → middleware-BWi34Ga3.mjs} +46 -306
  50. package/dist/{middleware-vQ_ZpgcX.js → middleware-BpMbjN9m.js} +31 -679
  51. package/dist/{middleware-DeVzbg1I.cjs → middleware-C27Pdo18.cjs} +30 -690
  52. package/dist/{middleware-CQlq6ykI.mjs → middleware-DiTi3jC5.mjs} +1 -1
  53. package/dist/{mod-BHEB3xhE.d.cts → mod-C0F6kvgS.d.cts} +1 -1
  54. package/dist/{mod-4WGAuR6X.d.ts → mod-vPYVoa5n.d.ts} +1 -1
  55. package/dist/mod.cjs +6 -6
  56. package/dist/mod.d.cts +5 -5
  57. package/dist/mod.d.ts +5 -5
  58. package/dist/mod.js +5 -5
  59. package/dist/{mq-DXMt_qCY.d.cts → mq-D-nlpY04.d.ts} +0 -34
  60. package/dist/{mq-B5_hohs7.d.ts → mq-D8uSFzxe.d.cts} +0 -34
  61. package/dist/nodeinfo/client.test.mjs +3 -3
  62. package/dist/nodeinfo/handler.test.mjs +5 -5
  63. package/dist/nodeinfo/types.test.mjs +4 -4
  64. package/dist/otel/exporter.test.mjs +3 -3
  65. package/dist/{outgoing-jsonld-BNL8AC14.mjs → outgoing-jsonld-L_DbOaFe.mjs} +1 -1
  66. package/dist/{owner-Bq2eZyO_.mjs → owner-SuWJf5wy.mjs} +2 -2
  67. package/dist/{proof-Buz7I8wj.cjs → proof-BclG-T7h.cjs} +1 -1
  68. package/dist/{proof-DZCjcFCd.mjs → proof-CZI5KQdk.mjs} +5 -5
  69. package/dist/{proof-CTG9azxN.js → proof-DMWr-n3N.js} +1 -1
  70. package/dist/{send-B253S5gN.mjs → send-1EADALaf.mjs} +3 -3
  71. package/dist/sig/accept.test.mjs +1 -1
  72. package/dist/sig/http.test.mjs +8 -8
  73. package/dist/sig/key.test.mjs +6 -6
  74. package/dist/sig/ld.test.mjs +7 -7
  75. package/dist/sig/mod.cjs +2 -2
  76. package/dist/sig/mod.js +2 -2
  77. package/dist/sig/owner.test.mjs +6 -6
  78. package/dist/sig/proof.test.mjs +8 -8
  79. package/dist/{std__assert-Dh6uLf_q.mjs → std__assert-BBjXFNOb.mjs} +4 -4
  80. package/dist/{temporal-d6TshGjq.mjs → temporal-GLaGoMUR.mjs} +1 -1
  81. package/dist/testing/mod.d.mts +8 -1037
  82. package/dist/testing/mod.mjs +2 -3
  83. package/dist/utils/docloader.test.mjs +6 -6
  84. package/dist/utils/kv-cache.test.mjs +1 -1
  85. package/dist/utils/mod.cjs +1 -1
  86. package/dist/utils/mod.js +1 -1
  87. package/package.json +7 -9
  88. package/dist/codec-CmlPqjNX.mjs +0 -103
  89. package/dist/federation/tasks/codec.test.d.mts +0 -2
  90. package/dist/federation/tasks/codec.test.mjs +0 -292
  91. package/dist/federation/tasks/enqueue.test.d.mts +0 -2
  92. package/dist/federation/tasks/enqueue.test.mjs +0 -992
  93. package/dist/federation/tasks/tasks.test.d.mts +0 -2
  94. package/dist/federation/tasks/tasks.test.mjs +0 -555
  95. package/dist/mq-03vS-C9P.mjs +0 -276
  96. package/dist/testing-Dy-WhqpN.mjs +0 -77
  97. /package/dist/{accept-CgDcxvjV.mjs → accept-CPkZzmGN.mjs} +0 -0
  98. /package/dist/{activity-listener-BeTGV3wc.mjs → activity-listener-tztVvlNb.mjs} +0 -0
  99. /package/dist/{assert_equals-PBVKNMJd.mjs → assert_equals-C-ZRDbaf.mjs} +0 -0
  100. /package/dist/{circuit-breaker-hJBB6jwA.mjs → circuit-breaker-CSWsyoef.mjs} +0 -0
  101. /package/dist/{client-B_A6mfn3.mjs → client-ByXmQhYD.mjs} +0 -0
  102. /package/dist/{collection-Dp5ky45w.mjs → collection-Cc3DVAhE.mjs} +0 -0
  103. /package/dist/{keycache-CaOR6NYg.mjs → keycache-BeU0LCII.mjs} +0 -0
  104. /package/dist/{keys-CSYsOMFG.mjs → keys-DGu1NFwu.mjs} +0 -0
  105. /package/dist/{kv-CIvR3Non.mjs → kv-rV3vodCc.mjs} +0 -0
  106. /package/dist/{negotiation-m_L2nyS3.mjs → negotiation-DDstyBvc.mjs} +0 -0
  107. /package/dist/{public-audience-c9zmYKgA.mjs → public-audience-Cvbr2Gzt.mjs} +0 -0
  108. /package/dist/{retry-DI4O-zYl.mjs → retry-CXg_MBI-.mjs} +0 -0
  109. /package/dist/{types-BFowWFTT.mjs → types-J53Kw7so.mjs} +0 -0
@@ -1,41 +1,39 @@
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-nexucTAX.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-C5hMINAa.mjs";
6
- import { t as formatAcceptSignature } from "./accept-CgDcxvjV.mjs";
7
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-CGrr6-I2.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-inQqS3yx.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-DAdEN549.mjs";
10
- import { n as kvCache } from "./kv-cache-C3qkFkbt.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-fnWaNT8y.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-Bq2eZyO_.mjs";
13
- import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-BNL8AC14.mjs";
14
- import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-DZCjcFCd.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-B253S5gN.mjs";
18
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-DlWCek6Z.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-d6TshGjq.mjs";
24
- import { t as createExponentialBackoffPolicy } from "./retry-DI4O-zYl.mjs";
25
- import { t as TaskCodec } from "./codec-CmlPqjNX.mjs";
26
- import { n as ParallelMessageQueue } from "./mq-03vS-C9P.mjs";
4
+ import { n as version, t as name } from "./deno-bSDsva_4.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-CwNvxtP6.mjs";
6
+ import { t as formatAcceptSignature } from "./accept-CPkZzmGN.mjs";
7
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-C0aqQKRk.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-DwsK1LoE.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-DlmmTFJc.mjs";
10
+ import { n as kvCache } from "./kv-cache-D3EQwzQ4.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-CBIxjtov.mjs";
12
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-SuWJf5wy.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-CZI5KQdk.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-1EADALaf.mjs";
18
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-CmQLlEE1.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-GLaGoMUR.mjs";
24
+ import { t as createExponentialBackoffPolicy } from "./retry-CXg_MBI-.mjs";
27
25
  import { getLogger, withContext } from "@logtape/logtape";
28
26
  import { RouterError } from "@fedify/uri-template";
29
27
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
30
28
  import { lookupWebFinger } from "@fedify/webfinger";
31
29
  import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "@opentelemetry/api";
32
- import { uniq } from "es-toolkit";
33
30
  import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
34
31
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
32
+ import { uniq } from "es-toolkit";
35
33
  import { DataPointType, MeterProvider as MeterProvider$1, MetricReader } from "@opentelemetry/sdk-metrics";
36
34
  import { domainToASCII } from "node:url";
37
35
  //#region src/compat/transformers.ts
38
- const logger$2 = getLogger([
36
+ const logger$1 = getLogger([
39
37
  "fedify",
40
38
  "compat",
41
39
  "transformers"
@@ -61,7 +59,7 @@ const logger$2 = getLogger([
61
59
  function autoIdAssigner(activity, context) {
62
60
  if (activity.id != null) return activity;
63
61
  const id = new URL(`/#${activity.constructor.name}/${crypto.randomUUID()}`, context.origin);
64
- logger$2.warn("As the activity to send does not have an id, a new id {id} has been generated for it. However, it is recommended to explicitly set the id for the activity.", { id: id.href });
62
+ logger$1.warn("As the activity to send does not have an id, a new id {id} has been generated for it. However, it is recommended to explicitly set the id for the activity.", { id: id.href });
65
63
  return activity.clone({ id });
66
64
  }
67
65
  /**
@@ -2095,160 +2093,6 @@ const MIN_COMPONENTS = [
2095
2093
  "@authority"
2096
2094
  ];
2097
2095
  //#endregion
2098
- //#region src/federation/tasks/enqueue.ts
2099
- /**
2100
- * The enqueue pipeline for custom background tasks. `ContextImpl.enqueueTask`
2101
- * and `ContextImpl.enqueueTaskMany` delegate to {@link enqueueTasks} so the
2102
- * handle validation, deduplication planning, payload encoding, and queue
2103
- * dispatch live in one cohesive place instead of one oversized method.
2104
- *
2105
- * @module
2106
- */
2107
- /**
2108
- * Validates the task handle, plans deduplication, encodes every payload, then
2109
- * dispatches the resulting messages to the queue. A single item flows through
2110
- * the same pipeline as a batch, so {@link Context.enqueueTask} and
2111
- * {@link Context.enqueueTaskMany} share one implementation.
2112
- * @template TContextData The context data to pass to the {@link Context}.
2113
- * @template TData The type of the task payload, inferred from the task's schema.
2114
- * @param ctx The enqueueing dependencies assembled by `ContextImpl`.
2115
- * @param task The handle returned by `defineTask()`.
2116
- * @param items The payloads to enqueue, in order.
2117
- * @param options The enqueue options governing delay, ordering, and dedup.
2118
- * @internal
2119
- */
2120
- const enqueueTasks = (ctx) => async function(task, items, options) {
2121
- const def = ctx.federation.taskDefinitions.get(task.name);
2122
- 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().`);
2123
- const queue = ctx.federation.resolveTaskQueue(task.name);
2124
- if (queue == null) throw new TypeError("No message queue is configured for tasks; pass `queue` to createFederation() or to defineTask().");
2125
- if (items.length < 1) return;
2126
- const plan = planDeduplication(ctx, queue, task.name, options, items.length);
2127
- const messages = await Promise.all(items.map(encodeTaskMessage(ctx.codec, ctx.origin, task, options)));
2128
- const claim = await claimDeduplication(ctx, plan, task.name);
2129
- if (!claim.proceed) return;
2130
- if (!ctx.federation.manuallyStartQueue) ctx.federation._startQueueInternal(ctx.data);
2131
- try {
2132
- await dispatch(queue, messages, {
2133
- delay: getDurationIfDefined(options.delay),
2134
- orderingKey: options.orderingKey,
2135
- deduplicationKey: claim.forwardedDeduplicationKey
2136
- });
2137
- } catch (error) {
2138
- if (claim.rollback != null) try {
2139
- await claim.rollback();
2140
- } catch (rollbackError) {
2141
- logger$1.warn("Failed to roll back the deduplication marker for task {taskName} after a failed enqueue; it will expire by TTL. {rollbackError}", {
2142
- taskName: task.name,
2143
- rollbackError
2144
- });
2145
- }
2146
- throw error;
2147
- }
2148
- };
2149
- const getDurationIfDefined = (item) => item == null ? void 0 : Temporal.Duration.from(item);
2150
- /**
2151
- * Decides how a `deduplicationKey` (if any) is honored: forwarded to a native
2152
- * queue, claimed via `cas`, or—when neither is available—dropped or rejected
2153
- * per the federation's `taskDeduplicationFallback`. Throws the fail-fast
2154
- * `TypeError`s so they precede the encode.
2155
- */
2156
- function planDeduplication(ctx, queue, taskName, options, itemCount) {
2157
- if (options.deduplicationKey == null) return { kind: "none" };
2158
- const key = options.deduplicationKey;
2159
- const native = queue.nativeDeduplication === true;
2160
- const canCas = ctx.federation.kv.cas != null;
2161
- const canBatchAtomically = queue.enqueueMany != null && !(queue instanceof ParallelMessageQueue && queue.queue.enqueueMany == null);
2162
- if (itemCount > 1 && !canBatchAtomically && (native || canCas)) throw new TypeError(`Task ${JSON.stringify(taskName)} was enqueued as a batch with a deduplicationKey, but its message queue does not implement enqueueMany; a multi-item batch cannot be deduplicated atomically without it. Implement enqueueMany on the queue, or enqueue the tasks individually with enqueueTask().`);
2163
- if (native) return {
2164
- kind: "native",
2165
- key
2166
- };
2167
- if (canCas) return {
2168
- kind: "cas",
2169
- key
2170
- };
2171
- if (ctx.federation.taskDeduplicationFallback === "closed") throw new TypeError("deduplicationKey was set but the message queue does not declare nativeDeduplication and the key-value store exposes no conditional write (cas); set taskDeduplicationFallback to \"open\" to proceed without deduplication, or use a backend that supports it.");
2172
- return {
2173
- kind: "open",
2174
- key
2175
- };
2176
- }
2177
- /**
2178
- * Executes the planned deduplication once the payloads are encoded. A native
2179
- * plan forwards its key to the queue; a `cas` plan claims the marker and stops
2180
- * the enqueue when it loses the race; an `open` plan logs and proceeds.
2181
- * @returns Whether to proceed, and the key (if any) to forward to the queue.
2182
- */
2183
- async function claimDeduplication(ctx, plan, taskName) {
2184
- switch (plan.kind) {
2185
- case "native": return {
2186
- proceed: true,
2187
- forwardedDeduplicationKey: plan.key
2188
- };
2189
- case "cas": {
2190
- const cacheKey = [...ctx.federation.kvPrefixes.taskDeduplication, plan.key];
2191
- const token = crypto.randomUUID();
2192
- if (!await ctx.federation.kv.cas(cacheKey, void 0, token, { ttl: ctx.federation.taskDeduplicationTtl })) return { proceed: false };
2193
- return {
2194
- proceed: true,
2195
- rollback: async () => {
2196
- await ctx.federation.kv.cas(cacheKey, token, void 0);
2197
- }
2198
- };
2199
- }
2200
- case "open": logger$1.debug("deduplicationKey {deduplicationKey} for task {taskName} ignored: the message queue declares no nativeDeduplication and the key-value store has no cas; proceeding (taskDeduplicationFallback is \"open\").", {
2201
- deduplicationKey: plan.key,
2202
- taskName
2203
- });
2204
- case "none": return { proceed: true };
2205
- default: throw new TypeError(`Unknown deduplication plan: ${JSON.stringify(plan)}`);
2206
- }
2207
- }
2208
- /**
2209
- * Sends the encoded messages to the queue, picking the bulk path when the
2210
- * queue implements `enqueueMany` and otherwise fanning out parallel single
2211
- * enqueues. The fan-out drops `deduplicationKey`, which is only ever set for a
2212
- * native plan that the bulk paths already cover.
2213
- */
2214
- async function dispatch(queue, messages, options) {
2215
- if (messages.length === 1) await queue.enqueue(messages[0], options);
2216
- else if (queue.enqueueMany != null) await queue.enqueueMany(messages, options);
2217
- else {
2218
- const fanoutOptions = {
2219
- delay: options.delay,
2220
- orderingKey: options.orderingKey
2221
- };
2222
- await Promise.all(messages.map((m) => queue.enqueue(m, fanoutOptions)));
2223
- }
2224
- }
2225
- /**
2226
- * Builds the per-payload encoder: validates and serializes the payload, then
2227
- * stamps the message envelope with a fresh id, the context's origin, and the
2228
- * active trace context. Curried so the batch encode reuses one bound encoder.
2229
- */
2230
- const encodeTaskMessage = (codec, origin, task, options) => async (data) => {
2231
- const encoded = await codec.encode(task.schema, data);
2232
- const carrier = {};
2233
- propagation.inject(context.active(), carrier);
2234
- return {
2235
- type: "task",
2236
- id: crypto.randomUUID(),
2237
- baseUrl: origin,
2238
- taskName: task.name,
2239
- data: encoded,
2240
- started: Temporal.Now.instant().toString(),
2241
- attempt: 0,
2242
- orderingKey: options.orderingKey,
2243
- traceContext: carrier
2244
- };
2245
- };
2246
- const logger$1 = getLogger([
2247
- "fedify",
2248
- "federation",
2249
- "task"
2250
- ]);
2251
- //#endregion
2252
2096
  //#region src/federation/webfinger.ts
2253
2097
  const logger = getLogger([
2254
2098
  "fedify",
@@ -2574,8 +2418,9 @@ var FederationImpl = class extends FederationBuilderImpl {
2574
2418
  inboxQueue;
2575
2419
  outboxQueue;
2576
2420
  fanoutQueue;
2577
- taskQueue;
2578
- startedQueues;
2421
+ inboxQueueStarted;
2422
+ outboxQueueStarted;
2423
+ fanoutQueueStarted;
2579
2424
  manuallyStartQueue;
2580
2425
  origin;
2581
2426
  documentLoaderFactory;
@@ -2589,10 +2434,6 @@ var FederationImpl = class extends FederationBuilderImpl {
2589
2434
  skipSignatureVerification;
2590
2435
  outboxRetryPolicy;
2591
2436
  inboxRetryPolicy;
2592
- taskRetryPolicy;
2593
- taskQueueResolution;
2594
- taskDeduplicationTtl;
2595
- taskDeduplicationFallback;
2596
2437
  circuitBreaker;
2597
2438
  activityTransformers;
2598
2439
  _tracerProvider;
@@ -2632,24 +2473,20 @@ var FederationImpl = class extends FederationBuilderImpl {
2632
2473
  httpMessageSignaturesSpec: ["_fedify", "httpMessageSignaturesSpec"],
2633
2474
  acceptSignatureNonce: ["_fedify", "acceptSignatureNonce"],
2634
2475
  circuitBreaker: ["_fedify", "circuit"],
2635
- taskDeduplication: ["_fedify", "taskDeduplication"],
2636
2476
  ...options.kvPrefixes ?? {}
2637
2477
  };
2638
2478
  if (options.queue == null) {
2639
2479
  this.inboxQueue = void 0;
2640
2480
  this.outboxQueue = void 0;
2641
2481
  this.fanoutQueue = void 0;
2642
- this.taskQueue = void 0;
2643
2482
  } else if ("enqueue" in options.queue && "listen" in options.queue) {
2644
2483
  this.inboxQueue = options.queue;
2645
2484
  this.outboxQueue = options.queue;
2646
2485
  this.fanoutQueue = options.queue;
2647
- this.taskQueue = void 0;
2648
2486
  } else {
2649
2487
  this.inboxQueue = options.queue.inbox;
2650
2488
  this.outboxQueue = options.queue.outbox;
2651
2489
  this.fanoutQueue = options.queue.fanout;
2652
- this.taskQueue = options.queue.task;
2653
2490
  }
2654
2491
  if (options.circuitBreaker !== false && this.outboxQueue != null) {
2655
2492
  this.circuitBreaker = new CircuitBreaker({
@@ -2670,7 +2507,9 @@ var FederationImpl = class extends FederationBuilderImpl {
2670
2507
  ]).warn("The configured key-value store does not support CAS; outbound delivery circuit breaker updates may race under concurrent workers.");
2671
2508
  }
2672
2509
  }
2673
- this.startedQueues = /* @__PURE__ */ new Set();
2510
+ this.inboxQueueStarted = false;
2511
+ this.outboxQueueStarted = false;
2512
+ this.fanoutQueueStarted = false;
2674
2513
  this.manuallyStartQueue = options.manuallyStartQueue ?? false;
2675
2514
  if (options.origin != null) if (typeof options.origin === "string") {
2676
2515
  if (!URL.canParse(options.origin) || !options.origin.match(/^https?:\/\//)) throw new TypeError(`Invalid origin: ${JSON.stringify(options.origin)}`);
@@ -2752,10 +2591,6 @@ var FederationImpl = class extends FederationBuilderImpl {
2752
2591
  this.inboxChallengePolicy = options.inboxChallengePolicy;
2753
2592
  this.outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy();
2754
2593
  this.inboxRetryPolicy = options.inboxRetryPolicy ?? createExponentialBackoffPolicy();
2755
- this.taskRetryPolicy = options.taskRetryPolicy ?? createExponentialBackoffPolicy();
2756
- this.taskQueueResolution = options.taskQueueResolution ?? "fallback";
2757
- this.taskDeduplicationTtl = Temporal.Duration.from(options.taskDeduplicationTtl ?? { hours: 1 });
2758
- this.taskDeduplicationFallback = options.taskDeduplicationFallback ?? "open";
2759
2594
  this.activityTransformers = options.activityTransformers ?? getDefaultActivityTransformers();
2760
2595
  this._tracerProvider = options.tracerProvider;
2761
2596
  if (benchmarkMode) {
@@ -2804,33 +2639,28 @@ var FederationImpl = class extends FederationBuilderImpl {
2804
2639
  _getTracer() {
2805
2640
  return this.tracerProvider.getTracer(name, version);
2806
2641
  }
2807
- resolveTaskQueue(taskName) {
2808
- const resolved = this.taskDefinitions.get(taskName)?.queue ?? this.taskQueue;
2809
- if (resolved != null) return resolved;
2810
- return this.taskQueueResolution === "strict" ? void 0 : this.outboxQueue;
2811
- }
2812
2642
  async _startQueueInternal(ctxData, signal, queue) {
2813
- const taskQueue = this.taskQueue ?? (this.taskQueueResolution === "fallback" ? this.outboxQueue : void 0);
2814
- const customQueues = this.taskDefinitions.values().map((def) => ["task", def.queue]);
2815
- const targets = [
2816
- ["inbox", this.inboxQueue],
2817
- ["outbox", this.outboxQueue],
2818
- ["fanout", this.fanoutQueue],
2819
- ["task", taskQueue],
2820
- ...customQueues
2821
- ];
2643
+ if (this.inboxQueue == null && this.outboxQueue == null) return;
2822
2644
  const logger = getLogger([
2823
2645
  "fedify",
2824
2646
  "federation",
2825
2647
  "queue"
2826
2648
  ]);
2827
2649
  const promises = [];
2828
- for (const [role, target] of targets) {
2829
- if (target == null || !(queue == null || queue === role)) continue;
2830
- if (this.startedQueues.has(target)) continue;
2831
- this.startedQueues.add(target);
2832
- logger.debug("Starting a {role} queue worker.", { role });
2833
- promises.push(target.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2650
+ if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
2651
+ logger.debug("Starting an inbox task worker.");
2652
+ this.inboxQueueStarted = true;
2653
+ promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2654
+ }
2655
+ if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
2656
+ logger.debug("Starting an outbox task worker.");
2657
+ this.outboxQueueStarted = true;
2658
+ promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2659
+ }
2660
+ if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
2661
+ logger.debug("Starting a fanout task worker.");
2662
+ this.fanoutQueueStarted = true;
2663
+ promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2834
2664
  }
2835
2665
  await Promise.all(promises);
2836
2666
  }
@@ -2953,7 +2783,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2953
2783
  }
2954
2784
  });
2955
2785
  });
2956
- } else if (message.type === "task") await this.#listenTaskMessage(contextData, message);
2786
+ }
2957
2787
  });
2958
2788
  }
2959
2789
  async #listenFanoutMessage(data, message) {
@@ -3517,77 +3347,6 @@ var FederationImpl = class extends FederationBuilderImpl {
3517
3347
  listenerSpan.end();
3518
3348
  });
3519
3349
  }
3520
- async #listenTaskMessage(contextData, message) {
3521
- const logger = getLogger([
3522
- "fedify",
3523
- "federation",
3524
- "task"
3525
- ]);
3526
- const def = this.taskDefinitions.get(message.taskName);
3527
- if (def == null) {
3528
- logger.warn("Received a custom task {taskName} with no registered handler; dropping.", { taskName: message.taskName });
3529
- return;
3530
- }
3531
- const context = this.#createContext(new URL(message.baseUrl), contextData);
3532
- let data;
3533
- try {
3534
- data = await context.codec.decode(def.schema, message.data);
3535
- } catch (error) {
3536
- logger.error("Custom task {taskName} payload could not be decoded or validated; dropping:\n{error}", {
3537
- taskName: message.taskName,
3538
- error
3539
- });
3540
- return;
3541
- }
3542
- try {
3543
- await def.handler(context, data);
3544
- } catch (error) {
3545
- if (def.onError != null) try {
3546
- await def.onError(context, error, data);
3547
- } catch (onErrorError) {
3548
- logger.error("onError for custom task {taskName} threw:\n{error}", {
3549
- taskName: message.taskName,
3550
- error: onErrorError
3551
- });
3552
- }
3553
- const queue = this.resolveTaskQueue(def.name);
3554
- if (queue?.nativeRetrial) throw error;
3555
- const retryPolicy = def.retryPolicy ?? this.taskRetryPolicy;
3556
- let elapsedTime = Temporal.Duration.from({ seconds: 0 });
3557
- try {
3558
- elapsedTime = Temporal.Instant.from(message.started).until(Temporal.Now.instant());
3559
- } catch (parseError) {
3560
- logger.error("Custom task {taskName} has an unparsable started time {started}; treating elapsedTime as zero:\n{error}", {
3561
- taskName: message.taskName,
3562
- started: message.started,
3563
- error: parseError
3564
- });
3565
- }
3566
- const delay = retryPolicy({
3567
- elapsedTime,
3568
- attempts: message.attempt
3569
- });
3570
- if (delay != null && queue != null) {
3571
- logger.error("Custom task {taskName} failed (attempt #{attempt}); retry...:\n{error}", {
3572
- taskName: message.taskName,
3573
- attempt: message.attempt,
3574
- error
3575
- });
3576
- const retryMessage = {
3577
- ...message,
3578
- attempt: message.attempt + 1
3579
- };
3580
- await queue.enqueue(retryMessage, {
3581
- delay: clampNegativeDelay(delay),
3582
- orderingKey: message.orderingKey
3583
- });
3584
- } else logger.error("Custom task {taskName} failed after {attempt} attempts; giving up:\n{error}", {
3585
- taskName: message.taskName,
3586
- attempt: message.attempt,
3587
- error
3588
- });
3589
- }
3590
- }
3591
3350
  startQueue(contextData, options = {}) {
3592
3351
  return this._startQueueInternal(contextData, options.signal, options.queue);
3593
3352
  }
@@ -4172,7 +3931,6 @@ var ContextImpl = class ContextImpl {
4172
3931
  documentLoader;
4173
3932
  contextLoader;
4174
3933
  invokedFromActorKeyPairsDispatcher;
4175
- #codec;
4176
3934
  constructor({ url, federation, data, documentLoader, contextLoader, invokedFromActorKeyPairsDispatcher }) {
4177
3935
  this.url = url;
4178
3936
  this.federation = federation;
@@ -4181,18 +3939,6 @@ var ContextImpl = class ContextImpl {
4181
3939
  this.contextLoader = contextLoader;
4182
3940
  this.invokedFromActorKeyPairsDispatcher = invokedFromActorKeyPairsDispatcher;
4183
3941
  }
4184
- /**
4185
- * A {@link TaskCodec} bound to this context's loaders, used to encode
4186
- * and decode custom task payloads. Lazily created and cached so a context
4187
- * that never enqueues or dispatches a task pays nothing.
4188
- * @internal
4189
- */
4190
- get codec() {
4191
- return this.#codec ??= new TaskCodec(this);
4192
- }
4193
- get #enqueueTasks() {
4194
- return enqueueTasks(this);
4195
- }
4196
3942
  clone(data) {
4197
3943
  return new ContextImpl({
4198
3944
  url: this.url,
@@ -4511,12 +4257,6 @@ var ContextImpl = class ContextImpl {
4511
4257
  allowPrivateAddress: this.federation.allowPrivateAddress
4512
4258
  });
4513
4259
  }
4514
- async enqueueTask(task, data, options = {}) {
4515
- await this.#enqueueTasks(task, [data], options);
4516
- }
4517
- async enqueueTaskMany(task, payloads, options = {}) {
4518
- await this.#enqueueTasks(task, payloads, options);
4519
- }
4520
4260
  sendActivity(sender, recipients, activity, options = {}) {
4521
4261
  return this.tracerProvider.getTracer(name, version).startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
4522
4262
  kind: this.federation.outboxQueue == null || options.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,