@fedify/fedify 2.0.0-dev.279 → 2.0.0-dev.335

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 (114) hide show
  1. package/dist/{builder-B7WWCOdc.js → builder-RHW0dkbP.js} +8 -3
  2. package/dist/{chunk-DqRYRqnO.cjs → chunk-CGaQZ11T.cjs} +19 -0
  3. package/dist/chunk-DJNbSFdH.js +29 -0
  4. package/dist/compat/mod.cjs +1 -1
  5. package/dist/compat/mod.d.cts +6 -6
  6. package/dist/compat/mod.d.ts +6 -6
  7. package/dist/compat/mod.js +2 -2
  8. package/dist/compat/transformers.test.js +11 -11
  9. package/dist/{context-D7JEVvXJ.d.cts → context-Cf0-LmZC.d.cts} +96 -5
  10. package/dist/{context-BNNWbaZL.d.ts → context-liIe6DFH.d.ts} +96 -5
  11. package/dist/{deno-fe0u4LiE.js → deno-Dhe5E7NK.js} +4 -2
  12. package/dist/{docloader-C9Dmxf-K.js → docloader-D6VuU143.js} +2 -2
  13. package/dist/federation/builder.test.js +3 -3
  14. package/dist/federation/handler.test.js +11 -11
  15. package/dist/federation/idempotency.test.js +47 -11
  16. package/dist/federation/inbox.test.js +2 -2
  17. package/dist/federation/middleware.test.js +171 -11
  18. package/dist/federation/mod.cjs +8 -7
  19. package/dist/federation/mod.d.cts +7 -7
  20. package/dist/federation/mod.d.ts +7 -7
  21. package/dist/federation/mod.js +8 -8
  22. package/dist/federation/send.test.js +89 -6
  23. package/dist/federation/webfinger.test.js +11 -11
  24. package/dist/{federation-CE0CJ_0G.cjs → federation-Bp3HI26G.cjs} +1 -1
  25. package/dist/{http-oCBlFLKT.js → http-CSqVEUdE.js} +2 -2
  26. package/dist/{http-DMi5iyiI.cjs → http-ChlQCtql.cjs} +5 -3
  27. package/dist/{http-7r8B3dF_.js → http-DZrrJD77.js} +4 -2
  28. package/dist/{inbox-Dm1rfkdg.js → inbox-9F91oWJU.js} +1 -1
  29. package/dist/{key-BGzsKfpZ.js → key-DFPkYar3.js} +1 -1
  30. package/dist/{kv-cache-CETRZwoP.js → kv-cache-1TNWtgx7.js} +1 -1
  31. package/dist/{kv-cache-C0AvpI7U.cjs → kv-cache-DwcKE9EQ.cjs} +2 -2
  32. package/dist/{ld-BaO1-A5Y.js → ld-kAhyoO55.js} +2 -2
  33. package/dist/middleware-BgurYNZ4.js +12 -0
  34. package/dist/{middleware-C0Vj7vNo.cjs → middleware-CULfPNt-.cjs} +88 -9
  35. package/dist/middleware-ChlsNVu2.cjs +12 -0
  36. package/dist/{middleware-R0w-WauH.js → middleware-DQriD-Kq.js} +82 -9
  37. package/dist/{middleware-CnGBoMop.js → middleware-DebYvXJs.js} +11 -11
  38. package/dist/{middleware-BlOT9luD.js → middleware-zvH5O0zk.js} +45 -11
  39. package/dist/{mod-YpmzboJc.d.ts → mod-B9_l3te3.d.ts} +1 -1
  40. package/dist/mod-Bh8mqlYw.d.cts +9 -0
  41. package/dist/{mod-BrS8tiad.d.cts → mod-COO7VMcm.d.cts} +1 -1
  42. package/dist/{mod-DZmuPaKv.d.ts → mod-CvhyLrjX.d.ts} +2 -2
  43. package/dist/mod-D6HodEq7.d.ts +7 -0
  44. package/dist/{mod-BHXq4Q3x.d.cts → mod-DWaA45ef.d.cts} +2 -2
  45. package/dist/{mod-054TSUXs.d.cts → mod-Do_sZWAA.d.cts} +1 -1
  46. package/dist/{mod-BhDb3RBS.d.ts → mod-Dquroqiv.d.ts} +1 -1
  47. package/dist/{mod-C74sRHP8.d.cts → mod-H3ScYaOb.d.cts} +1 -1
  48. package/dist/{mod-jOa7W503.d.ts → mod-q2IR8UiH.d.ts} +1 -1
  49. package/dist/mod.cjs +59 -9
  50. package/dist/mod.d.cts +20 -11
  51. package/dist/mod.d.ts +21 -11
  52. package/dist/mod.js +61 -12
  53. package/dist/nodeinfo/handler.test.js +11 -11
  54. package/dist/nodeinfo/mod.cjs +1 -1
  55. package/dist/nodeinfo/mod.d.cts +2 -2
  56. package/dist/nodeinfo/mod.d.ts +2 -2
  57. package/dist/nodeinfo/mod.js +2 -2
  58. package/dist/otel/mod.cjs +1 -1
  59. package/dist/otel/mod.d.cts +1 -1
  60. package/dist/otel/mod.d.ts +1 -1
  61. package/dist/{owner-BqIhDQWW.js → owner-DcyH0sQg.js} +1 -1
  62. package/dist/{proof-DoHt7qrS.js → proof-D7C8ouBO.js} +2 -2
  63. package/dist/{proof-Cg6AAAWI.js → proof-JtZEQaKw.js} +1 -1
  64. package/dist/{proof-vSvvLbTh.cjs → proof-_Rz8hNBt.cjs} +2 -2
  65. package/dist/runtime/mod.cjs +14 -0
  66. package/dist/runtime/mod.d.cts +2 -0
  67. package/dist/runtime/mod.d.ts +4 -0
  68. package/dist/runtime/mod.js +7 -0
  69. package/dist/runtime-c2Njxsry.cjs +17 -0
  70. package/dist/runtime-poamPCMb.js +13 -0
  71. package/dist/{send-CO2ZYT96.js → send-mAsnzegg.js} +38 -4
  72. package/dist/sig/http.test.js +3 -3
  73. package/dist/sig/key.test.js +2 -2
  74. package/dist/sig/ld.test.js +3 -3
  75. package/dist/sig/mod.cjs +3 -3
  76. package/dist/sig/mod.d.cts +3 -3
  77. package/dist/sig/mod.d.ts +3 -3
  78. package/dist/sig/mod.js +3 -3
  79. package/dist/sig/owner.test.js +3 -3
  80. package/dist/sig/proof.test.js +3 -3
  81. package/dist/testing/mod.d.ts +80 -0
  82. package/dist/{transformers-BjBg6Lag.cjs → transformers-3g8GZwkZ.cjs} +1 -1
  83. package/dist/{types-B6z6CqIz.cjs → types-Cd_hszr_.cjs} +1 -1
  84. package/dist/utils/docloader.test.js +4 -4
  85. package/dist/utils/mod.cjs +3 -3
  86. package/dist/utils/mod.d.cts +3 -3
  87. package/dist/utils/mod.d.ts +3 -3
  88. package/dist/utils/mod.js +3 -3
  89. package/dist/vocab/mod.cjs +13 -0
  90. package/dist/vocab/mod.d.cts +1 -0
  91. package/dist/vocab/mod.d.ts +3 -0
  92. package/dist/vocab/mod.js +5 -0
  93. package/package.json +25 -5
  94. package/dist/middleware-BDJNulB_.js +0 -12
  95. package/dist/middleware-DT3JkH-g.cjs +0 -12
  96. /package/dist/{client-by-PEGAJ.d.cts → client-CwkOPN13.d.cts} +0 -0
  97. /package/dist/{client-CUTUGgvJ.d.ts → client-a7NwzhA2.d.ts} +0 -0
  98. /package/dist/{compat-nxUqe4Z-.js → compat-Bb4NuTUO.js} +0 -0
  99. /package/dist/{federation-D6FVaeAR.js → federation-DaMfqRm4.js} +0 -0
  100. /package/dist/{http-ClB3pLcL.d.cts → http-CCEu-x1_.d.cts} +0 -0
  101. /package/dist/{http-DLBDPal9.d.ts → http-CODSJcKx.d.ts} +0 -0
  102. /package/dist/{kv-B4vFhIYL.d.cts → kv-g9jFc34-.d.cts} +0 -0
  103. /package/dist/{kv-CYySNrsn.d.ts → kv-jg_8SMc1.d.ts} +0 -0
  104. /package/dist/{mod-1E3W847c.d.ts → mod-AGjRfPjT.d.ts} +0 -0
  105. /package/dist/{mod-C81L6_lQ.d.cts → mod-gq_Xfdz8.d.cts} +0 -0
  106. /package/dist/{nodeinfo-BlLsRSiT.js → nodeinfo-DoESQxq5.js} +0 -0
  107. /package/dist/{owner-C-zfmVAD.d.cts → owner-9yZ5Ibsb.d.cts} +0 -0
  108. /package/dist/{owner-BgI8C-VY.d.ts → owner-DQYAbVmX.d.ts} +0 -0
  109. /package/dist/{sig-CwuONEzF.js → sig-BNhspNOf.js} +0 -0
  110. /package/dist/{sig-DeXX2xnj.cjs → sig-vX39WyWI.cjs} +0 -0
  111. /package/dist/{transformers-N_ip_y4P.js → transformers-C3FLHUd6.js} +0 -0
  112. /package/dist/{types-8l28uC8o.js → types-C93Ob9cU.js} +0 -0
  113. /package/dist/{utils-Db0ZmjcD.cjs → utils-BQ9KqEK9.cjs} +0 -0
  114. /package/dist/{utils-Wranxuoe.js → utils-Dn5OPdSW.js} +0 -0
@@ -3,7 +3,7 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { deno_default } from "./deno-fe0u4LiE.js";
6
+ import { deno_default } from "./deno-Dhe5E7NK.js";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
9
9
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -2,7 +2,7 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { doubleKnock, validateCryptoKey } from "./http-7r8B3dF_.js";
5
+ import { doubleKnock, validateCryptoKey } from "./http-DZrrJD77.js";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  import { curry } from "es-toolkit";
8
8
  import { UrlError, createActivityPubRequest, getDocumentLoader, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -2,8 +2,8 @@
2
2
  const { Temporal } = require("@js-temporal/polyfill");
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
- const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_http = require('./http-DMi5iyiI.cjs');
5
+ const require_chunk = require('./chunk-CGaQZ11T.cjs');
6
+ const require_http = require('./http-ChlQCtql.cjs');
7
7
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
8
8
  const es_toolkit = require_chunk.__toESM(require("es-toolkit"));
9
9
  const __fedify_vocab_runtime = require_chunk.__toESM(require("@fedify/vocab-runtime"));
@@ -3,8 +3,8 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { deno_default } from "./deno-fe0u4LiE.js";
7
- import { fetchKey, validateCryptoKey } from "./key-BGzsKfpZ.js";
6
+ import { deno_default } from "./deno-Dhe5E7NK.js";
7
+ import { fetchKey, validateCryptoKey } from "./key-DFPkYar3.js";
8
8
  import { getLogger } from "@logtape/logtape";
9
9
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
10
10
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -0,0 +1,12 @@
1
+
2
+ import { Temporal } from "@js-temporal/polyfill";
3
+ import { URLPattern } from "urlpattern-polyfill";
4
+
5
+ import "./transformers-C3FLHUd6.js";
6
+ import "./http-DZrrJD77.js";
7
+ import { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, createFederation } from "./middleware-DQriD-Kq.js";
8
+ import "./proof-JtZEQaKw.js";
9
+ import "./types-C93Ob9cU.js";
10
+ import "./kv-cache-1TNWtgx7.js";
11
+
12
+ export { FederationImpl };
@@ -2,12 +2,12 @@
2
2
  const { Temporal } = require("@js-temporal/polyfill");
3
3
  const { URLPattern } = require("urlpattern-polyfill");
4
4
 
5
- const require_chunk = require('./chunk-DqRYRqnO.cjs');
6
- const require_transformers = require('./transformers-BjBg6Lag.cjs');
7
- const require_http = require('./http-DMi5iyiI.cjs');
8
- const require_proof = require('./proof-vSvvLbTh.cjs');
9
- const require_types = require('./types-B6z6CqIz.cjs');
10
- const require_kv_cache = require('./kv-cache-C0AvpI7U.cjs');
5
+ const require_chunk = require('./chunk-CGaQZ11T.cjs');
6
+ const require_transformers = require('./transformers-3g8GZwkZ.cjs');
7
+ const require_http = require('./http-ChlQCtql.cjs');
8
+ const require_proof = require('./proof-_Rz8hNBt.cjs');
9
+ const require_types = require('./types-Cd_hszr_.cjs');
10
+ const require_kv_cache = require('./kv-cache-DwcKE9EQ.cjs');
11
11
  const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
12
12
  const __fedify_vocab = require_chunk.__toESM(require("@fedify/vocab"));
13
13
  const __opentelemetry_api = require_chunk.__toESM(require("@opentelemetry/api"));
@@ -323,6 +323,7 @@ var FederationBuilderImpl = class {
323
323
  inboxListeners;
324
324
  inboxErrorHandler;
325
325
  sharedInboxKeyDispatcher;
326
+ outboxPermanentFailureHandler;
326
327
  idempotencyStrategy;
327
328
  collectionTypeIds;
328
329
  collectionCallbacks;
@@ -338,7 +339,7 @@ var FederationBuilderImpl = class {
338
339
  this.collectionTypeIds = {};
339
340
  }
340
341
  async build(options) {
341
- const { FederationImpl: FederationImpl$1 } = await Promise.resolve().then(() => require("./middleware-DT3JkH-g.cjs"));
342
+ const { FederationImpl: FederationImpl$1 } = await Promise.resolve().then(() => require("./middleware-ChlsNVu2.cjs"));
342
343
  const f = new FederationImpl$1(options);
343
344
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
344
345
  f.router = this.router.clone();
@@ -360,6 +361,7 @@ var FederationBuilderImpl = class {
360
361
  f.inboxListeners = this.inboxListeners?.clone();
361
362
  f.inboxErrorHandler = this.inboxErrorHandler;
362
363
  f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
364
+ f.outboxPermanentFailureHandler = this.outboxPermanentFailureHandler;
363
365
  f.idempotencyStrategy = this.idempotencyStrategy;
364
366
  return f;
365
367
  }
@@ -841,6 +843,9 @@ var FederationBuilderImpl = class {
841
843
  const path = this.router.build(`collection:${routeName}`, values) ?? this.router.build(`orderedCollection:${routeName}`, values);
842
844
  return path;
843
845
  }
846
+ setOutboxPermanentFailureHandler(handler) {
847
+ this.outboxPermanentFailureHandler = handler;
848
+ }
844
849
  /**
845
850
  * Converts a name (string or symbol) to a unique string identifier.
846
851
  * For symbols, generates and caches a UUID if not already present.
@@ -2181,7 +2186,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2181
2186
  statusText: response.statusText,
2182
2187
  error
2183
2188
  });
2184
- throw new Error(`Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`);
2189
+ throw new SendActivityError(inbox, response.status, `Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`, error);
2185
2190
  }
2186
2191
  span.addEvent("activitypub.activity.sent", {
2187
2192
  "activitypub.activity.json": JSON.stringify(activity),
@@ -2189,6 +2194,40 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2189
2194
  "activitypub.activity.id": activityId ?? ""
2190
2195
  });
2191
2196
  }
2197
+ /**
2198
+ * An error that is thrown when an activity fails to send to a remote inbox.
2199
+ * It contains structured information about the failure, including the HTTP
2200
+ * status code, the inbox URL, and the response body.
2201
+ * @since 2.0.0
2202
+ */
2203
+ var SendActivityError = class extends Error {
2204
+ /**
2205
+ * The inbox URL that the activity was being sent to.
2206
+ */
2207
+ inbox;
2208
+ /**
2209
+ * The HTTP status code returned by the inbox.
2210
+ */
2211
+ statusCode;
2212
+ /**
2213
+ * The response body from the inbox, if any.
2214
+ */
2215
+ responseBody;
2216
+ /**
2217
+ * Creates a new {@link SendActivityError}.
2218
+ * @param inbox The inbox URL.
2219
+ * @param statusCode The HTTP status code.
2220
+ * @param message The error message.
2221
+ * @param responseBody The response body.
2222
+ */
2223
+ constructor(inbox, statusCode, message, responseBody) {
2224
+ super(message);
2225
+ this.name = "SendActivityError";
2226
+ this.inbox = inbox;
2227
+ this.statusCode = statusCode;
2228
+ this.responseBody = responseBody;
2229
+ }
2230
+ };
2192
2231
 
2193
2232
  //#endregion
2194
2233
  //#region src/federation/webfinger.ts
@@ -2350,6 +2389,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2350
2389
  allowPrivateAddress;
2351
2390
  userAgent;
2352
2391
  onOutboxError;
2392
+ permanentFailureStatusCodes;
2353
2393
  signatureTimeWindow;
2354
2394
  skipSignatureVerification;
2355
2395
  outboxRetryPolicy;
@@ -2431,6 +2471,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2431
2471
  }));
2432
2472
  this.userAgent = userAgent;
2433
2473
  this.onOutboxError = options.onOutboxError;
2474
+ this.permanentFailureStatusCodes = options.permanentFailureStatusCodes ?? [404, 410];
2434
2475
  this.signatureTimeWindow = options.signatureTimeWindow ?? { hours: 1 };
2435
2476
  this.skipSignatureVerification = options.skipSignatureVerification ?? false;
2436
2477
  this.outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy();
@@ -2613,13 +2654,44 @@ var FederationImpl = class extends FederationBuilderImpl {
2613
2654
  tracerProvider: this.tracerProvider
2614
2655
  });
2615
2656
  try {
2616
- this.onOutboxError?.(error, activity);
2657
+ await this.onOutboxError?.(error, activity);
2617
2658
  } catch (error$1) {
2618
2659
  logger$1.error("An unexpected error occurred in onError handler:\n{error}", {
2619
2660
  ...logData,
2620
2661
  error: error$1
2621
2662
  });
2622
2663
  }
2664
+ if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
2665
+ logger$1.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
2666
+ ...logData,
2667
+ status: error.statusCode
2668
+ });
2669
+ if (this.outboxPermanentFailureHandler != null) {
2670
+ const ctx = this.#createContext(new URL(message.baseUrl), _, { documentLoader: this.documentLoaderFactory(loaderOptions) });
2671
+ try {
2672
+ await this.outboxPermanentFailureHandler(ctx, {
2673
+ inbox: new URL(message.inbox),
2674
+ activity,
2675
+ error,
2676
+ statusCode: error.statusCode,
2677
+ actorIds: (message.actorIds ?? []).flatMap((id) => {
2678
+ try {
2679
+ return [new URL(id)];
2680
+ } catch {
2681
+ logger$1.warn("Invalid actorId URL in OutboxMessage: {id}", { id });
2682
+ return [];
2683
+ }
2684
+ })
2685
+ });
2686
+ } catch (handlerError) {
2687
+ logger$1.error("An unexpected error occurred in outboxPermanentFailureHandler:\n{error}", {
2688
+ ...logData,
2689
+ error: handlerError
2690
+ });
2691
+ }
2692
+ }
2693
+ return;
2694
+ }
2623
2695
  if (this.outboxQueue?.nativeRetrial) {
2624
2696
  logger$1.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
2625
2697
  ...logData,
@@ -2910,6 +2982,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2910
2982
  activityType: (0, __fedify_vocab.getTypeId)(activity).href,
2911
2983
  inbox,
2912
2984
  sharedInbox: inboxes[inbox].sharedInbox,
2985
+ actorIds: [...inboxes[inbox].actorIds],
2913
2986
  started: (/* @__PURE__ */ new Date()).toISOString(),
2914
2987
  attempt: 0,
2915
2988
  headers: collectionSync == null ? {} : { "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) },
@@ -4234,6 +4307,12 @@ Object.defineProperty(exports, 'RouterError', {
4234
4307
  return RouterError;
4235
4308
  }
4236
4309
  });
4310
+ Object.defineProperty(exports, 'SendActivityError', {
4311
+ enumerable: true,
4312
+ get: function () {
4313
+ return SendActivityError;
4314
+ }
4315
+ });
4237
4316
  Object.defineProperty(exports, 'buildCollectionSynchronizationHeader', {
4238
4317
  enumerable: true,
4239
4318
  get: function () {
@@ -0,0 +1,12 @@
1
+
2
+ const { Temporal } = require("@js-temporal/polyfill");
3
+ const { URLPattern } = require("urlpattern-polyfill");
4
+
5
+ require('./transformers-3g8GZwkZ.cjs');
6
+ require('./http-ChlQCtql.cjs');
7
+ const require_middleware = require('./middleware-CULfPNt-.cjs');
8
+ require('./proof-_Rz8hNBt.cjs');
9
+ require('./types-Cd_hszr_.cjs');
10
+ require('./kv-cache-DwcKE9EQ.cjs');
11
+
12
+ exports.FederationImpl = require_middleware.FederationImpl;
@@ -2,11 +2,11 @@
2
2
  import { Temporal } from "@js-temporal/polyfill";
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
 
5
- import { getDefaultActivityTransformers } from "./transformers-N_ip_y4P.js";
6
- import { deno_default, doubleKnock, exportJwk, importJwk, validateCryptoKey, verifyRequest } from "./http-7r8B3dF_.js";
7
- import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-Cg6AAAWI.js";
8
- import { getNodeInfo, nodeInfoToJson } from "./types-8l28uC8o.js";
9
- import { getAuthenticatedDocumentLoader, kvCache } from "./kv-cache-CETRZwoP.js";
5
+ import { getDefaultActivityTransformers } from "./transformers-C3FLHUd6.js";
6
+ import { deno_default, doubleKnock, exportJwk, importJwk, validateCryptoKey, verifyRequest } from "./http-DZrrJD77.js";
7
+ import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-JtZEQaKw.js";
8
+ import { getNodeInfo, nodeInfoToJson } from "./types-C93Ob9cU.js";
9
+ import { getAuthenticatedDocumentLoader, kvCache } from "./kv-cache-1TNWtgx7.js";
10
10
  import { getLogger, withContext } from "@logtape/logtape";
11
11
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
12
12
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -322,6 +322,7 @@ var FederationBuilderImpl = class {
322
322
  inboxListeners;
323
323
  inboxErrorHandler;
324
324
  sharedInboxKeyDispatcher;
325
+ outboxPermanentFailureHandler;
325
326
  idempotencyStrategy;
326
327
  collectionTypeIds;
327
328
  collectionCallbacks;
@@ -337,7 +338,7 @@ var FederationBuilderImpl = class {
337
338
  this.collectionTypeIds = {};
338
339
  }
339
340
  async build(options) {
340
- const { FederationImpl: FederationImpl$1 } = await import("./middleware-BDJNulB_.js");
341
+ const { FederationImpl: FederationImpl$1 } = await import("./middleware-BgurYNZ4.js");
341
342
  const f = new FederationImpl$1(options);
342
343
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
343
344
  f.router = this.router.clone();
@@ -359,6 +360,7 @@ var FederationBuilderImpl = class {
359
360
  f.inboxListeners = this.inboxListeners?.clone();
360
361
  f.inboxErrorHandler = this.inboxErrorHandler;
361
362
  f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
363
+ f.outboxPermanentFailureHandler = this.outboxPermanentFailureHandler;
362
364
  f.idempotencyStrategy = this.idempotencyStrategy;
363
365
  return f;
364
366
  }
@@ -840,6 +842,9 @@ var FederationBuilderImpl = class {
840
842
  const path = this.router.build(`collection:${routeName}`, values) ?? this.router.build(`orderedCollection:${routeName}`, values);
841
843
  return path;
842
844
  }
845
+ setOutboxPermanentFailureHandler(handler) {
846
+ this.outboxPermanentFailureHandler = handler;
847
+ }
843
848
  /**
844
849
  * Converts a name (string or symbol) to a unique string identifier.
845
850
  * For symbols, generates and caches a UUID if not already present.
@@ -2180,7 +2185,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2180
2185
  statusText: response.statusText,
2181
2186
  error
2182
2187
  });
2183
- throw new Error(`Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`);
2188
+ throw new SendActivityError(inbox, response.status, `Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`, error);
2184
2189
  }
2185
2190
  span.addEvent("activitypub.activity.sent", {
2186
2191
  "activitypub.activity.json": JSON.stringify(activity),
@@ -2188,6 +2193,40 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2188
2193
  "activitypub.activity.id": activityId ?? ""
2189
2194
  });
2190
2195
  }
2196
+ /**
2197
+ * An error that is thrown when an activity fails to send to a remote inbox.
2198
+ * It contains structured information about the failure, including the HTTP
2199
+ * status code, the inbox URL, and the response body.
2200
+ * @since 2.0.0
2201
+ */
2202
+ var SendActivityError = class extends Error {
2203
+ /**
2204
+ * The inbox URL that the activity was being sent to.
2205
+ */
2206
+ inbox;
2207
+ /**
2208
+ * The HTTP status code returned by the inbox.
2209
+ */
2210
+ statusCode;
2211
+ /**
2212
+ * The response body from the inbox, if any.
2213
+ */
2214
+ responseBody;
2215
+ /**
2216
+ * Creates a new {@link SendActivityError}.
2217
+ * @param inbox The inbox URL.
2218
+ * @param statusCode The HTTP status code.
2219
+ * @param message The error message.
2220
+ * @param responseBody The response body.
2221
+ */
2222
+ constructor(inbox, statusCode, message, responseBody) {
2223
+ super(message);
2224
+ this.name = "SendActivityError";
2225
+ this.inbox = inbox;
2226
+ this.statusCode = statusCode;
2227
+ this.responseBody = responseBody;
2228
+ }
2229
+ };
2191
2230
 
2192
2231
  //#endregion
2193
2232
  //#region src/federation/webfinger.ts
@@ -2349,6 +2388,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2349
2388
  allowPrivateAddress;
2350
2389
  userAgent;
2351
2390
  onOutboxError;
2391
+ permanentFailureStatusCodes;
2352
2392
  signatureTimeWindow;
2353
2393
  skipSignatureVerification;
2354
2394
  outboxRetryPolicy;
@@ -2430,6 +2470,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2430
2470
  }));
2431
2471
  this.userAgent = userAgent;
2432
2472
  this.onOutboxError = options.onOutboxError;
2473
+ this.permanentFailureStatusCodes = options.permanentFailureStatusCodes ?? [404, 410];
2433
2474
  this.signatureTimeWindow = options.signatureTimeWindow ?? { hours: 1 };
2434
2475
  this.skipSignatureVerification = options.skipSignatureVerification ?? false;
2435
2476
  this.outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy();
@@ -2612,13 +2653,44 @@ var FederationImpl = class extends FederationBuilderImpl {
2612
2653
  tracerProvider: this.tracerProvider
2613
2654
  });
2614
2655
  try {
2615
- this.onOutboxError?.(error, activity);
2656
+ await this.onOutboxError?.(error, activity);
2616
2657
  } catch (error$1) {
2617
2658
  logger$1.error("An unexpected error occurred in onError handler:\n{error}", {
2618
2659
  ...logData,
2619
2660
  error: error$1
2620
2661
  });
2621
2662
  }
2663
+ if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
2664
+ logger$1.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
2665
+ ...logData,
2666
+ status: error.statusCode
2667
+ });
2668
+ if (this.outboxPermanentFailureHandler != null) {
2669
+ const ctx = this.#createContext(new URL(message.baseUrl), _, { documentLoader: this.documentLoaderFactory(loaderOptions) });
2670
+ try {
2671
+ await this.outboxPermanentFailureHandler(ctx, {
2672
+ inbox: new URL(message.inbox),
2673
+ activity,
2674
+ error,
2675
+ statusCode: error.statusCode,
2676
+ actorIds: (message.actorIds ?? []).flatMap((id) => {
2677
+ try {
2678
+ return [new URL(id)];
2679
+ } catch {
2680
+ logger$1.warn("Invalid actorId URL in OutboxMessage: {id}", { id });
2681
+ return [];
2682
+ }
2683
+ })
2684
+ });
2685
+ } catch (handlerError) {
2686
+ logger$1.error("An unexpected error occurred in outboxPermanentFailureHandler:\n{error}", {
2687
+ ...logData,
2688
+ error: handlerError
2689
+ });
2690
+ }
2691
+ }
2692
+ return;
2693
+ }
2622
2694
  if (this.outboxQueue?.nativeRetrial) {
2623
2695
  logger$1.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
2624
2696
  ...logData,
@@ -2909,6 +2981,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2909
2981
  activityType: getTypeId(activity).href,
2910
2982
  inbox,
2911
2983
  sharedInbox: inboxes[inbox].sharedInbox,
2984
+ actorIds: [...inboxes[inbox].actorIds],
2912
2985
  started: (/* @__PURE__ */ new Date()).toISOString(),
2913
2986
  attempt: 0,
2914
2987
  headers: collectionSync == null ? {} : { "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) },
@@ -4197,4 +4270,4 @@ function getRequestId(request) {
4197
4270
  }
4198
4271
 
4199
4272
  //#endregion
4200
- export { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, Router$1 as Router, RouterError, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, respondWithObject, respondWithObjectIfAcceptable };
4273
+ export { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, Router$1 as Router, RouterError, SendActivityError, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, respondWithObject, respondWithObjectIfAcceptable };
@@ -3,24 +3,24 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import "./deno-fe0u4LiE.js";
7
- import { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, createFederation } from "./middleware-BlOT9luD.js";
6
+ import "./deno-Dhe5E7NK.js";
7
+ import { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, createFederation } from "./middleware-zvH5O0zk.js";
8
8
  import "./client-Dg7OfUDA.js";
9
9
  import "./router-D9eI0s4b.js";
10
10
  import "./types-CPz01LGH.js";
11
- import "./key-BGzsKfpZ.js";
12
- import "./http-oCBlFLKT.js";
13
- import "./ld-BaO1-A5Y.js";
14
- import "./owner-BqIhDQWW.js";
15
- import "./proof-DoHt7qrS.js";
16
- import "./docloader-C9Dmxf-K.js";
11
+ import "./key-DFPkYar3.js";
12
+ import "./http-CSqVEUdE.js";
13
+ import "./ld-kAhyoO55.js";
14
+ import "./owner-DcyH0sQg.js";
15
+ import "./proof-D7C8ouBO.js";
16
+ import "./docloader-D6VuU143.js";
17
17
  import "./kv-cache-B__dHl7g.js";
18
- import "./inbox-Dm1rfkdg.js";
19
- import "./builder-B7WWCOdc.js";
18
+ import "./inbox-9F91oWJU.js";
19
+ import "./builder-RHW0dkbP.js";
20
20
  import "./collection-CcnIw1qY.js";
21
21
  import "./keycache-DRxpZ5r9.js";
22
22
  import "./negotiation-5NPJL6zp.js";
23
23
  import "./retry-D4GJ670a.js";
24
- import "./send-CO2ZYT96.js";
24
+ import "./send-mAsnzegg.js";
25
25
 
26
26
  export { FederationImpl };
@@ -3,24 +3,24 @@
3
3
  import { URLPattern } from "urlpattern-polyfill";
4
4
  globalThis.addEventListener = () => {};
5
5
 
6
- import { deno_default } from "./deno-fe0u4LiE.js";
6
+ import { deno_default } from "./deno-Dhe5E7NK.js";
7
7
  import { getNodeInfo } from "./client-Dg7OfUDA.js";
8
8
  import { RouterError } from "./router-D9eI0s4b.js";
9
9
  import { nodeInfoToJson } from "./types-CPz01LGH.js";
10
- import { exportJwk, importJwk, validateCryptoKey } from "./key-BGzsKfpZ.js";
11
- import { verifyRequest } from "./http-oCBlFLKT.js";
12
- import { detachSignature, hasSignature, signJsonLd, verifyJsonLd } from "./ld-BaO1-A5Y.js";
13
- import { doesActorOwnKey, getKeyOwner } from "./owner-BqIhDQWW.js";
14
- import { signObject, verifyObject } from "./proof-DoHt7qrS.js";
15
- import { getAuthenticatedDocumentLoader } from "./docloader-C9Dmxf-K.js";
10
+ import { exportJwk, importJwk, validateCryptoKey } from "./key-DFPkYar3.js";
11
+ import { verifyRequest } from "./http-CSqVEUdE.js";
12
+ import { detachSignature, hasSignature, signJsonLd, verifyJsonLd } from "./ld-kAhyoO55.js";
13
+ import { doesActorOwnKey, getKeyOwner } from "./owner-DcyH0sQg.js";
14
+ import { signObject, verifyObject } from "./proof-D7C8ouBO.js";
15
+ import { getAuthenticatedDocumentLoader } from "./docloader-D6VuU143.js";
16
16
  import { kvCache } from "./kv-cache-B__dHl7g.js";
17
- import { routeActivity } from "./inbox-Dm1rfkdg.js";
18
- import { FederationBuilderImpl } from "./builder-B7WWCOdc.js";
17
+ import { routeActivity } from "./inbox-9F91oWJU.js";
18
+ import { FederationBuilderImpl } from "./builder-RHW0dkbP.js";
19
19
  import { buildCollectionSynchronizationHeader } from "./collection-CcnIw1qY.js";
20
20
  import { KvKeyCache } from "./keycache-DRxpZ5r9.js";
21
21
  import { acceptsJsonLd } from "./negotiation-5NPJL6zp.js";
22
22
  import { createExponentialBackoffPolicy } from "./retry-D4GJ670a.js";
23
- import { extractInboxes, sendActivity } from "./send-CO2ZYT96.js";
23
+ import { SendActivityError, extractInboxes, sendActivity } from "./send-mAsnzegg.js";
24
24
  import { getLogger, withContext } from "@logtape/logtape";
25
25
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
26
26
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1307,6 +1307,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1307
1307
  allowPrivateAddress;
1308
1308
  userAgent;
1309
1309
  onOutboxError;
1310
+ permanentFailureStatusCodes;
1310
1311
  signatureTimeWindow;
1311
1312
  skipSignatureVerification;
1312
1313
  outboxRetryPolicy;
@@ -1388,6 +1389,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1388
1389
  }));
1389
1390
  this.userAgent = userAgent;
1390
1391
  this.onOutboxError = options.onOutboxError;
1392
+ this.permanentFailureStatusCodes = options.permanentFailureStatusCodes ?? [404, 410];
1391
1393
  this.signatureTimeWindow = options.signatureTimeWindow ?? { hours: 1 };
1392
1394
  this.skipSignatureVerification = options.skipSignatureVerification ?? false;
1393
1395
  this.outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy();
@@ -1570,13 +1572,44 @@ var FederationImpl = class extends FederationBuilderImpl {
1570
1572
  tracerProvider: this.tracerProvider
1571
1573
  });
1572
1574
  try {
1573
- this.onOutboxError?.(error, activity);
1575
+ await this.onOutboxError?.(error, activity);
1574
1576
  } catch (error$1) {
1575
1577
  logger$2.error("An unexpected error occurred in onError handler:\n{error}", {
1576
1578
  ...logData,
1577
1579
  error: error$1
1578
1580
  });
1579
1581
  }
1582
+ if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
1583
+ logger$2.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
1584
+ ...logData,
1585
+ status: error.statusCode
1586
+ });
1587
+ if (this.outboxPermanentFailureHandler != null) {
1588
+ const ctx = this.#createContext(new URL(message.baseUrl), _, { documentLoader: this.documentLoaderFactory(loaderOptions) });
1589
+ try {
1590
+ await this.outboxPermanentFailureHandler(ctx, {
1591
+ inbox: new URL(message.inbox),
1592
+ activity,
1593
+ error,
1594
+ statusCode: error.statusCode,
1595
+ actorIds: (message.actorIds ?? []).flatMap((id) => {
1596
+ try {
1597
+ return [new URL(id)];
1598
+ } catch {
1599
+ logger$2.warn("Invalid actorId URL in OutboxMessage: {id}", { id });
1600
+ return [];
1601
+ }
1602
+ })
1603
+ });
1604
+ } catch (handlerError) {
1605
+ logger$2.error("An unexpected error occurred in outboxPermanentFailureHandler:\n{error}", {
1606
+ ...logData,
1607
+ error: handlerError
1608
+ });
1609
+ }
1610
+ }
1611
+ return;
1612
+ }
1580
1613
  if (this.outboxQueue?.nativeRetrial) {
1581
1614
  logger$2.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
1582
1615
  ...logData,
@@ -1867,6 +1900,7 @@ var FederationImpl = class extends FederationBuilderImpl {
1867
1900
  activityType: getTypeId(activity).href,
1868
1901
  inbox,
1869
1902
  sharedInbox: inboxes[inbox].sharedInbox,
1903
+ actorIds: [...inboxes[inbox].actorIds],
1870
1904
  started: (/* @__PURE__ */ new Date()).toISOString(),
1871
1905
  attempt: 0,
1872
1906
  headers: collectionSync == null ? {} : { "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) },
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { ActivityTransformer, Context } from "./context-BNNWbaZL.js";
3
+ import { ActivityTransformer, Context } from "./context-liIe6DFH.js";
4
4
  import { Activity } from "@fedify/vocab";
5
5
 
6
6
  //#region src/compat/transformers.d.ts
@@ -0,0 +1,9 @@
1
+ import "node:module";
2
+
3
+ //#region rolldown:runtime
4
+
5
+ import * as import___fedify_vocab_runtime from "@fedify/vocab-runtime";
6
+ __reExport(mod_d_exports, import___fedify_vocab_runtime);
7
+
8
+ //#endregion
9
+ export { __export, __reExport, mod_d_exports };
@@ -1,4 +1,4 @@
1
- import { KeyCache } from "./http-ClB3pLcL.cjs";
1
+ import { KeyCache } from "./http-CCEu-x1_.cjs";
2
2
  import { CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "@fedify/vocab";
3
3
  import { DocumentLoader } from "@fedify/vocab-runtime";
4
4
  import { TracerProvider } from "@opentelemetry/api";
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { HttpMessageSignaturesSpecDeterminer } from "./http-DLBDPal9.js";
4
- import { KvKey, KvStore } from "./kv-CYySNrsn.js";
3
+ import { HttpMessageSignaturesSpecDeterminer } from "./http-CODSJcKx.js";
4
+ import { KvKey, KvStore } from "./kv-jg_8SMc1.js";
5
5
  import { TracerProvider } from "@opentelemetry/api";
6
6
  import { DocumentLoader, DocumentLoaderFactoryOptions } from "@fedify/vocab-runtime";
7
7
 
@@ -0,0 +1,7 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import { URLPattern } from "urlpattern-polyfill";
3
+ import * as import___fedify_vocab_runtime from "@fedify/vocab-runtime";
4
+ __reExport(mod_d_exports, import___fedify_vocab_runtime);
5
+
6
+ //#endregion
7
+ export { mod_d_exports };
@@ -1,5 +1,5 @@
1
- import { HttpMessageSignaturesSpecDeterminer } from "./http-ClB3pLcL.cjs";
2
- import { KvKey, KvStore } from "./kv-B4vFhIYL.cjs";
1
+ import { HttpMessageSignaturesSpecDeterminer } from "./http-CCEu-x1_.cjs";
2
+ import { KvKey, KvStore } from "./kv-g9jFc34-.cjs";
3
3
  import { DocumentLoader, DocumentLoaderFactoryOptions } from "@fedify/vocab-runtime";
4
4
  import { TracerProvider } from "@opentelemetry/api";
5
5
 
@@ -1,4 +1,4 @@
1
- import { ActorAliasMapper, ActorDispatcher, ActorHandleMapper, RequestContext, WebFingerLinksDispatcher } from "./context-D7JEVvXJ.cjs";
1
+ import { ActorAliasMapper, ActorDispatcher, ActorHandleMapper, RequestContext, WebFingerLinksDispatcher } from "./context-Cf0-LmZC.cjs";
2
2
  import { Span, Tracer } from "@opentelemetry/api";
3
3
 
4
4
  //#region src/federation/webfinger.d.ts
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { ActorAliasMapper, ActorDispatcher, ActorHandleMapper, RequestContext, WebFingerLinksDispatcher } from "./context-BNNWbaZL.js";
3
+ import { ActorAliasMapper, ActorDispatcher, ActorHandleMapper, RequestContext, WebFingerLinksDispatcher } from "./context-liIe6DFH.js";
4
4
  import { Span, Tracer } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/federation/webfinger.d.ts
@@ -1,4 +1,4 @@
1
- import { ActivityTransformer, Context } from "./context-D7JEVvXJ.cjs";
1
+ import { ActivityTransformer, Context } from "./context-Cf0-LmZC.cjs";
2
2
  import { Activity } from "@fedify/vocab";
3
3
 
4
4
  //#region src/compat/transformers.d.ts