@fedify/fedify 2.0.36-dev.2598 → 2.0.36-dev.2647

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 (57) hide show
  1. package/dist/{builder-B5hI5Xsn.mjs → builder-Cv8baeaM.mjs} +3 -3
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{context-lxjaUTAI.d.ts → context-C00pWP8x.d.ts} +6 -0
  6. package/dist/{context-CnoWxuoB.d.cts → context-ao-qb3eP.d.cts} +6 -0
  7. package/dist/{deno--OYa_lxj.mjs → deno-Bk4jrob6.mjs} +1 -1
  8. package/dist/{docloader-BXR2f83H.mjs → docloader-w8xGNWvP.mjs} +2 -2
  9. package/dist/federation/builder.test.mjs +1 -1
  10. package/dist/federation/handler.test.mjs +6 -6
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/inbox.test.mjs +1 -1
  13. package/dist/federation/middleware.test.mjs +602 -6
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.d.cts +2 -2
  16. package/dist/federation/mod.d.ts +2 -2
  17. package/dist/federation/mod.js +1 -1
  18. package/dist/federation/send.test.mjs +3 -3
  19. package/dist/federation/temporal.test.mjs +1 -1
  20. package/dist/federation/webfinger.test.mjs +1 -1
  21. package/dist/{http-CO_IVq7x.cjs → http-B9ZWGTaN.cjs} +1 -1
  22. package/dist/{http-CfyVeGgF.js → http-C1v_vvt4.js} +1 -1
  23. package/dist/{http-C3d2DXwF.mjs → http-CDK9iAjb.mjs} +2 -2
  24. package/dist/{inbox-huUE3IP8.mjs → inbox-DAm48Q_C.mjs} +1 -1
  25. package/dist/{key-D5e9c_yV.mjs → key-C8OKWl8g.mjs} +1 -1
  26. package/dist/{kv-cache-Zw0soD-7.js → kv-cache-B1Y7_B63.js} +1 -1
  27. package/dist/{kv-cache-BMlo_kyv.cjs → kv-cache-BFFwfQPZ.cjs} +1 -1
  28. package/dist/{ld-9qfz9rP_.mjs → ld-gUJKeHbH.mjs} +2 -2
  29. package/dist/{middleware-Ad6kTSBf.cjs → middleware-3t8hmtzt.cjs} +1 -1
  30. package/dist/{middleware-BKs_a9P1.js → middleware-D-DIq_jJ.js} +85 -34
  31. package/dist/{middleware-BhYpLGA_.mjs → middleware-DLxdIffl.mjs} +93 -42
  32. package/dist/{middleware-CT1Lbohd.mjs → middleware-LgcMsPlF.mjs} +1 -1
  33. package/dist/{middleware-CXoG7ZAW.cjs → middleware-_yMwRAE9.cjs} +86 -35
  34. package/dist/{mod-w1oyHseQ.d.cts → mod-6uJWdCc0.d.cts} +1 -1
  35. package/dist/{mod-I-34OMN3.d.ts → mod-DtRh015i.d.ts} +1 -1
  36. package/dist/mod.cjs +4 -4
  37. package/dist/mod.d.cts +2 -2
  38. package/dist/mod.d.ts +2 -2
  39. package/dist/mod.js +4 -4
  40. package/dist/nodeinfo/handler.test.mjs +1 -1
  41. package/dist/{owner-R4ffU9Ht.mjs → owner-BenEndHH.mjs} +2 -2
  42. package/dist/{proof-CiBs9Q4l.mjs → proof-Bo9pmjQJ.mjs} +2 -2
  43. package/dist/{proof-CE8nwTF6.js → proof-BvtZYI3N.js} +1 -1
  44. package/dist/{proof-BrreJTRF.cjs → proof-DF1RSNYg.cjs} +1 -1
  45. package/dist/{send-DpvZgVSA.mjs → send-PTFa5PEa.mjs} +2 -2
  46. package/dist/sig/http.test.mjs +2 -2
  47. package/dist/sig/key.test.mjs +2 -2
  48. package/dist/sig/ld.test.mjs +2 -2
  49. package/dist/sig/mod.cjs +2 -2
  50. package/dist/sig/mod.js +2 -2
  51. package/dist/sig/owner.test.mjs +1 -1
  52. package/dist/sig/proof.test.mjs +2 -2
  53. package/dist/{temporal-Dd-J410Z.mjs → temporal-CNbx4A18.mjs} +1 -1
  54. package/dist/utils/docloader.test.mjs +2 -2
  55. package/dist/utils/mod.cjs +1 -1
  56. package/dist/utils/mod.js +1 -1
  57. package/package.json +5 -5
@@ -8,10 +8,10 @@ import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
8
8
  import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
9
9
  import { t as assertNotEquals } from "../assert_not_equals-BkxW5QJI.mjs";
10
10
  import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
11
- import { u as verifyRequest } from "../http-C3d2DXwF.mjs";
11
+ import { u as verifyRequest } from "../http-CDK9iAjb.mjs";
12
12
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CCxRJhWa.mjs";
13
- import { t as doesActorOwnKey } from "../owner-R4ffU9Ht.mjs";
14
- import { i as sendActivity, n as extractInboxes, r as fetchWithValidatedRedirects, t as SendActivityError } from "../send-DpvZgVSA.mjs";
13
+ import { t as doesActorOwnKey } from "../owner-BenEndHH.mjs";
14
+ import { i as sendActivity, n as extractInboxes, r as fetchWithValidatedRedirects, t as SendActivityError } from "../send-PTFa5PEa.mjs";
15
15
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
16
16
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
17
17
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import "../std__assert-DflMZha5.mjs";
5
5
  import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
6
6
  import { t as assert } from "../assert-BhQd8QHP.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-Dd-J410Z.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-CNbx4A18.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  //#region src/federation/temporal.test.ts
10
10
  test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
@@ -5,7 +5,7 @@ import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-DflMZha5.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
8
- import { a as createFederation, o as handleWebFinger } from "../middleware-BhYpLGA_.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-DLxdIffl.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Image, Link, Person } from "@fedify/vocab";
11
11
  //#region src/federation/webfinger.test.ts
@@ -11,7 +11,7 @@ let byte_encodings_base64 = require("byte-encodings/base64");
11
11
  let structured_field_values = require("structured-field-values");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.0.36-dev.2598+90504ae2";
14
+ var version = "2.0.36-dev.2647+2864b09d";
15
15
  //#endregion
16
16
  //#region src/sig/key.ts
17
17
  /** Classifies decoding failures without hiding unexpected loader errors. */
@@ -10,7 +10,7 @@ import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
10
10
  import { Item, decodeDict, encodeItem } from "structured-field-values";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.0.36-dev.2598+90504ae2";
13
+ var version = "2.0.36-dev.2647+2864b09d";
14
14
  //#endregion
15
15
  //#region src/sig/key.ts
16
16
  /** Classifies decoding failures without hiding unexpected loader errors. */
@@ -1,8 +1,8 @@
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--OYa_lxj.mjs";
5
- import { o as validateCryptoKey, r as fetchKey } from "./key-D5e9c_yV.mjs";
4
+ import { n as version, t as name } from "./deno-Bk4jrob6.mjs";
5
+ import { o as validateCryptoKey, r as fetchKey } from "./key-C8OKWl8g.mjs";
6
6
  import { CryptographicKey } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { FetchError } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
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--OYa_lxj.mjs";
4
+ import { n as version, t as name } from "./deno-Bk4jrob6.mjs";
5
5
  import { Activity, getTypeId } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
@@ -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--OYa_lxj.mjs";
4
+ import { n as version, t as name } from "./deno-Bk4jrob6.mjs";
5
5
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { FetchError, UrlError, getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { l as validateCryptoKey, t as doubleKnockScoped } from "./http-CfyVeGgF.js";
3
+ import { l as validateCryptoKey, t as doubleKnockScoped } from "./http-C1v_vvt4.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-CO_IVq7x.cjs");
4
+ const require_http = require("./http-B9ZWGTaN.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,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--OYa_lxj.mjs";
5
- import { o as validateCryptoKey, r as fetchKey } from "./key-D5e9c_yV.mjs";
4
+ import { n as version, t as name } from "./deno-Bk4jrob6.mjs";
5
+ import { o as validateCryptoKey, r as fetchKey } from "./key-C8OKWl8g.mjs";
6
6
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader, preloadedContexts } from "@fedify/vocab-runtime";
@@ -1,4 +1,4 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
- const require_middleware = require("./middleware-CXoG7ZAW.cjs");
3
+ const require_middleware = require("./middleware-_yMwRAE9.cjs");
4
4
  exports.FederationImpl = require_middleware.FederationImpl;
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./chunk-CRNNMoPX.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-BGMIq1cs.js";
5
- import { c as importJwk, d as name, f as version, i as exportJwk, l as validateCryptoKey, r as verifyRequest, t as doubleKnockScoped } from "./http-CfyVeGgF.js";
5
+ import { c as importJwk, d as name, f as version, i as exportJwk, l as validateCryptoKey, r as verifyRequest, t as doubleKnockScoped } from "./http-C1v_vvt4.js";
6
6
  import { a as MAX_BODY_SIZE, i as BodyTooLargeError, n as getNodeInfo, o as readBoundedText, t as nodeInfoToJson } from "./types-B1_pRFE_.js";
7
- import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-CE8nwTF6.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-Zw0soD-7.js";
7
+ import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-BvtZYI3N.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-B1Y7_B63.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
11
11
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -2869,6 +2869,23 @@ var FederationImpl = class extends FederationBuilderImpl {
2869
2869
  _getTracer() {
2870
2870
  return this.tracerProvider.getTracer(name, version);
2871
2871
  }
2872
+ /**
2873
+ * Starts listening on a queue, converting a synchronous throw into
2874
+ * a rejected promise.
2875
+ *
2876
+ * `MessageQueue.listen()` is documented to never reject, but some
2877
+ * implementations (e.g., `WorkersMessageQueue`) throw synchronously. Without
2878
+ * this normalization, one such throw aborts {@link _startQueueInternal} while
2879
+ * it is still collecting listener promises, so listeners started earlier are
2880
+ * never awaited and later queues are never started.
2881
+ */
2882
+ #listenQueue(queue, ctxData, signal) {
2883
+ try {
2884
+ return queue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal });
2885
+ } catch (error) {
2886
+ return Promise.reject(error);
2887
+ }
2888
+ }
2872
2889
  async _startQueueInternal(ctxData, signal, queue) {
2873
2890
  if (this.inboxQueue == null && this.outboxQueue == null) return;
2874
2891
  const logger = getLogger([
@@ -2880,20 +2897,38 @@ var FederationImpl = class extends FederationBuilderImpl {
2880
2897
  if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
2881
2898
  logger.debug("Starting an inbox task worker.");
2882
2899
  this.inboxQueueStarted = true;
2883
- promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2900
+ promises.push(this.#listenQueue(this.inboxQueue, ctxData, signal));
2884
2901
  }
2885
2902
  if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
2886
2903
  logger.debug("Starting an outbox task worker.");
2887
2904
  this.outboxQueueStarted = true;
2888
- promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2905
+ promises.push(this.#listenQueue(this.outboxQueue, ctxData, signal));
2889
2906
  }
2890
2907
  if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
2891
2908
  logger.debug("Starting a fanout task worker.");
2892
2909
  this.fanoutQueueStarted = true;
2893
- promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
2910
+ promises.push(this.#listenQueue(this.fanoutQueue, ctxData, signal));
2894
2911
  }
2895
2912
  await Promise.all(promises);
2896
2913
  }
2914
+ /**
2915
+ * Starts the queue workers automatically, reporting a failure instead of
2916
+ * leaving the returned promise unobserved.
2917
+ *
2918
+ * Automatic startup is best-effort: call sites cannot await it, so a failing
2919
+ * listener (e.g., `WorkersMessageQueue`, whose `listen()` throws) must not
2920
+ * become an unhandled rejection. {@link startQueue} keeps rejecting for
2921
+ * callers that start workers deliberately.
2922
+ */
2923
+ _startQueueAutomatically(ctxData) {
2924
+ this._startQueueInternal(ctxData).catch((error) => {
2925
+ getLogger([
2926
+ "fedify",
2927
+ "federation",
2928
+ "queue"
2929
+ ]).warn("Failed to start queue workers automatically: {error}", { error });
2930
+ });
2931
+ }
2897
2932
  processQueuedTask(contextData, message) {
2898
2933
  const tracer = this._getTracer();
2899
2934
  const extractedContext = propagation.extract(context.active(), message.traceContext);
@@ -3450,19 +3485,27 @@ var FederationImpl = class extends FederationBuilderImpl {
3450
3485
  activity: jsonLd
3451
3486
  });
3452
3487
  const promises = [];
3453
- for (const inbox in inboxes) promises.push(sendActivity({
3454
- allowPrivateAddress: this.allowPrivateAddress,
3455
- keys,
3456
- activity: jsonLd,
3457
- activityId: activity.id?.href,
3458
- activityType: getTypeId(activity).href,
3459
- inbox: new URL(inbox),
3460
- sharedInbox: inboxes[inbox].sharedInbox,
3461
- headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
3462
- specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
3463
- tracerProvider: this.tracerProvider
3464
- }));
3465
- await Promise.all(promises);
3488
+ try {
3489
+ for (const inbox in inboxes) {
3490
+ const promise = sendActivity({
3491
+ allowPrivateAddress: this.allowPrivateAddress,
3492
+ keys,
3493
+ activity: jsonLd,
3494
+ activityId: activity.id?.href,
3495
+ activityType: getTypeId(activity).href,
3496
+ inbox: new URL(inbox),
3497
+ sharedInbox: inboxes[inbox].sharedInbox,
3498
+ headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
3499
+ specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
3500
+ tracerProvider: this.tracerProvider
3501
+ });
3502
+ promise.catch(() => {});
3503
+ promises.push(promise);
3504
+ }
3505
+ await Promise.all(promises);
3506
+ } finally {
3507
+ await Promise.allSettled(promises);
3508
+ }
3466
3509
  return;
3467
3510
  }
3468
3511
  logger.debug("Enqueuing activity {activityId} to send later.", {
@@ -3477,7 +3520,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3477
3520
  privateKey: privateKeyJwk
3478
3521
  });
3479
3522
  }
3480
- if (!this.manuallyStartQueue) this._startQueueInternal(ctx.data);
3523
+ if (!this.manuallyStartQueue) this._startQueueAutomatically(ctx.data);
3481
3524
  const carrier = {};
3482
3525
  propagation.inject(context.active(), carrier);
3483
3526
  const messages = [];
@@ -3689,7 +3732,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3689
3732
  const identity = await this.sharedInboxKeyDispatcher(context);
3690
3733
  if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
3691
3734
  }
3692
- if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
3735
+ if (!this.manuallyStartQueue) this._startQueueAutomatically(contextData);
3693
3736
  const inboxContextFactory = context.toInboxContext.bind(context);
3694
3737
  inboxContextFactory[rawInboxContextFactorySymbol] = context.toInboxContext.bind(context);
3695
3738
  return await handleInbox(request, {
@@ -4296,7 +4339,7 @@ var ContextImpl = class ContextImpl {
4296
4339
  orderingKey: options.orderingKey,
4297
4340
  traceContext: carrier
4298
4341
  };
4299
- if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
4342
+ if (!this.federation.manuallyStartQueue) this.federation._startQueueAutomatically(this.data);
4300
4343
  await this.federation.fanoutQueue.enqueue(message, { orderingKey: options.orderingKey });
4301
4344
  }
4302
4345
  async *getFollowers(identifier) {
@@ -4666,18 +4709,26 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
4666
4709
  if (options?.immediate) logger.debug("Forwarding activity immediately without queue since immediate option is set.");
4667
4710
  else logger.debug("Forwarding activity immediately without queue since queue is not set.");
4668
4711
  const promises = [];
4669
- for (const inbox in inboxes) promises.push(sendActivity({
4670
- allowPrivateAddress: this.federation.allowPrivateAddress,
4671
- keys,
4672
- activity: this.activity,
4673
- activityId: this.activityId,
4674
- activityType: this.activityType,
4675
- inbox: new URL(inbox),
4676
- sharedInbox: inboxes[inbox].sharedInbox,
4677
- tracerProvider: this.tracerProvider,
4678
- specDeterminer: new KvSpecDeterminer(this.federation.kv, this.federation.kvPrefixes.httpMessageSignaturesSpec, this.federation.firstKnock)
4679
- }));
4680
- await Promise.all(promises);
4712
+ try {
4713
+ for (const inbox in inboxes) {
4714
+ const promise = sendActivity({
4715
+ allowPrivateAddress: this.federation.allowPrivateAddress,
4716
+ keys,
4717
+ activity: this.activity,
4718
+ activityId: this.activityId,
4719
+ activityType: this.activityType,
4720
+ inbox: new URL(inbox),
4721
+ sharedInbox: inboxes[inbox].sharedInbox,
4722
+ tracerProvider: this.tracerProvider,
4723
+ specDeterminer: new KvSpecDeterminer(this.federation.kv, this.federation.kvPrefixes.httpMessageSignaturesSpec, this.federation.firstKnock)
4724
+ });
4725
+ promise.catch(() => {});
4726
+ promises.push(promise);
4727
+ }
4728
+ await Promise.all(promises);
4729
+ } finally {
4730
+ await Promise.allSettled(promises);
4731
+ }
4681
4732
  return;
4682
4733
  }
4683
4734
  logger.debug("Enqueuing activity {activityId} to forward later.", {
@@ -2,24 +2,24 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno--OYa_lxj.mjs";
6
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-D5e9c_yV.mjs";
7
- import { u as verifyRequest } from "./http-C3d2DXwF.mjs";
8
- import { n as getAuthenticatedDocumentLoader } from "./docloader-BXR2f83H.mjs";
5
+ import { n as version, t as name } from "./deno-Bk4jrob6.mjs";
6
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-C8OKWl8g.mjs";
7
+ import { u as verifyRequest } from "./http-CDK9iAjb.mjs";
8
+ import { n as getAuthenticatedDocumentLoader } from "./docloader-w8xGNWvP.mjs";
9
9
  import { n as kvCache } from "./kv-cache-BrjuJue8.mjs";
10
- import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-9qfz9rP_.mjs";
11
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-R4ffU9Ht.mjs";
12
- import { n as signObject, r as verifyObject } from "./proof-CiBs9Q4l.mjs";
10
+ import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-gUJKeHbH.mjs";
11
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-BenEndHH.mjs";
12
+ import { n as signObject, r as verifyObject } from "./proof-Bo9pmjQJ.mjs";
13
13
  import { d as MAX_BODY_SIZE, f as readBoundedText, t as getNodeInfo, u as BodyTooLargeError } from "./client-DGNacEx_.mjs";
14
14
  import { t as nodeInfoToJson } from "./types-MNlFfxjv.mjs";
15
- import { n as actorsHaveSameOrigin, r as routeActivity } from "./inbox-huUE3IP8.mjs";
16
- import { t as FederationBuilderImpl } from "./builder-B5hI5Xsn.mjs";
15
+ import { n as actorsHaveSameOrigin, r as routeActivity } from "./inbox-DAm48Q_C.mjs";
16
+ import { t as FederationBuilderImpl } from "./builder-Cv8baeaM.mjs";
17
17
  import { t as buildCollectionSynchronizationHeader } from "./collection-DI6YzYpd.mjs";
18
18
  import { t as KvKeyCache } from "./keycache-DBD6fzl1.mjs";
19
19
  import { t as acceptsJsonLd } from "./negotiation-TWEs6Cl8.mjs";
20
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-Dd-J410Z.mjs";
20
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-CNbx4A18.mjs";
21
21
  import { t as createExponentialBackoffPolicy } from "./retry-Ddbq3AcK.mjs";
22
- import { i as sendActivity, n as extractInboxes, t as SendActivityError } from "./send-DpvZgVSA.mjs";
22
+ import { i as sendActivity, n as extractInboxes, t as SendActivityError } from "./send-PTFa5PEa.mjs";
23
23
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
24
24
  import { lookupWebFinger } from "@fedify/webfinger";
25
25
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -1532,6 +1532,23 @@ var FederationImpl = class extends FederationBuilderImpl {
1532
1532
  _getTracer() {
1533
1533
  return this.tracerProvider.getTracer(name, version);
1534
1534
  }
1535
+ /**
1536
+ * Starts listening on a queue, converting a synchronous throw into
1537
+ * a rejected promise.
1538
+ *
1539
+ * `MessageQueue.listen()` is documented to never reject, but some
1540
+ * implementations (e.g., `WorkersMessageQueue`) throw synchronously. Without
1541
+ * this normalization, one such throw aborts {@link _startQueueInternal} while
1542
+ * it is still collecting listener promises, so listeners started earlier are
1543
+ * never awaited and later queues are never started.
1544
+ */
1545
+ #listenQueue(queue, ctxData, signal) {
1546
+ try {
1547
+ return queue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal });
1548
+ } catch (error) {
1549
+ return Promise.reject(error);
1550
+ }
1551
+ }
1535
1552
  async _startQueueInternal(ctxData, signal, queue) {
1536
1553
  if (this.inboxQueue == null && this.outboxQueue == null) return;
1537
1554
  const logger = getLogger([
@@ -1543,20 +1560,38 @@ var FederationImpl = class extends FederationBuilderImpl {
1543
1560
  if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
1544
1561
  logger.debug("Starting an inbox task worker.");
1545
1562
  this.inboxQueueStarted = true;
1546
- promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
1563
+ promises.push(this.#listenQueue(this.inboxQueue, ctxData, signal));
1547
1564
  }
1548
1565
  if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
1549
1566
  logger.debug("Starting an outbox task worker.");
1550
1567
  this.outboxQueueStarted = true;
1551
- promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
1568
+ promises.push(this.#listenQueue(this.outboxQueue, ctxData, signal));
1552
1569
  }
1553
1570
  if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
1554
1571
  logger.debug("Starting a fanout task worker.");
1555
1572
  this.fanoutQueueStarted = true;
1556
- promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
1573
+ promises.push(this.#listenQueue(this.fanoutQueue, ctxData, signal));
1557
1574
  }
1558
1575
  await Promise.all(promises);
1559
1576
  }
1577
+ /**
1578
+ * Starts the queue workers automatically, reporting a failure instead of
1579
+ * leaving the returned promise unobserved.
1580
+ *
1581
+ * Automatic startup is best-effort: call sites cannot await it, so a failing
1582
+ * listener (e.g., `WorkersMessageQueue`, whose `listen()` throws) must not
1583
+ * become an unhandled rejection. {@link startQueue} keeps rejecting for
1584
+ * callers that start workers deliberately.
1585
+ */
1586
+ _startQueueAutomatically(ctxData) {
1587
+ this._startQueueInternal(ctxData).catch((error) => {
1588
+ getLogger([
1589
+ "fedify",
1590
+ "federation",
1591
+ "queue"
1592
+ ]).warn("Failed to start queue workers automatically: {error}", { error });
1593
+ });
1594
+ }
1560
1595
  processQueuedTask(contextData, message) {
1561
1596
  const tracer = this._getTracer();
1562
1597
  const extractedContext = propagation.extract(context.active(), message.traceContext);
@@ -2113,19 +2148,27 @@ var FederationImpl = class extends FederationBuilderImpl {
2113
2148
  activity: jsonLd
2114
2149
  });
2115
2150
  const promises = [];
2116
- for (const inbox in inboxes) promises.push(sendActivity({
2117
- allowPrivateAddress: this.allowPrivateAddress,
2118
- keys,
2119
- activity: jsonLd,
2120
- activityId: activity.id?.href,
2121
- activityType: getTypeId(activity).href,
2122
- inbox: new URL(inbox),
2123
- sharedInbox: inboxes[inbox].sharedInbox,
2124
- headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
2125
- specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
2126
- tracerProvider: this.tracerProvider
2127
- }));
2128
- await Promise.all(promises);
2151
+ try {
2152
+ for (const inbox in inboxes) {
2153
+ const promise = sendActivity({
2154
+ allowPrivateAddress: this.allowPrivateAddress,
2155
+ keys,
2156
+ activity: jsonLd,
2157
+ activityId: activity.id?.href,
2158
+ activityType: getTypeId(activity).href,
2159
+ inbox: new URL(inbox),
2160
+ sharedInbox: inboxes[inbox].sharedInbox,
2161
+ headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
2162
+ specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
2163
+ tracerProvider: this.tracerProvider
2164
+ });
2165
+ promise.catch(() => {});
2166
+ promises.push(promise);
2167
+ }
2168
+ await Promise.all(promises);
2169
+ } finally {
2170
+ await Promise.allSettled(promises);
2171
+ }
2129
2172
  return;
2130
2173
  }
2131
2174
  logger.debug("Enqueuing activity {activityId} to send later.", {
@@ -2140,7 +2183,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2140
2183
  privateKey: privateKeyJwk
2141
2184
  });
2142
2185
  }
2143
- if (!this.manuallyStartQueue) this._startQueueInternal(ctx.data);
2186
+ if (!this.manuallyStartQueue) this._startQueueAutomatically(ctx.data);
2144
2187
  const carrier = {};
2145
2188
  propagation.inject(context.active(), carrier);
2146
2189
  const messages = [];
@@ -2352,7 +2395,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2352
2395
  const identity = await this.sharedInboxKeyDispatcher(context);
2353
2396
  if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
2354
2397
  }
2355
- if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
2398
+ if (!this.manuallyStartQueue) this._startQueueAutomatically(contextData);
2356
2399
  const inboxContextFactory = context.toInboxContext.bind(context);
2357
2400
  inboxContextFactory[rawInboxContextFactorySymbol] = context.toInboxContext.bind(context);
2358
2401
  return await handleInbox(request, {
@@ -2959,7 +3002,7 @@ var ContextImpl = class ContextImpl {
2959
3002
  orderingKey: options.orderingKey,
2960
3003
  traceContext: carrier
2961
3004
  };
2962
- if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
3005
+ if (!this.federation.manuallyStartQueue) this.federation._startQueueAutomatically(this.data);
2963
3006
  await this.federation.fanoutQueue.enqueue(message, { orderingKey: options.orderingKey });
2964
3007
  }
2965
3008
  async *getFollowers(identifier) {
@@ -3329,18 +3372,26 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
3329
3372
  if (options?.immediate) logger.debug("Forwarding activity immediately without queue since immediate option is set.");
3330
3373
  else logger.debug("Forwarding activity immediately without queue since queue is not set.");
3331
3374
  const promises = [];
3332
- for (const inbox in inboxes) promises.push(sendActivity({
3333
- allowPrivateAddress: this.federation.allowPrivateAddress,
3334
- keys,
3335
- activity: this.activity,
3336
- activityId: this.activityId,
3337
- activityType: this.activityType,
3338
- inbox: new URL(inbox),
3339
- sharedInbox: inboxes[inbox].sharedInbox,
3340
- tracerProvider: this.tracerProvider,
3341
- specDeterminer: new KvSpecDeterminer(this.federation.kv, this.federation.kvPrefixes.httpMessageSignaturesSpec, this.federation.firstKnock)
3342
- }));
3343
- await Promise.all(promises);
3375
+ try {
3376
+ for (const inbox in inboxes) {
3377
+ const promise = sendActivity({
3378
+ allowPrivateAddress: this.federation.allowPrivateAddress,
3379
+ keys,
3380
+ activity: this.activity,
3381
+ activityId: this.activityId,
3382
+ activityType: this.activityType,
3383
+ inbox: new URL(inbox),
3384
+ sharedInbox: inboxes[inbox].sharedInbox,
3385
+ tracerProvider: this.tracerProvider,
3386
+ specDeterminer: new KvSpecDeterminer(this.federation.kv, this.federation.kvPrefixes.httpMessageSignaturesSpec, this.federation.firstKnock)
3387
+ });
3388
+ promise.catch(() => {});
3389
+ promises.push(promise);
3390
+ }
3391
+ await Promise.all(promises);
3392
+ } finally {
3393
+ await Promise.allSettled(promises);
3394
+ }
3344
3395
  return;
3345
3396
  }
3346
3397
  logger.debug("Enqueuing activity {activityId} to forward later.", {
@@ -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-BhYpLGA_.mjs";
4
+ import { n as FederationImpl } from "./middleware-DLxdIffl.mjs";
5
5
  export { FederationImpl };