@fedify/fedify 2.4.0-dev.1964 → 2.4.0-dev.1995

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 (94) hide show
  1. package/dist/{builder-B4zpKIFU.mjs → builder-D0DxgOV5.mjs} +2 -2
  2. package/dist/{client-CtxvmazV.mjs → client-DpnpgjyX.mjs} +78 -4
  3. package/dist/compat/mod.d.cts +1 -1
  4. package/dist/compat/mod.d.ts +1 -1
  5. package/dist/compat/transformers.test.mjs +1 -1
  6. package/dist/compound-proof-CJnWc6c-.mjs +495 -0
  7. package/dist/{context-COLwHogJ.d.cts → context-BeDnDuF3.d.cts} +4 -3
  8. package/dist/{context-DiiCt4S7.d.ts → context-uyRUWoZQ.d.ts} +4 -3
  9. package/dist/{deno-CtG93ohj.mjs → deno-CABhzCb_.mjs} +1 -1
  10. package/dist/{docloader-dk_k3S8d.mjs → docloader-BbGSL0Xq.mjs} +2 -2
  11. package/dist/federation/builder.test.mjs +1 -1
  12. package/dist/federation/handler-compound-proof.test.d.mts +2 -0
  13. package/dist/federation/handler-compound-proof.test.mjs +152 -0
  14. package/dist/federation/handler.test.mjs +122 -4
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/keycache.test.mjs +52 -9
  17. package/dist/federation/metrics.test.mjs +1 -1
  18. package/dist/federation/middleware.test.mjs +111 -15
  19. package/dist/federation/mod.cjs +1 -1
  20. package/dist/federation/mod.d.cts +2 -2
  21. package/dist/federation/mod.d.ts +2 -2
  22. package/dist/federation/mod.js +1 -1
  23. package/dist/federation/send.test.mjs +139 -4
  24. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  25. package/dist/federation/tasks/tasks.test.mjs +2 -2
  26. package/dist/federation/temporal.test.mjs +1 -1
  27. package/dist/federation/webfinger.test.mjs +1 -1
  28. package/dist/{federation-Drjlrrax.cjs → federation-DCEHQk4G.cjs} +632 -57
  29. package/dist/{http-6TI0tI03.d.cts → http-65PYi9jY.d.ts} +34 -2
  30. package/dist/{http-Dj4s1UQ0.js → http-9WyuldYh.js} +170 -8
  31. package/dist/{http-CdrSn2ip.d.ts → http-CP-7OdSq.d.cts} +34 -2
  32. package/dist/{http-B3skRvGo.cjs → http-CRFns-UE.cjs} +181 -7
  33. package/dist/{http-D7LX-BL9.mjs → http-D9urSO2D.mjs} +3 -3
  34. package/dist/{key-BVjgbs_9.mjs → key-Ccs8cnd7.mjs} +169 -7
  35. package/dist/{keycache-ZLqIfrkL.mjs → keycache-BUDHB5rY.mjs} +12 -4
  36. package/dist/{kv-cache-DtsjH_bY.cjs → kv-cache-DXT9vmIg.cjs} +2 -2
  37. package/dist/{kv-cache-tGNbvDCF.js → kv-cache-DtmXhPXG.js} +2 -2
  38. package/dist/{kv-cache-xRcC_xxP.mjs → kv-cache-lKyFn_Dn.mjs} +1 -1
  39. package/dist/{ld-OuCeQFny.mjs → ld-qup__MAW.mjs} +3 -3
  40. package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
  41. package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
  42. package/dist/{metrics-B9N27cCB.mjs → metrics-CISXCvB1.mjs} +1 -1
  43. package/dist/{middleware-TeLjzoxn.mjs → middleware-CzvJvPHK.mjs} +58 -15
  44. package/dist/{middleware-Cd_vPqDH.mjs → middleware-DkrU2WhY.mjs} +1 -1
  45. package/dist/{middleware-CPTDFMmJ.js → middleware-DsfWajaD.js} +593 -18
  46. package/dist/{mod-DypxPS9H.d.ts → mod-C0BYc0OU.d.ts} +1 -1
  47. package/dist/{mod-CnGLNoVw.d.cts → mod-CbKDOnCt.d.cts} +1 -1
  48. package/dist/{mod-CLHkCwLm.d.cts → mod-CyiSjRkk.d.cts} +1 -1
  49. package/dist/{mod-CSH1Ee-I.d.ts → mod-D882_Xsg.d.ts} +1 -1
  50. package/dist/{mod-DzRXACM5.d.ts → mod-UDwMjuHM.d.ts} +1 -1
  51. package/dist/{mod-BZldCEU0.d.cts → mod-x9W0d0Pk.d.cts} +1 -1
  52. package/dist/mod.cjs +20 -20
  53. package/dist/mod.d.cts +6 -6
  54. package/dist/mod.d.ts +6 -6
  55. package/dist/mod.js +5 -5
  56. package/dist/nodeinfo/client.test.mjs +28 -1
  57. package/dist/nodeinfo/handler.test.mjs +1 -1
  58. package/dist/nodeinfo/mod.cjs +1 -1
  59. package/dist/nodeinfo/mod.js +1 -1
  60. package/dist/{owner-DGSfntI-.d.ts → owner-BF0L9cMt.d.cts} +12 -1
  61. package/dist/{proof-BO_esQii.js → owner-BIPEZGiU.js} +1255 -1098
  62. package/dist/{owner-r_waTiQj.d.cts → owner-BSzr5-I8.d.ts} +12 -1
  63. package/dist/owner-CRoq8Spb.mjs +175 -0
  64. package/dist/{proof-Dua0d906.cjs → owner-CVA7L9MA.cjs} +1266 -1097
  65. package/dist/{proof-D5Ajk4DJ.mjs → proof-BDxNVZ3E.mjs} +186 -83
  66. package/dist/{send-DVXyUqhO.mjs → send-BzM5GLyn.mjs} +68 -11
  67. package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
  68. package/dist/sig/compound-proof-discovery.test.mjs +331 -0
  69. package/dist/sig/compound-proof-verification.test.d.mts +2 -0
  70. package/dist/sig/compound-proof-verification.test.mjs +465 -0
  71. package/dist/sig/compound-proof.test.d.mts +2 -0
  72. package/dist/sig/compound-proof.test.mjs +324 -0
  73. package/dist/sig/http.test.mjs +2 -2
  74. package/dist/sig/key.test.mjs +169 -2
  75. package/dist/sig/ld.test.mjs +55 -2
  76. package/dist/sig/mod.cjs +17 -17
  77. package/dist/sig/mod.d.cts +3 -3
  78. package/dist/sig/mod.d.ts +3 -3
  79. package/dist/sig/mod.js +2 -2
  80. package/dist/sig/owner.test.mjs +103 -4
  81. package/dist/sig/proof.test.mjs +120 -1
  82. package/dist/{temporal-BoDw51A-.mjs → temporal-Dv6Qv-8k.mjs} +1 -1
  83. package/dist/testing/kv.test.mjs +1 -1
  84. package/dist/testing/mod.d.mts +2 -1
  85. package/dist/{types-RXm5YxpC.cjs → types-Be2zbyeG.cjs} +94 -2
  86. package/dist/{types-Dtyf8lVj.js → types-C_cNlNVK.js} +78 -4
  87. package/dist/utils/docloader.test.mjs +27 -3
  88. package/dist/utils/kv-cache.test.mjs +1 -1
  89. package/dist/utils/mod.cjs +1 -1
  90. package/dist/utils/mod.d.cts +1 -1
  91. package/dist/utils/mod.d.ts +1 -1
  92. package/dist/utils/mod.js +1 -1
  93. package/package.json +6 -6
  94. package/dist/owner-DTEqTzSr.mjs +0 -120
@@ -16,14 +16,14 @@ import "../std__assert-CxFT0MNt.mjs";
16
16
  import { t as assertRejects } from "../assert_rejects-wFbSPn1O.mjs";
17
17
  import { t as assertStrictEquals } from "../assert_strict_equals-Bpjl4Psw.mjs";
18
18
  import { t as assert } from "../assert-CebeUf0C.mjs";
19
- import { g as recordInboxActivity } from "../metrics-B9N27cCB.mjs";
20
- import { l as verifyRequest, s as signRequest } from "../http-D7LX-BL9.mjs";
19
+ import { g as recordInboxActivity } from "../metrics-CISXCvB1.mjs";
20
+ import { l as verifyRequest, s as signRequest } from "../http-D9urSO2D.mjs";
21
21
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
22
- import { t as getAuthenticatedDocumentLoader } from "../docloader-dk_k3S8d.mjs";
23
- import { g as handleBenchmarkTrigger, i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-TeLjzoxn.mjs";
24
- import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-OuCeQFny.mjs";
25
- import { t as doesActorOwnKey } from "../owner-DTEqTzSr.mjs";
26
- import { i as verifyObject, r as signObject } from "../proof-D5Ajk4DJ.mjs";
22
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-BbGSL0Xq.mjs";
23
+ import { g as handleBenchmarkTrigger, i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-CzvJvPHK.mjs";
24
+ import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-qup__MAW.mjs";
25
+ import { t as doesActorOwnKey } from "../owner-CRoq8Spb.mjs";
26
+ import { a as verifyObject, r as signObject } from "../proof-BDxNVZ3E.mjs";
27
27
  import { t as CircuitBreaker } from "../circuit-breaker-C5NqoLBJ.mjs";
28
28
  import { t as TaskCodec } from "../codec-C6rTrpIp.mjs";
29
29
  import { t as markCircuitBreakerLegacySweepDone } from "../circuit-breaker-test-utils-DW6YC_Pe.mjs";
@@ -33,7 +33,7 @@ import * as vocab from "@fedify/vocab";
33
33
  import { Create, Note, Offer, Person, getTypeId, lookupObject } from "@fedify/vocab";
34
34
  import { SpanStatusCode, metrics } from "@opentelemetry/api";
35
35
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
36
- import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
36
+ import { FetchError, UrlError, getDocumentLoader } from "@fedify/vocab-runtime";
37
37
  import { deepStrictEqual, ok, rejects, strictEqual } from "node:assert/strict";
38
38
  import serialize from "json-canon";
39
39
  import { DataPointType, MeterProvider as MeterProvider$1, MetricReader } from "@opentelemetry/sdk-metrics";
@@ -2165,7 +2165,7 @@ test("Federation.setOutboxListeners()", async (t) => {
2165
2165
  const records = [];
2166
2166
  await reset();
2167
2167
  esm_default.spyGlobal();
2168
- esm_default.post("https://remote.example/inbox", {
2168
+ esm_default.post("https://example.com/inbox", {
2169
2169
  status: 202,
2170
2170
  body: "Accepted"
2171
2171
  });
@@ -2191,7 +2191,7 @@ test("Federation.setOutboxListeners()", async (t) => {
2191
2191
  federation.setOutboxListeners("/users/{identifier}/outbox").on(vocab.Activity, async (ctx, activity) => {
2192
2192
  await ctx.sendActivity({ identifier: ctx.identifier }, new vocab.Person({
2193
2193
  id: new URL("https://remote.example/users/alice"),
2194
- inbox: new URL("https://remote.example/inbox")
2194
+ inbox: new URL("https://example.com/inbox")
2195
2195
  }), activity);
2196
2196
  }).authorize((ctx, identifier) => {
2197
2197
  return identifier === "john" && ctx.request.headers.get("authorization") === "Bearer token";
@@ -2267,7 +2267,7 @@ test("Federation.setOutboxListeners()", async (t) => {
2267
2267
  let ldsVerified = false;
2268
2268
  await reset();
2269
2269
  esm_default.spyGlobal();
2270
- esm_default.post("https://remote.example/inbox", async (cl) => {
2270
+ esm_default.post("https://example.com/inbox", async (cl) => {
2271
2271
  const verifyOptions = {
2272
2272
  documentLoader: mockDocumentLoader,
2273
2273
  contextLoader: mockDocumentLoader
@@ -2300,7 +2300,7 @@ test("Federation.setOutboxListeners()", async (t) => {
2300
2300
  keyId: rsaPublicKey2.id
2301
2301
  }], {
2302
2302
  id: new URL("https://remote.example/users/alice"),
2303
- inboxId: new URL("https://remote.example/inbox")
2303
+ inboxId: new URL("https://example.com/inbox")
2304
2304
  }, { skipIfUnsigned: true });
2305
2305
  }).authorize((ctx, identifier) => {
2306
2306
  return identifier === "person2" && ctx.request.headers.get("authorization") === "Bearer token";
@@ -3110,6 +3110,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
3110
3110
  const kv = new MemoryKvStore();
3111
3111
  const queuedMessages = [];
3112
3112
  const federation = new FederationImpl({
3113
+ allowPrivateAddress: true,
3113
3114
  kv,
3114
3115
  queue: {
3115
3116
  nativeRetrial: true,
@@ -3172,6 +3173,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
3172
3173
  const kv = new MemoryKvStore();
3173
3174
  let queuedMessages = [];
3174
3175
  const federation = new FederationImpl({
3176
+ allowPrivateAddress: true,
3175
3177
  kv,
3176
3178
  queue: {
3177
3179
  enqueue(message, _options) {
@@ -3242,6 +3244,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
3242
3244
  const kv = new MemoryKvStore();
3243
3245
  const [meterProvider, recorder] = createTestMeterProvider();
3244
3246
  await new FederationImpl({
3247
+ allowPrivateAddress: true,
3245
3248
  kv,
3246
3249
  meterProvider,
3247
3250
  queue: {
@@ -3284,6 +3287,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
3284
3287
  const kv = new MemoryKvStore();
3285
3288
  const [meterProvider, recorder] = createTestMeterProvider();
3286
3289
  await new FederationImpl({
3290
+ allowPrivateAddress: true,
3287
3291
  kv,
3288
3292
  meterProvider,
3289
3293
  queue: {
@@ -4972,6 +4976,7 @@ test("FederationImpl.processQueuedTask() permanent failure", async (t) => {
4972
4976
  return Promise.resolve();
4973
4977
  }
4974
4978
  },
4979
+ allowPrivateAddress: true,
4975
4980
  ...options.permanentFailureStatusCodes ? { permanentFailureStatusCodes: options.permanentFailureStatusCodes } : {},
4976
4981
  ...options.meterProvider ? { meterProvider: options.meterProvider } : {},
4977
4982
  ...options.tracerProvider ? { tracerProvider: options.tracerProvider } : {}
@@ -5170,6 +5175,7 @@ test("FederationImpl.processQueuedTask() circuit breaker", async (t) => {
5170
5175
  return Promise.resolve();
5171
5176
  }
5172
5177
  },
5178
+ allowPrivateAddress: true,
5173
5179
  circuitBreaker: options,
5174
5180
  ...federationOptions
5175
5181
  });
@@ -6183,7 +6189,8 @@ test("FederationImpl.processQueuedTask() queue task metrics", async (t) => {
6183
6189
  listen(_handler, _options) {
6184
6190
  return Promise.resolve();
6185
6191
  }
6186
- }
6192
+ },
6193
+ allowPrivateAddress: true
6187
6194
  });
6188
6195
  federation.setInboxListeners("/users/{identifier}/inbox", "/inbox");
6189
6196
  esm_default.spyGlobal();
@@ -7523,6 +7530,7 @@ test("createFederation() applies publicKeyTtl to cached public keys", async () =
7523
7530
  const publicKeyKey = [
7524
7531
  "_fedify",
7525
7532
  "publicKey",
7533
+ "2",
7526
7534
  keyId
7527
7535
  ];
7528
7536
  assertEquals((await deliver()).status, 202);
@@ -7530,10 +7538,11 @@ test("createFederation() applies publicKeyTtl to cached public keys", async () =
7530
7538
  assert(keyFetches > 0);
7531
7539
  assert(await kv.get(publicKeyKey) != null);
7532
7540
  assertEquals(kv.lastTtl(publicKeyKey)?.total("day"), 7);
7533
- keyFetches = 0;
7541
+ const keyCacheWrites = () => kv.writes.filter((w) => w.key.length === publicKeyKey.length && w.key.every((part, i) => part === publicKeyKey[i])).length;
7542
+ const warmWrites = keyCacheWrites();
7534
7543
  assertEquals((await deliver()).status, 202);
7535
7544
  assertEquals(inbox.length, 2);
7536
- assertEquals(keyFetches, 0);
7545
+ assertEquals(keyCacheWrites(), warmWrites);
7537
7546
  kv.advance({ days: 8 });
7538
7547
  assertEquals(await kv.get(publicKeyKey), void 0);
7539
7548
  keyFetches = 0;
@@ -7786,5 +7795,92 @@ test("ContextImpl.enqueueTaskMany()", async (t) => {
7786
7795
  strictEqual(queue.enqueued.length, 0);
7787
7796
  });
7788
7797
  });
7798
+ test("ContextImpl.sendActivity() honors the private-address policy", async (t) => {
7799
+ for (const allowPrivateAddress of [false, true]) await t.step(`allowPrivateAddress: ${allowPrivateAddress}`, async () => {
7800
+ const inbox = "http://127.0.0.1/inbox";
7801
+ esm_default.mockGlobal().post(inbox, 202);
7802
+ try {
7803
+ const ctx = createFederation({
7804
+ kv: new MemoryKvStore(),
7805
+ allowPrivateAddress
7806
+ }).createContext(new URL("https://example.com/"));
7807
+ const send = () => ctx.sendActivity({
7808
+ privateKey: ed25519PrivateKey,
7809
+ keyId: ed25519Multikey.id
7810
+ }, new Person({
7811
+ id: new URL("https://example.com/recipient"),
7812
+ inbox: new URL(inbox)
7813
+ }), new Create({
7814
+ id: new URL("https://example.com/activity"),
7815
+ actor: new URL("https://example.com/person")
7816
+ }), { immediate: true });
7817
+ if (allowPrivateAddress) {
7818
+ await send();
7819
+ assertEquals(esm_default.callHistory.calls(inbox).length, 1);
7820
+ } else {
7821
+ await assertRejects(send, UrlError);
7822
+ assertEquals(esm_default.callHistory.calls(inbox).length, 0);
7823
+ }
7824
+ } finally {
7825
+ esm_default.hardReset();
7826
+ }
7827
+ });
7828
+ });
7829
+ test("Federation.fetch() bounds inbox bodies before dispatch", async () => {
7830
+ let dispatched = false;
7831
+ const json = JSON.stringify({
7832
+ "@context": "https://www.w3.org/ns/activitystreams",
7833
+ id: "https://example.com/activities/bounded",
7834
+ type: "Create",
7835
+ actor: "https://example.com/actor"
7836
+ });
7837
+ const federation = createFederation({
7838
+ kv: new MemoryKvStore(),
7839
+ skipSignatureVerification: true,
7840
+ contextLoaderFactory: () => mockDocumentLoader
7841
+ });
7842
+ federation.setActorDispatcher("/actors/{identifier}", () => new Person({ id: new URL("https://example.com/actor") }));
7843
+ federation.setInboxListeners("/actors/{identifier}/inbox", "/inbox").on(Create, () => {
7844
+ dispatched = true;
7845
+ });
7846
+ for (const contentLength of [
7847
+ void 0,
7848
+ "1",
7849
+ String(16777217)
7850
+ ]) {
7851
+ assertEquals((await federation.fetch(new Request("https://example.com/inbox", {
7852
+ method: "POST",
7853
+ headers: contentLength == null ? {} : { "Content-Length": contentLength },
7854
+ body: json.padEnd(16777217)
7855
+ }), { contextData: void 0 })).status, 413);
7856
+ assertFalse(dispatched);
7857
+ }
7858
+ let canceled = false;
7859
+ let pulls = 0;
7860
+ const body = new ReadableStream({
7861
+ pull(controller) {
7862
+ pulls++;
7863
+ controller.enqueue(new Uint8Array(64 * 1024));
7864
+ },
7865
+ cancel() {
7866
+ canceled = true;
7867
+ }
7868
+ }, { highWaterMark: 0 });
7869
+ const request = new Request("https://example.com/inbox", {
7870
+ method: "POST",
7871
+ body,
7872
+ duplex: "half"
7873
+ });
7874
+ assertEquals((await federation.fetch(request, { contextData: void 0 })).status, 413);
7875
+ await new Promise((resolve) => setTimeout(resolve, 0));
7876
+ assert(canceled);
7877
+ assert(pulls <= 260);
7878
+ assertFalse(dispatched);
7879
+ assertEquals((await federation.fetch(new Request("https://example.com/inbox", {
7880
+ method: "POST",
7881
+ body: json
7882
+ }), { contextData: void 0 })).status, 202);
7883
+ assert(dispatched);
7884
+ });
7789
7885
  //#endregion
7790
7886
  export {};
@@ -1,6 +1,6 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_federation = require("../federation-Drjlrrax.cjs");
3
+ const require_federation = require("../federation-DCEHQk4G.cjs");
4
4
  exports.CircuitBreaker = require_federation.CircuitBreaker;
5
5
  exports.InProcessMessageQueue = require_federation.InProcessMessageQueue;
6
6
  exports.MemoryKvStore = require_federation.MemoryKvStore;
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { $ as MessageQueueDepth, A as OutboxListenerSetters, At as ObjectAuthorizePredicate, B as TaskEnqueueOptions, Bt as SendActivityError, C as FederationStartQueueOptions, Ct as CustomCollectionCounter, D as InboxListenerSetters, Dt as InboxListener, E as InboxChallengePolicy, Et as InboxErrorHandler, F as createFederation, Ft as OutboxPermanentFailureHandler, G as RetryPolicy, H as TaskRegistry, Ht as PageItems, I as Message, It as SharedInboxKeyDispatcher, J as respondWithObject, K as createExponentialBackoffPolicy, L as createFederationBuilder, Lt as UnverifiedActivityHandler, M as FederationKvPrefixes, Mt as OutboxErrorHandler, N as FederationOrigin, Nt as OutboxListener, O as MediaUploaderSetters, Ot as MediaUploaderCallback, P as FederationQueueOptions, Pt as OutboxListenerErrorHandler, Q as MessageQueue, R as TaskDefinition, Rt as UnverifiedActivityReason, S as FederationOptions, St as CollectionDispatcher, T as IdempotencyStrategy, Tt as CustomCollectionDispatcher, U as CreateExponentialBackoffPolicyOptions, Ut as buildCollectionSynchronizationHeader, V as TaskHandler, Vt as SenderKeyPair, W as RetryContext, Wt as digest, X as InProcessMessageQueue, Y as respondWithObjectIfAcceptable, Z as InProcessMessageQueueOptions, _ as Federatable, _t as ActorHandleMapper, a as GetSignedKeyOptions, at as CircuitBreakerBeforeSendDecision, b as FederationBuilder, bt as CollectionCounter, c as ParseUriResult, ct as CircuitBreakerKvState, d as SendActivityOptions, dt as CircuitBreakerStateChange, et as MessageQueueEnqueueOptions, f as SendActivityOptionsForCollection, ft as NormalizedCircuitBreakerOptions, g as CustomCollectionCallbackSetters, gt as ActorDispatcher, h as ConstructorWithTypeId, ht as ActorAliasMapper, i as GetActorOptions, it as CircuitBreakerActivityDrop, j as Rfc6570Expression, jt as ObjectDispatcher, k as ObjectCallbackSetters, kt as NodeInfoDispatcher, l as RequestContext, lt as CircuitBreakerOptions, m as CollectionCallbackSetters, mt as parseCircuitBreakerKvState, n as Context, nt as ParallelMessageQueue, o as InboxContext, ot as CircuitBreakerCreateOptions, p as ActorCallbackSetters, pt as normalizeCircuitBreakerOptions, q as RespondWithObjectOptions, r as ForwardActivityOptions, rt as CircuitBreaker, s as OutboxContext, st as CircuitBreakerFailurePolicy, t as ActorKeyPair, tt as MessageQueueListenOptions, u as RouteActivityOptions, ut as CircuitBreakerState, v as Federation, vt as ActorKeyPairsDispatcher, w as IdempotencyKeyCallback, wt as CustomCollectionCursor, x as FederationFetchOptions, xt as CollectionCursor, y as FederationBenchmarkOptions, yt as AuthorizePredicate, z as TaskDefinitionOptions, zt as WebFingerLinksDispatcher } from "../context-COLwHogJ.cjs";
2
+ import { $ as MessageQueueDepth, A as OutboxListenerSetters, At as ObjectAuthorizePredicate, B as TaskEnqueueOptions, Bt as SendActivityError, C as FederationStartQueueOptions, Ct as CustomCollectionCounter, D as InboxListenerSetters, Dt as InboxListener, E as InboxChallengePolicy, Et as InboxErrorHandler, F as createFederation, Ft as OutboxPermanentFailureHandler, G as RetryPolicy, H as TaskRegistry, Ht as PageItems, I as Message, It as SharedInboxKeyDispatcher, J as respondWithObject, K as createExponentialBackoffPolicy, L as createFederationBuilder, Lt as UnverifiedActivityHandler, M as FederationKvPrefixes, Mt as OutboxErrorHandler, N as FederationOrigin, Nt as OutboxListener, O as MediaUploaderSetters, Ot as MediaUploaderCallback, P as FederationQueueOptions, Pt as OutboxListenerErrorHandler, Q as MessageQueue, R as TaskDefinition, Rt as UnverifiedActivityReason, S as FederationOptions, St as CollectionDispatcher, T as IdempotencyStrategy, Tt as CustomCollectionDispatcher, U as CreateExponentialBackoffPolicyOptions, Ut as buildCollectionSynchronizationHeader, V as TaskHandler, Vt as SenderKeyPair, W as RetryContext, Wt as digest, X as InProcessMessageQueue, Y as respondWithObjectIfAcceptable, Z as InProcessMessageQueueOptions, _ as Federatable, _t as ActorHandleMapper, a as GetSignedKeyOptions, at as CircuitBreakerBeforeSendDecision, b as FederationBuilder, bt as CollectionCounter, c as ParseUriResult, ct as CircuitBreakerKvState, d as SendActivityOptions, dt as CircuitBreakerStateChange, et as MessageQueueEnqueueOptions, f as SendActivityOptionsForCollection, ft as NormalizedCircuitBreakerOptions, g as CustomCollectionCallbackSetters, gt as ActorDispatcher, h as ConstructorWithTypeId, ht as ActorAliasMapper, i as GetActorOptions, it as CircuitBreakerActivityDrop, j as Rfc6570Expression, jt as ObjectDispatcher, k as ObjectCallbackSetters, kt as NodeInfoDispatcher, l as RequestContext, lt as CircuitBreakerOptions, m as CollectionCallbackSetters, mt as parseCircuitBreakerKvState, n as Context, nt as ParallelMessageQueue, o as InboxContext, ot as CircuitBreakerCreateOptions, p as ActorCallbackSetters, pt as normalizeCircuitBreakerOptions, q as RespondWithObjectOptions, r as ForwardActivityOptions, rt as CircuitBreaker, s as OutboxContext, st as CircuitBreakerFailurePolicy, t as ActorKeyPair, tt as MessageQueueListenOptions, u as RouteActivityOptions, ut as CircuitBreakerState, v as Federation, vt as ActorKeyPairsDispatcher, w as IdempotencyKeyCallback, wt as CustomCollectionCursor, x as FederationFetchOptions, xt as CollectionCursor, y as FederationBenchmarkOptions, yt as AuthorizePredicate, z as TaskDefinitionOptions, zt as WebFingerLinksDispatcher } from "../context-BeDnDuF3.cjs";
3
3
  import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-BhNbN8Ed.cjs";
4
- import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-BZldCEU0.cjs";
4
+ import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-x9W0d0Pk.cjs";
5
5
  export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CircuitBreaker, CircuitBreakerActivityDrop, CircuitBreakerBeforeSendDecision, CircuitBreakerCreateOptions, CircuitBreakerFailurePolicy, CircuitBreakerKvState, CircuitBreakerOptions, CircuitBreakerState, CircuitBreakerStateChange, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBenchmarkOptions, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetActorOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MediaUploaderCallback, MediaUploaderSetters, MemoryKvStore, Message, MessageQueue, MessageQueueDepth, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, NormalizedCircuitBreakerOptions, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxContext, OutboxErrorHandler, OutboxListener, OutboxListenerErrorHandler, OutboxListenerSetters, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, TaskDefinition, TaskDefinitionOptions, TaskEnqueueOptions, TaskHandler, TaskRegistry, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, normalizeCircuitBreakerOptions, parseCircuitBreakerKvState, respondWithObject, respondWithObjectIfAcceptable };
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { $ as MessageQueueDepth, A as OutboxListenerSetters, At as ObjectAuthorizePredicate, B as TaskEnqueueOptions, Bt as SendActivityError, C as FederationStartQueueOptions, Ct as CustomCollectionCounter, D as InboxListenerSetters, Dt as InboxListener, E as InboxChallengePolicy, Et as InboxErrorHandler, F as createFederation, Ft as OutboxPermanentFailureHandler, G as RetryPolicy, H as TaskRegistry, Ht as PageItems, I as Message, It as SharedInboxKeyDispatcher, J as respondWithObject, K as createExponentialBackoffPolicy, L as createFederationBuilder, Lt as UnverifiedActivityHandler, M as FederationKvPrefixes, Mt as OutboxErrorHandler, N as FederationOrigin, Nt as OutboxListener, O as MediaUploaderSetters, Ot as MediaUploaderCallback, P as FederationQueueOptions, Pt as OutboxListenerErrorHandler, Q as MessageQueue, R as TaskDefinition, Rt as UnverifiedActivityReason, S as FederationOptions, St as CollectionDispatcher, T as IdempotencyStrategy, Tt as CustomCollectionDispatcher, U as CreateExponentialBackoffPolicyOptions, Ut as buildCollectionSynchronizationHeader, V as TaskHandler, Vt as SenderKeyPair, W as RetryContext, Wt as digest, X as InProcessMessageQueue, Y as respondWithObjectIfAcceptable, Z as InProcessMessageQueueOptions, _ as Federatable, _t as ActorHandleMapper, a as GetSignedKeyOptions, at as CircuitBreakerBeforeSendDecision, b as FederationBuilder, bt as CollectionCounter, c as ParseUriResult, ct as CircuitBreakerKvState, d as SendActivityOptions, dt as CircuitBreakerStateChange, et as MessageQueueEnqueueOptions, f as SendActivityOptionsForCollection, ft as NormalizedCircuitBreakerOptions, g as CustomCollectionCallbackSetters, gt as ActorDispatcher, h as ConstructorWithTypeId, ht as ActorAliasMapper, i as GetActorOptions, it as CircuitBreakerActivityDrop, j as Rfc6570Expression, jt as ObjectDispatcher, k as ObjectCallbackSetters, kt as NodeInfoDispatcher, l as RequestContext, lt as CircuitBreakerOptions, m as CollectionCallbackSetters, mt as parseCircuitBreakerKvState, n as Context, nt as ParallelMessageQueue, o as InboxContext, ot as CircuitBreakerCreateOptions, p as ActorCallbackSetters, pt as normalizeCircuitBreakerOptions, q as RespondWithObjectOptions, r as ForwardActivityOptions, rt as CircuitBreaker, s as OutboxContext, st as CircuitBreakerFailurePolicy, t as ActorKeyPair, tt as MessageQueueListenOptions, u as RouteActivityOptions, ut as CircuitBreakerState, v as Federation, vt as ActorKeyPairsDispatcher, w as IdempotencyKeyCallback, wt as CustomCollectionCursor, x as FederationFetchOptions, xt as CollectionCursor, y as FederationBenchmarkOptions, yt as AuthorizePredicate, z as TaskDefinitionOptions, zt as WebFingerLinksDispatcher } from "../context-DiiCt4S7.js";
2
+ import { $ as MessageQueueDepth, A as OutboxListenerSetters, At as ObjectAuthorizePredicate, B as TaskEnqueueOptions, Bt as SendActivityError, C as FederationStartQueueOptions, Ct as CustomCollectionCounter, D as InboxListenerSetters, Dt as InboxListener, E as InboxChallengePolicy, Et as InboxErrorHandler, F as createFederation, Ft as OutboxPermanentFailureHandler, G as RetryPolicy, H as TaskRegistry, Ht as PageItems, I as Message, It as SharedInboxKeyDispatcher, J as respondWithObject, K as createExponentialBackoffPolicy, L as createFederationBuilder, Lt as UnverifiedActivityHandler, M as FederationKvPrefixes, Mt as OutboxErrorHandler, N as FederationOrigin, Nt as OutboxListener, O as MediaUploaderSetters, Ot as MediaUploaderCallback, P as FederationQueueOptions, Pt as OutboxListenerErrorHandler, Q as MessageQueue, R as TaskDefinition, Rt as UnverifiedActivityReason, S as FederationOptions, St as CollectionDispatcher, T as IdempotencyStrategy, Tt as CustomCollectionDispatcher, U as CreateExponentialBackoffPolicyOptions, Ut as buildCollectionSynchronizationHeader, V as TaskHandler, Vt as SenderKeyPair, W as RetryContext, Wt as digest, X as InProcessMessageQueue, Y as respondWithObjectIfAcceptable, Z as InProcessMessageQueueOptions, _ as Federatable, _t as ActorHandleMapper, a as GetSignedKeyOptions, at as CircuitBreakerBeforeSendDecision, b as FederationBuilder, bt as CollectionCounter, c as ParseUriResult, ct as CircuitBreakerKvState, d as SendActivityOptions, dt as CircuitBreakerStateChange, et as MessageQueueEnqueueOptions, f as SendActivityOptionsForCollection, ft as NormalizedCircuitBreakerOptions, g as CustomCollectionCallbackSetters, gt as ActorDispatcher, h as ConstructorWithTypeId, ht as ActorAliasMapper, i as GetActorOptions, it as CircuitBreakerActivityDrop, j as Rfc6570Expression, jt as ObjectDispatcher, k as ObjectCallbackSetters, kt as NodeInfoDispatcher, l as RequestContext, lt as CircuitBreakerOptions, m as CollectionCallbackSetters, mt as parseCircuitBreakerKvState, n as Context, nt as ParallelMessageQueue, o as InboxContext, ot as CircuitBreakerCreateOptions, p as ActorCallbackSetters, pt as normalizeCircuitBreakerOptions, q as RespondWithObjectOptions, r as ForwardActivityOptions, rt as CircuitBreaker, s as OutboxContext, st as CircuitBreakerFailurePolicy, t as ActorKeyPair, tt as MessageQueueListenOptions, u as RouteActivityOptions, ut as CircuitBreakerState, v as Federation, vt as ActorKeyPairsDispatcher, w as IdempotencyKeyCallback, wt as CustomCollectionCursor, x as FederationFetchOptions, xt as CollectionCursor, y as FederationBenchmarkOptions, yt as AuthorizePredicate, z as TaskDefinitionOptions, zt as WebFingerLinksDispatcher } from "../context-uyRUWoZQ.js";
3
3
  import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "../kv-BhNbN8Ed.js";
4
- import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-CSH1Ee-I.js";
4
+ import { a as RouterOptions, i as RouterError, n as handleWebFinger, o as RouterRouteResult, r as Router, t as WebFingerHandlerParameters } from "../mod-D882_Xsg.js";
5
5
  export { ActorAliasMapper, ActorCallbackSetters, ActorDispatcher, ActorHandleMapper, ActorKeyPair, ActorKeyPairsDispatcher, AuthorizePredicate, CircuitBreaker, CircuitBreakerActivityDrop, CircuitBreakerBeforeSendDecision, CircuitBreakerCreateOptions, CircuitBreakerFailurePolicy, CircuitBreakerKvState, CircuitBreakerOptions, CircuitBreakerState, CircuitBreakerStateChange, CollectionCallbackSetters, CollectionCounter, CollectionCursor, CollectionDispatcher, ConstructorWithTypeId, Context, CreateExponentialBackoffPolicyOptions, CustomCollectionCallbackSetters, CustomCollectionCounter, CustomCollectionCursor, CustomCollectionDispatcher, Federatable, Federation, FederationBenchmarkOptions, FederationBuilder, FederationFetchOptions, FederationKvPrefixes, FederationOptions, FederationOrigin, FederationQueueOptions, FederationStartQueueOptions, ForwardActivityOptions, GetActorOptions, GetSignedKeyOptions, IdempotencyKeyCallback, IdempotencyStrategy, InProcessMessageQueue, InProcessMessageQueueOptions, InboxChallengePolicy, InboxContext, InboxErrorHandler, InboxListener, InboxListenerSetters, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, MediaUploaderCallback, MediaUploaderSetters, MemoryKvStore, Message, MessageQueue, MessageQueueDepth, MessageQueueEnqueueOptions, MessageQueueListenOptions, NodeInfoDispatcher, NormalizedCircuitBreakerOptions, ObjectAuthorizePredicate, ObjectCallbackSetters, ObjectDispatcher, OutboxContext, OutboxErrorHandler, OutboxListener, OutboxListenerErrorHandler, OutboxListenerSetters, OutboxPermanentFailureHandler, PageItems, ParallelMessageQueue, ParseUriResult, RequestContext, RespondWithObjectOptions, RetryContext, RetryPolicy, Rfc6570Expression, RouteActivityOptions, Router, RouterError, RouterOptions, RouterRouteResult, SendActivityError, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair, SharedInboxKeyDispatcher, TaskDefinition, TaskDefinitionOptions, TaskEnqueueOptions, TaskHandler, TaskRegistry, UnverifiedActivityHandler, UnverifiedActivityReason, WebFingerHandlerParameters, WebFingerLinksDispatcher, buildCollectionSynchronizationHeader, createExponentialBackoffPolicy, createFederation, createFederationBuilder, digest, handleWebFinger, normalizeCircuitBreakerOptions, parseCircuitBreakerKvState, respondWithObject, respondWithObjectIfAcceptable };
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { a as respondWithObject, c as digest, d as parseCircuitBreakerKvState, f as createFederationBuilder, i as SendActivityError, l as CircuitBreaker, n as handleWebFinger, o as respondWithObjectIfAcceptable, r as createExponentialBackoffPolicy, s as buildCollectionSynchronizationHeader, t as createFederation, u as normalizeCircuitBreakerOptions } from "../middleware-CPTDFMmJ.js";
3
+ import { a as respondWithObject, c as digest, d as parseCircuitBreakerKvState, f as createFederationBuilder, i as SendActivityError, l as CircuitBreaker, n as handleWebFinger, o as respondWithObjectIfAcceptable, r as createExponentialBackoffPolicy, s as buildCollectionSynchronizationHeader, t as createFederation, u as normalizeCircuitBreakerOptions } from "../middleware-DsfWajaD.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { Router as Router$1, RouterError as RouterError$1, assertPath, isPath } from "@fedify/uri-template";
6
6
  import { isEqual } from "es-toolkit";
@@ -10,13 +10,13 @@ import { t as assertNotEquals } from "../assert_not_equals-BN7yDMWe.mjs";
10
10
  import "../std__assert-CxFT0MNt.mjs";
11
11
  import { t as assertRejects } from "../assert_rejects-wFbSPn1O.mjs";
12
12
  import { t as assert } from "../assert-CebeUf0C.mjs";
13
- import { l as verifyRequest } from "../http-D7LX-BL9.mjs";
13
+ import { l as verifyRequest } from "../http-D9urSO2D.mjs";
14
14
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
15
- import { t as doesActorOwnKey } from "../owner-DTEqTzSr.mjs";
16
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-DVXyUqhO.mjs";
15
+ import { t as doesActorOwnKey } from "../owner-CRoq8Spb.mjs";
16
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BzM5GLyn.mjs";
17
17
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
18
18
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
19
- import { FetchError } from "@fedify/vocab-runtime";
19
+ import { FetchError, UrlError } from "@fedify/vocab-runtime";
20
20
  import { AggregationTemporality, InMemoryMetricExporter, MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
21
21
  //#region src/federation/send.test.ts
22
22
  test("extractInboxes()", () => {
@@ -465,6 +465,7 @@ test("sendActivity() records OpenTelemetry delivery metrics", async (t) => {
465
465
  activityId: "https://example.com/activity",
466
466
  activityType: "https://www.w3.org/ns/activitystreams#Create",
467
467
  keys: [],
468
+ allowPrivateAddress: true,
468
469
  inbox: new URL("https://metrics.example:8443/inbox/path?x=1"),
469
470
  meterProvider
470
471
  });
@@ -502,6 +503,7 @@ test("sendActivity() records OpenTelemetry delivery metrics", async (t) => {
502
503
  activityId: "https://example.com/follow",
503
504
  activityType: "https://www.w3.org/ns/activitystreams#Follow",
504
505
  keys: [],
506
+ allowPrivateAddress: true,
505
507
  inbox: new URL("https://metrics.example/inbox"),
506
508
  meterProvider
507
509
  }), SendActivityError);
@@ -539,6 +541,7 @@ test("sendActivity() exports delivery metrics through OpenTelemetry SDK", async
539
541
  activityId: "https://example.com/activity",
540
542
  activityType: "https://www.w3.org/ns/activitystreams#Create",
541
543
  keys: [],
544
+ allowPrivateAddress: true,
542
545
  inbox: new URL("https://sdk-metrics.example/inbox"),
543
546
  meterProvider
544
547
  });
@@ -555,5 +558,137 @@ test("sendActivity() exports delivery metrics through OpenTelemetry SDK", async
555
558
  }
556
559
  }
557
560
  });
561
+ for (const signed of [false, true]) {
562
+ const keys = [{
563
+ privateKey: signed ? rsaPrivateKey2 : ed25519PrivateKey,
564
+ keyId: signed ? rsaPublicKey2.id : ed25519Multikey.id
565
+ }];
566
+ test(`sendActivity() validates destinations (signed: ${signed})`, async (t) => {
567
+ const activity = {
568
+ type: "Create",
569
+ id: "https://example.com/activity"
570
+ };
571
+ const publicInbox = "https://8.8.8.8/inbox";
572
+ const privateInbox = "http://127.0.0.1/inbox";
573
+ for (const target of [
574
+ privateInbox,
575
+ "http://169.254.169.254/",
576
+ "http://[::1]/"
577
+ ]) await t.step(`rejects ${target} before fetching`, async () => {
578
+ esm_default.mockGlobal().catch(202);
579
+ try {
580
+ await assertRejects(() => sendActivity({
581
+ activity,
582
+ keys,
583
+ inbox: new URL(target)
584
+ }), UrlError);
585
+ assertEquals(esm_default.callHistory.calls().length, 0);
586
+ } finally {
587
+ esm_default.hardReset();
588
+ }
589
+ });
590
+ for (const status of [
591
+ 301,
592
+ 302,
593
+ 303,
594
+ 307,
595
+ 308
596
+ ]) for (const allowPrivateAddress of [false, true]) await t.step(`${status} private redirect, opt-in: ${allowPrivateAddress}`, async () => {
597
+ esm_default.mockGlobal();
598
+ esm_default.route(publicInbox, {
599
+ status,
600
+ headers: { Location: privateInbox }
601
+ });
602
+ esm_default.route(privateInbox, 202);
603
+ try {
604
+ const send = () => sendActivity({
605
+ activity,
606
+ keys,
607
+ inbox: new URL(publicInbox),
608
+ allowPrivateAddress
609
+ });
610
+ if (allowPrivateAddress) {
611
+ await send();
612
+ const calls = esm_default.callHistory.calls(privateInbox);
613
+ assertEquals(calls.length, 1);
614
+ const request = calls[0].request;
615
+ const preservesBody = signed || status === 307 || status === 308;
616
+ assertEquals(request.method, preservesBody ? "POST" : "GET");
617
+ assertEquals(await request.clone().text(), preservesBody ? JSON.stringify(activity) : "");
618
+ } else {
619
+ await assertRejects(send, UrlError);
620
+ assertEquals(esm_default.callHistory.calls(privateInbox).length, 0);
621
+ }
622
+ } finally {
623
+ esm_default.hardReset();
624
+ }
625
+ });
626
+ await t.step("rejects a private destination after a public redirect", async () => {
627
+ esm_default.mockGlobal().route(publicInbox, {
628
+ status: 307,
629
+ headers: { Location: "/next" }
630
+ }).route("https://8.8.8.8/next", {
631
+ status: 308,
632
+ headers: { Location: privateInbox }
633
+ }).route(privateInbox, 202);
634
+ try {
635
+ await assertRejects(() => sendActivity({
636
+ activity,
637
+ keys,
638
+ inbox: new URL(publicInbox)
639
+ }), UrlError);
640
+ assertEquals(esm_default.callHistory.calls(privateInbox).length, 0);
641
+ } finally {
642
+ esm_default.hardReset();
643
+ }
644
+ });
645
+ await t.step("limits redirect loops", async () => {
646
+ esm_default.mockGlobal().route(publicInbox, {
647
+ status: 307,
648
+ headers: { Location: publicInbox }
649
+ });
650
+ try {
651
+ await assertRejects(() => sendActivity({
652
+ activity,
653
+ keys,
654
+ inbox: new URL(publicInbox)
655
+ }));
656
+ assert(esm_default.callHistory.calls().length <= 21);
657
+ } finally {
658
+ esm_default.hardReset();
659
+ }
660
+ });
661
+ await t.step("allows a direct private inbox with opt-in", async () => {
662
+ esm_default.mockGlobal().route(privateInbox, 202);
663
+ try {
664
+ await sendActivity({
665
+ activity,
666
+ keys,
667
+ inbox: new URL(privateInbox),
668
+ allowPrivateAddress: true
669
+ });
670
+ assertEquals(esm_default.callHistory.calls(privateInbox).length, 1);
671
+ } finally {
672
+ esm_default.hardReset();
673
+ }
674
+ });
675
+ await t.step("allows relative public redirects", async () => {
676
+ esm_default.mockGlobal().route(publicInbox, {
677
+ status: 307,
678
+ headers: { Location: "/next" }
679
+ }).route("https://8.8.8.8/next", 202);
680
+ try {
681
+ await sendActivity({
682
+ activity,
683
+ keys,
684
+ inbox: new URL(publicInbox)
685
+ });
686
+ assertEquals(esm_default.callHistory.calls("https://8.8.8.8/next").length, 1);
687
+ } finally {
688
+ esm_default.hardReset();
689
+ }
690
+ });
691
+ });
692
+ }
558
693
  //#endregion
559
694
  export {};
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
5
5
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
6
6
  import "../../testing-hbky2gMN.mjs";
7
- import { o as createFederation } from "../../middleware-TeLjzoxn.mjs";
7
+ import { o as createFederation } from "../../middleware-CzvJvPHK.mjs";
8
8
  import { n as ParallelMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
9
9
  import { configure, reset } from "@logtape/logtape";
10
10
  import { delay } from "es-toolkit";
@@ -4,8 +4,8 @@ globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
5
5
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
6
6
  import "../../testing-hbky2gMN.mjs";
7
- import { o as createFederation } from "../../middleware-TeLjzoxn.mjs";
8
- import { r as createFederationBuilder } from "../../builder-B4zpKIFU.mjs";
7
+ import { o as createFederation } from "../../middleware-CzvJvPHK.mjs";
8
+ import { r as createFederationBuilder } from "../../builder-D0DxgOV5.mjs";
9
9
  import { t as TaskCodec } from "../../codec-C6rTrpIp.mjs";
10
10
  import { t as InProcessMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
11
11
  import { W3CTraceContextPropagator } from "@opentelemetry/core";
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertFalse } from "../assert_false-3pLLLsO4.mjs";
5
5
  import "../std__assert-CxFT0MNt.mjs";
6
6
  import { t as assert } from "../assert-CebeUf0C.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-BoDw51A-.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-Dv6Qv-8k.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 () => {
@@ -6,7 +6,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
6
  import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
7
7
  import { t as assertNotEquals } from "../assert_not_equals-BN7yDMWe.mjs";
8
8
  import "../std__assert-CxFT0MNt.mjs";
9
- import { o as createFederation, s as handleWebFinger } from "../middleware-TeLjzoxn.mjs";
9
+ import { o as createFederation, s as handleWebFinger } from "../middleware-CzvJvPHK.mjs";
10
10
  import { Image, Link, Person, Tombstone } from "@fedify/vocab";
11
11
  import { createTestMeterProvider, test } from "@fedify/fixture";
12
12
  //#region src/federation/webfinger.test.ts