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

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 (53) hide show
  1. package/dist/{builder-Dndt590h.mjs → builder-B5hI5Xsn.mjs} +3 -3
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-D_rTMbAD.mjs → deno--OYa_lxj.mjs} +1 -1
  4. package/dist/{docloader-DpTrZ5sA.mjs → docloader-BXR2f83H.mjs} +2 -2
  5. package/dist/federation/builder.test.mjs +1 -1
  6. package/dist/federation/handler.test.mjs +8 -8
  7. package/dist/federation/idempotency.test.mjs +2 -2
  8. package/dist/federation/inbox.test.mjs +1 -1
  9. package/dist/federation/middleware.test.mjs +381 -8
  10. package/dist/federation/mod.cjs +1 -1
  11. package/dist/federation/mod.js +1 -1
  12. package/dist/federation/send.test.mjs +3 -3
  13. package/dist/federation/temporal.test.mjs +1 -1
  14. package/dist/federation/webfinger.test.mjs +1 -1
  15. package/dist/{http-DGD9d8-A.mjs → http-C3d2DXwF.mjs} +2 -2
  16. package/dist/{http-DbDnj-Q7.cjs → http-CO_IVq7x.cjs} +1 -1
  17. package/dist/{http-BS1CmlZ6.js → http-CfyVeGgF.js} +1 -1
  18. package/dist/{inbox-BwpBTbhH.mjs → inbox-huUE3IP8.mjs} +1 -1
  19. package/dist/{key-1Gf85RN1.mjs → key-D5e9c_yV.mjs} +1 -1
  20. package/dist/{kv-cache-BdA7HpfF.cjs → kv-cache-BMlo_kyv.cjs} +1 -1
  21. package/dist/{kv-cache-BARiicPE.js → kv-cache-Zw0soD-7.js} +1 -1
  22. package/dist/{ld-BuuOR_Ms.mjs → ld-9qfz9rP_.mjs} +99 -10
  23. package/dist/{middleware-D9TWYyT_.cjs → middleware-Ad6kTSBf.cjs} +1 -1
  24. package/dist/{middleware-CQRCnFB4.js → middleware-BKs_a9P1.js} +111 -15
  25. package/dist/{middleware-DDM0j-X6.mjs → middleware-BhYpLGA_.mjs} +119 -23
  26. package/dist/{middleware-C5Nypx4Z.mjs → middleware-CT1Lbohd.mjs} +1 -1
  27. package/dist/{middleware-DThg01d8.cjs → middleware-CXoG7ZAW.cjs} +112 -16
  28. package/dist/{mod-DVPS4yam.d.cts → mod-BA6vqC2S.d.cts} +19 -7
  29. package/dist/{mod-BS-jg3Wx.d.ts → mod-CL9Ep0uo.d.ts} +19 -7
  30. package/dist/mod.cjs +4 -4
  31. package/dist/mod.d.cts +1 -1
  32. package/dist/mod.d.ts +1 -1
  33. package/dist/mod.js +4 -4
  34. package/dist/nodeinfo/handler.test.mjs +1 -1
  35. package/dist/{owner-BI33UeIv.mjs → owner-R4ffU9Ht.mjs} +2 -2
  36. package/dist/{proof-vVwkNRv4.cjs → proof-BrreJTRF.cjs} +131 -18
  37. package/dist/{proof-BBHUW8ev.js → proof-CE8nwTF6.js} +132 -19
  38. package/dist/{proof-GM73LJjx.mjs → proof-CiBs9Q4l.mjs} +36 -12
  39. package/dist/{send-nImUK91D.mjs → send-DpvZgVSA.mjs} +2 -2
  40. package/dist/sig/http.test.mjs +2 -2
  41. package/dist/sig/key.test.mjs +2 -2
  42. package/dist/sig/ld.test.mjs +198 -4
  43. package/dist/sig/mod.cjs +2 -2
  44. package/dist/sig/mod.d.cts +1 -1
  45. package/dist/sig/mod.d.ts +1 -1
  46. package/dist/sig/mod.js +2 -2
  47. package/dist/sig/owner.test.mjs +1 -1
  48. package/dist/sig/proof.test.mjs +71 -2
  49. package/dist/{temporal-CfNFB7M_.mjs → temporal-Dd-J410Z.mjs} +1 -1
  50. package/dist/utils/docloader.test.mjs +2 -2
  51. package/dist/utils/mod.cjs +1 -1
  52. package/dist/utils/mod.js +1 -1
  53. package/package.json +5 -5
@@ -2,8 +2,8 @@ import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError, t as Router } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-D_rTMbAD.mjs";
6
- import { t as InboxListenerSet } from "./inbox-BwpBTbhH.mjs";
5
+ import { n as version, t as name } from "./deno--OYa_lxj.mjs";
6
+ import { t as InboxListenerSet } from "./inbox-huUE3IP8.mjs";
7
7
  import { getTypeId } from "@fedify/vocab";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { getLogger } from "@logtape/logtape";
@@ -43,7 +43,7 @@ var FederationBuilderImpl = class {
43
43
  this.collectionTypeIds = {};
44
44
  }
45
45
  async build(options) {
46
- const { FederationImpl } = await import("./middleware-C5Nypx4Z.mjs");
46
+ const { FederationImpl } = await import("./middleware-CT1Lbohd.mjs");
47
47
  const f = new FederationImpl(options);
48
48
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
49
49
  f.router = this.router.clone();
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
6
6
  import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
7
- import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-DDM0j-X6.mjs";
7
+ import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-BhYpLGA_.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  import { Follow, Person } from "@fedify/vocab";
10
10
  //#region src/compat/transformers.test.ts
@@ -3,6 +3,6 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  //#region deno.json
5
5
  var name = "@fedify/fedify";
6
- var version = "2.0.36-dev.2551+8b012df4";
6
+ var version = "2.0.36-dev.2598+90504ae2";
7
7
  //#endregion
8
8
  export { version as n, name as t };
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { o as validateCryptoKey } from "./key-1Gf85RN1.mjs";
5
- import { r as doubleKnockScoped } from "./http-DGD9d8-A.mjs";
4
+ import { o as validateCryptoKey } from "./key-D5e9c_yV.mjs";
5
+ import { r as doubleKnockScoped } from "./http-C3d2DXwF.mjs";
6
6
  import { curry } from "es-toolkit";
7
7
  import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest } from "@fedify/vocab-runtime";
8
8
  import { openDirectFetch, openPublicFetch } from "@fedify/vocab-runtime/internal";
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { i as assertExists, n as assertStrictEquals } from "../std__assert-DflMZha5.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-D4DNWrux.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
8
- import { n as createFederationBuilder } from "../builder-Dndt590h.mjs";
8
+ import { n as createFederationBuilder } from "../builder-B5hI5Xsn.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Activity, Note, Person } from "@fedify/vocab";
11
11
  //#region src/federation/builder.test.ts
@@ -6,14 +6,14 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-DflMZha5.mjs";
7
7
  import { t as assert } from "../assert-BhQd8QHP.mjs";
8
8
  import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
9
- import { i as generateCryptoKeyPair } from "../key-1Gf85RN1.mjs";
10
- import { c as signRequest } from "../http-DGD9d8-A.mjs";
9
+ import { i as generateCryptoKeyPair } from "../key-D5e9c_yV.mjs";
10
+ import { c as signRequest } from "../http-C3d2DXwF.mjs";
11
11
  import { a as rsaPrivateKey3, c as rsaPublicKey3, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CCxRJhWa.mjs";
12
- import { a as compactJsonLd, f as signJsonLd } from "../ld-BuuOR_Ms.mjs";
13
- import { n as signObject } from "../proof-GM73LJjx.mjs";
12
+ import { a as compactJsonLd, f as signJsonLd } from "../ld-9qfz9rP_.mjs";
13
+ import { n as signObject } from "../proof-CiBs9Q4l.mjs";
14
14
  import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
15
- import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-DDM0j-X6.mjs";
16
- import { t as InboxListenerSet } from "../inbox-BwpBTbhH.mjs";
15
+ import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-BhYpLGA_.mjs";
16
+ import { t as InboxListenerSet } from "../inbox-huUE3IP8.mjs";
17
17
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
18
18
  import { Create, CryptographicKey, Multikey, Note, Person } from "@fedify/vocab";
19
19
  //#region src/federation/handler.test.ts
@@ -531,8 +531,8 @@ test("handleCollection()", async () => {
531
531
  assertEquals(response.status, 200);
532
532
  assertEquals(response.headers.get("Content-Type"), "application/activity+json");
533
533
  const createCtx = [
534
- "https://w3id.org/identity/v1",
535
534
  "https://www.w3.org/ns/activitystreams",
535
+ "https://w3id.org/security/v1",
536
536
  "https://w3id.org/security/data-integrity/v1",
537
537
  {
538
538
  toot: "http://joinmastodon.org/ns#",
@@ -2821,8 +2821,8 @@ test("handleCustomCollection()", async () => {
2821
2821
  assertEquals(response.status, 200);
2822
2822
  assertEquals(response.headers.get("Content-Type"), "application/activity+json");
2823
2823
  const createCtx = [
2824
- "https://w3id.org/identity/v1",
2825
2824
  "https://www.w3.org/ns/activitystreams",
2825
+ "https://w3id.org/security/v1",
2826
2826
  "https://w3id.org/security/data-integrity/v1",
2827
2827
  {
2828
2828
  toot: "http://joinmastodon.org/ns#",
@@ -4,9 +4,9 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-DflMZha5.mjs";
6
6
  import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-CCxRJhWa.mjs";
7
- import { n as signObject } from "../proof-GM73LJjx.mjs";
7
+ import { n as signObject } from "../proof-CiBs9Q4l.mjs";
8
8
  import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
9
- import { a as createFederation } from "../middleware-DDM0j-X6.mjs";
9
+ import { a as createFederation } from "../middleware-BhYpLGA_.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, Follow, Person } from "@fedify/vocab";
12
12
  //#region src/federation/idempotency.test.ts
@@ -3,7 +3,7 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { r as assertFalse, t as assertThrows } from "../assert_throws-D4DNWrux.mjs";
6
- import { n as actorsHaveSameOrigin, t as InboxListenerSet } from "../inbox-BwpBTbhH.mjs";
6
+ import { n as actorsHaveSameOrigin, t as InboxListenerSet } from "../inbox-huUE3IP8.mjs";
7
7
  import { test } from "@fedify/fixture";
8
8
  import { Activity, Create, Invite, Offer, Update } from "@fedify/vocab";
9
9
  //#region src/federation/inbox.test.ts
@@ -9,14 +9,14 @@ import { r as assertFalse, t as assertThrows } from "../assert_throws-D4DNWrux.m
9
9
  import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
10
10
  import { t as assertNotEquals } from "../assert_not_equals-BkxW5QJI.mjs";
11
11
  import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
12
- import { c as signRequest, u as verifyRequest } from "../http-DGD9d8-A.mjs";
12
+ import { c as signRequest, u as verifyRequest } from "../http-C3d2DXwF.mjs";
13
13
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CCxRJhWa.mjs";
14
- import { n as getAuthenticatedDocumentLoader } from "../docloader-DpTrZ5sA.mjs";
15
- import { a as compactJsonLd, f as signJsonLd, m as verifyJsonLd, s as detachSignature } from "../ld-BuuOR_Ms.mjs";
16
- import { t as doesActorOwnKey } from "../owner-BI33UeIv.mjs";
17
- import { n as signObject, r as verifyObject } from "../proof-GM73LJjx.mjs";
14
+ import { n as getAuthenticatedDocumentLoader } from "../docloader-BXR2f83H.mjs";
15
+ import { a as compactJsonLd, f as signJsonLd, i as attachSignature, m as verifyJsonLd, s as detachSignature } from "../ld-9qfz9rP_.mjs";
16
+ import { t as doesActorOwnKey } from "../owner-R4ffU9Ht.mjs";
17
+ import { n as signObject, r as verifyObject } from "../proof-CiBs9Q4l.mjs";
18
18
  import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
19
- import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-DDM0j-X6.mjs";
19
+ import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-BhYpLGA_.mjs";
20
20
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
21
21
  import * as vocab from "@fedify/vocab";
22
22
  import { Create, Offer, Person, getTypeId, lookupObject } from "@fedify/vocab";
@@ -3594,15 +3594,19 @@ test("ContextImpl.sendActivity()", async (t) => {
3594
3594
  queue
3595
3595
  });
3596
3596
  federation2.setActorDispatcher("/{identifier}", async (ctx, identifier) => {
3597
- if (identifier !== "john") return null;
3597
+ if (identifier !== "john" && identifier !== "rsa-only") return null;
3598
3598
  const keys = await ctx.getActorKeyPairs(identifier);
3599
3599
  return new vocab.Person({
3600
3600
  id: ctx.getActorUri(identifier),
3601
- preferredUsername: "john",
3601
+ preferredUsername: identifier,
3602
3602
  publicKey: keys[0].cryptographicKey,
3603
3603
  assertionMethods: keys.map((k) => k.multikey)
3604
3604
  });
3605
3605
  }).setKeyPairsDispatcher((_ctx, identifier) => {
3606
+ if (identifier === "rsa-only") return [{
3607
+ privateKey: rsaPrivateKey2,
3608
+ publicKey: rsaPublicKey2.publicKey
3609
+ }];
3606
3610
  if (identifier !== "john") return [];
3607
3611
  return [{
3608
3612
  privateKey: rsaPrivateKey2,
@@ -3651,6 +3655,375 @@ test("ContextImpl.sendActivity()", async (t) => {
3651
3655
  proofCount++;
3652
3656
  }
3653
3657
  assertEquals(proofCount, 1);
3658
+ const oldContext = [
3659
+ "https://w3id.org/identity/v1",
3660
+ "https://www.w3.org/ns/activitystreams",
3661
+ "https://w3id.org/security/data-integrity/v1"
3662
+ ];
3663
+ const oldJson = await (await signObject(new vocab.Create({
3664
+ id: new URL("https://example.com/activity/1"),
3665
+ actor: new URL("https://example.com/john")
3666
+ }), ed25519PrivateKey, ed25519Multikey.id, {
3667
+ contextLoader: documentLoader,
3668
+ context: oldContext
3669
+ })).toJsonLd({
3670
+ format: "compact",
3671
+ contextLoader: documentLoader,
3672
+ context: oldContext
3673
+ });
3674
+ queue.clear();
3675
+ await federation2.processQueuedTask(void 0, {
3676
+ ...fanoutMsg,
3677
+ id: crypto.randomUUID(),
3678
+ activity: oldJson
3679
+ });
3680
+ const replayed = queue.messages.at(-1);
3681
+ assert(replayed != null && replayed.type === "outbox");
3682
+ assertEquals(detachSignature(replayed.activity), oldJson);
3683
+ const proofless = { ...oldJson };
3684
+ delete proofless.proof;
3685
+ queue.clear();
3686
+ await federation2.processQueuedTask(void 0, {
3687
+ ...fanoutMsg,
3688
+ id: crypto.randomUUID(),
3689
+ activity: proofless
3690
+ });
3691
+ const signedReplay = queue.messages.at(-1);
3692
+ assert(signedReplay != null && signedReplay.type === "outbox");
3693
+ assert(typeof signedReplay.activity === "object" && signedReplay.activity != null && "proof" in signedReplay.activity);
3694
+ const edKey = (await ctx2.getActorKeyPairs("john")).find((key) => key.privateKey.algorithm.name === "Ed25519");
3695
+ assert(edKey != null && edKey.multikey.id != null);
3696
+ const restoredJson = await (await signObject(new vocab.Create({
3697
+ id: new URL("https://example.com/activity/old"),
3698
+ actor: ctx2.getActorUri("john")
3699
+ }), edKey.privateKey, edKey.multikey.id, {
3700
+ contextLoader: documentLoader,
3701
+ context: oldContext
3702
+ })).toJsonLd({
3703
+ format: "compact",
3704
+ contextLoader: documentLoader,
3705
+ context: oldContext
3706
+ });
3707
+ const restored = await vocab.Create.fromJsonLd(restoredJson, {
3708
+ contextLoader: documentLoader,
3709
+ documentLoader
3710
+ });
3711
+ queue.clear();
3712
+ await ctx2.sendActivity([{
3713
+ privateKey: rsaPrivateKey2,
3714
+ keyId: rsaPublicKey2.id
3715
+ }], {
3716
+ id: new URL("https://example.com/recipient"),
3717
+ inboxId: new URL("https://example.com/inbox")
3718
+ }, restored);
3719
+ const resent = queue.messages.at(-1);
3720
+ assert(resent != null && resent.type === "outbox");
3721
+ assertEquals(detachSignature(resent.activity), restoredJson);
3722
+ queue.clear();
3723
+ await ctx2.sendActivity([{
3724
+ privateKey: rsaPrivateKey2,
3725
+ keyId: rsaPublicKey2.id
3726
+ }], {
3727
+ id: new URL("https://example.com/recipient"),
3728
+ inboxId: new URL("https://example.com/inbox")
3729
+ }, restored, { fanout: "force" });
3730
+ const queuedFanout = queue.messages.at(-1);
3731
+ assert(queuedFanout != null && queuedFanout.type === "fanout");
3732
+ assertEquals(queuedFanout.activity, restoredJson);
3733
+ const restoredWithSignature = await vocab.Create.fromJsonLd(attachSignature(restoredJson, {
3734
+ "@context": "https://w3id.org/identity/v1",
3735
+ type: "RsaSignature2017",
3736
+ creator: "https://example.com/person2#key4",
3737
+ created: "2026-01-01T00:00:00Z",
3738
+ signatureValue: "abc"
3739
+ }), {
3740
+ contextLoader: documentLoader,
3741
+ documentLoader
3742
+ });
3743
+ queue.clear();
3744
+ await ctx2.sendActivity([{
3745
+ privateKey: rsaPrivateKey2,
3746
+ keyId: rsaPublicKey2.id
3747
+ }], {
3748
+ id: new URL("https://example.com/recipient"),
3749
+ inboxId: new URL("https://example.com/inbox")
3750
+ }, restoredWithSignature);
3751
+ const resigned = queue.messages.at(-1);
3752
+ assert(resigned != null && resigned.type === "outbox");
3753
+ assertEquals(detachSignature(resigned.activity), restoredJson);
3754
+ const rsaOnlyJson = await (await signObject(new vocab.Create({
3755
+ id: new URL("https://example.com/activity/rsa-only"),
3756
+ actor: new URL("https://example.com/rsa-only")
3757
+ }), ed25519PrivateKey, ed25519Multikey.id, {
3758
+ contextLoader: documentLoader,
3759
+ context: oldContext
3760
+ })).toJsonLd({
3761
+ format: "compact",
3762
+ contextLoader: documentLoader,
3763
+ context: oldContext
3764
+ });
3765
+ const rsaOnlyRestored = await vocab.Create.fromJsonLd(rsaOnlyJson, {
3766
+ contextLoader: documentLoader,
3767
+ documentLoader
3768
+ });
3769
+ queue.clear();
3770
+ await ctx2.sendActivity({ identifier: "rsa-only" }, {
3771
+ id: new URL("https://example.com/recipient"),
3772
+ inboxId: new URL("https://example.com/inbox")
3773
+ }, rsaOnlyRestored, { fanout: "force" });
3774
+ const rsaOnlyMessage = queue.messages.at(-1);
3775
+ assert(rsaOnlyMessage != null && rsaOnlyMessage.type === "fanout");
3776
+ assertEquals(rsaOnlyMessage.activity, rsaOnlyJson);
3777
+ queue.clear();
3778
+ await ctx2.sendActivity({ username: "john" }, {
3779
+ id: new URL("https://example.com/recipient"),
3780
+ inboxId: new URL("https://example.com/inbox")
3781
+ }, restored, { fanout: "force" });
3782
+ const namedFanout = queue.messages.at(-1);
3783
+ assert(namedFanout != null && namedFanout.type === "fanout");
3784
+ const namedJson = detachSignature(namedFanout.activity);
3785
+ assertEquals((Array.isArray(namedJson.proof) ? namedJson.proof : [namedJson.proof]).length, 1);
3786
+ assert(namedJson["@context"].includes("https://w3id.org/security/v1"));
3787
+ const noIdJson = await (await signObject(new vocab.Create({ actor: ctx2.getActorUri("john") }), edKey.privateKey, edKey.multikey.id, {
3788
+ contextLoader: documentLoader,
3789
+ context: oldContext
3790
+ })).toJsonLd({
3791
+ format: "compact",
3792
+ contextLoader: documentLoader,
3793
+ context: oldContext
3794
+ });
3795
+ const noIdRestored = await vocab.Create.fromJsonLd(noIdJson, {
3796
+ contextLoader: documentLoader,
3797
+ documentLoader
3798
+ });
3799
+ queue.clear();
3800
+ await ctx2.sendActivity([{
3801
+ privateKey: rsaPrivateKey2,
3802
+ keyId: rsaPublicKey2.id
3803
+ }], {
3804
+ id: new URL("https://example.com/recipient"),
3805
+ inboxId: new URL("https://example.com/inbox")
3806
+ }, noIdRestored);
3807
+ const noIdQueued = queue.messages.at(-1);
3808
+ assert(noIdQueued != null && noIdQueued.type === "outbox");
3809
+ assert(typeof detachSignature(noIdQueued.activity).id === "string");
3810
+ const currentJson = await (await signObject(new vocab.Create({
3811
+ id: new URL("https://example.com/activity/current"),
3812
+ actor: ctx2.getActorUri("john")
3813
+ }), edKey.privateKey, edKey.multikey.id, { contextLoader: documentLoader })).toJsonLd({
3814
+ format: "compact",
3815
+ contextLoader: documentLoader
3816
+ });
3817
+ const currentRestored = await vocab.Create.fromJsonLd(currentJson, {
3818
+ contextLoader: documentLoader,
3819
+ documentLoader
3820
+ });
3821
+ queue.clear();
3822
+ await ctx2.sendActivity({ username: "john" }, {
3823
+ id: new URL("https://example.com/recipient"),
3824
+ inboxId: new URL("https://example.com/inbox")
3825
+ }, currentRestored, { fanout: "force" });
3826
+ const currentFanout = queue.messages.at(-1);
3827
+ assert(currentFanout != null && currentFanout.type === "fanout");
3828
+ const currentQueued = detachSignature(currentFanout.activity);
3829
+ assertEquals((Array.isArray(currentQueued.proof) ? currentQueued.proof : [currentQueued.proof]).length, 2);
3830
+ });
3831
+ queue.clear();
3832
+ await t.step("activity transformers preserve proofs", async () => {
3833
+ const originalProof = new vocab.DataIntegrityProof({
3834
+ cryptosuite: "eddsa-jcs-2022",
3835
+ verificationMethod: new URL("https://example.com/rsa-only#multikey-2"),
3836
+ proofPurpose: "assertionMethod",
3837
+ proofValue: new Uint8Array([
3838
+ 1,
3839
+ 2,
3840
+ 3,
3841
+ 4
3842
+ ]),
3843
+ created: Temporal.Instant.from("2026-01-01T00:00:00Z")
3844
+ });
3845
+ const addedProof = new vocab.DataIntegrityProof({
3846
+ cryptosuite: "eddsa-jcs-2022",
3847
+ verificationMethod: new URL("https://example.com/rsa-only#multikey-2"),
3848
+ proofPurpose: "assertionMethod",
3849
+ proofValue: new Uint8Array([
3850
+ 5,
3851
+ 6,
3852
+ 7,
3853
+ 8
3854
+ ]),
3855
+ created: Temporal.Instant.from("2026-01-02T00:00:00Z")
3856
+ });
3857
+ const replacementProof = new vocab.DataIntegrityProof({
3858
+ cryptosuite: "eddsa-jcs-2022",
3859
+ verificationMethod: new URL("https://example.com/rsa-only#multikey-2"),
3860
+ proofPurpose: "assertionMethod",
3861
+ proofValue: new Uint8Array([
3862
+ 9,
3863
+ 10,
3864
+ 11,
3865
+ 12
3866
+ ]),
3867
+ created: Temporal.Instant.from("2026-01-03T00:00:00Z")
3868
+ });
3869
+ const restoredProof = new vocab.DataIntegrityProof({
3870
+ cryptosuite: "eddsa-jcs-2022",
3871
+ verificationMethod: new URL("https://example.com/rsa-only#multikey-2"),
3872
+ proofPurpose: "assertionMethod",
3873
+ proofValue: new Uint8Array([
3874
+ 13,
3875
+ 14,
3876
+ 15,
3877
+ 16
3878
+ ]),
3879
+ created: Temporal.Instant.from("2026-01-04T00:00:00Z")
3880
+ });
3881
+ const restoredProofHolder = {};
3882
+ const federation3 = new FederationImpl({
3883
+ kv,
3884
+ allowPrivateAddress: true,
3885
+ queue,
3886
+ activityTransformers: [(activity) => {
3887
+ if (activity.id?.href === "https://example.com/activity/transformed-proof") return activity.clone({ proofs: [originalProof, addedProof] });
3888
+ if (activity.id?.href === "https://example.com/activity/replaced-proof") return new vocab.Create({
3889
+ id: activity.id,
3890
+ actor: new URL("https://example.com/rsa-only"),
3891
+ object: new URL("https://example.com/note/replaced"),
3892
+ proofs: [replacementProof]
3893
+ });
3894
+ if (activity.id?.href === "https://example.com/activity/restored-proof") return activity.clone({ proofs: [restoredProofHolder.old, restoredProof] });
3895
+ return activity;
3896
+ }]
3897
+ });
3898
+ federation3.setActorDispatcher("/{identifier}", async (ctx, identifier) => {
3899
+ if (identifier !== "rsa-only") return null;
3900
+ const keys = await ctx.getActorKeyPairs(identifier);
3901
+ return new vocab.Person({
3902
+ id: ctx.getActorUri(identifier),
3903
+ preferredUsername: identifier,
3904
+ publicKey: keys[0].cryptographicKey,
3905
+ assertionMethods: keys.map((k) => k.multikey)
3906
+ });
3907
+ }).setKeyPairsDispatcher((_ctx, identifier) => identifier === "rsa-only" ? [{
3908
+ privateKey: rsaPrivateKey2,
3909
+ publicKey: rsaPublicKey2.publicKey
3910
+ }] : []);
3911
+ const ctx3 = new ContextImpl({
3912
+ data: void 0,
3913
+ federation: federation3,
3914
+ url: new URL("https://example.com/"),
3915
+ documentLoader,
3916
+ contextLoader: documentLoader
3917
+ });
3918
+ const activity = new vocab.Create({
3919
+ id: new URL("https://example.com/activity/transformed-proof"),
3920
+ actor: ctx3.getActorUri("rsa-only"),
3921
+ proofs: [originalProof]
3922
+ });
3923
+ await ctx3.sendActivity({ identifier: "rsa-only" }, {
3924
+ id: new URL("https://example.com/recipient"),
3925
+ inboxId: new URL("https://example.com/inbox")
3926
+ }, activity, { fanout: "force" });
3927
+ const fanout = queue.messages.at(-1);
3928
+ assert(fanout != null && fanout.type === "fanout");
3929
+ const fanoutJson = detachSignature(fanout.activity);
3930
+ assertEquals((Array.isArray(fanoutJson.proof) ? fanoutJson.proof : [fanoutJson.proof]).length, 2);
3931
+ const replacedActivity = new vocab.Create({
3932
+ id: new URL("https://example.com/activity/replaced-proof"),
3933
+ actor: ctx3.getActorUri("rsa-only"),
3934
+ proofs: [originalProof]
3935
+ });
3936
+ queue.clear();
3937
+ await ctx3.sendActivity({ identifier: "rsa-only" }, {
3938
+ id: new URL("https://example.com/recipient"),
3939
+ inboxId: new URL("https://example.com/inbox")
3940
+ }, replacedActivity, { fanout: "force" });
3941
+ const replacedFanout = queue.messages.at(-1);
3942
+ assert(replacedFanout != null && replacedFanout.type === "fanout");
3943
+ const replacedJson = detachSignature(replacedFanout.activity);
3944
+ assertEquals(replacedJson.object, "https://example.com/note/replaced");
3945
+ const replacedProofs = Array.isArray(replacedJson.proof) ? replacedJson.proof : [replacedJson.proof];
3946
+ assertEquals(replacedProofs.length, 1);
3947
+ const [keptProof] = replacedProofs;
3948
+ assertEquals(keptProof.created, "2026-01-03T00:00:00Z");
3949
+ const oldContext = [
3950
+ "https://w3id.org/identity/v1",
3951
+ "https://www.w3.org/ns/activitystreams",
3952
+ "https://w3id.org/security/data-integrity/v1"
3953
+ ];
3954
+ const restoredJson = await (await signObject(new vocab.Create({
3955
+ id: new URL("https://example.com/activity/restored-proof"),
3956
+ actor: ctx3.getActorUri("rsa-only")
3957
+ }), ed25519PrivateKey, ed25519Multikey.id, {
3958
+ contextLoader: documentLoader,
3959
+ context: oldContext
3960
+ })).toJsonLd({
3961
+ format: "compact",
3962
+ contextLoader: documentLoader,
3963
+ context: oldContext
3964
+ });
3965
+ const restored = await vocab.Create.fromJsonLd(restoredJson, {
3966
+ contextLoader: documentLoader,
3967
+ documentLoader
3968
+ });
3969
+ for await (const proof of restored.getProofs({ contextLoader: documentLoader })) {
3970
+ restoredProofHolder.old = proof;
3971
+ break;
3972
+ }
3973
+ queue.clear();
3974
+ await ctx3.sendActivity({ identifier: "rsa-only" }, {
3975
+ id: new URL("https://example.com/recipient"),
3976
+ inboxId: new URL("https://example.com/inbox")
3977
+ }, restored, { fanout: "force" });
3978
+ const restoredFanout = queue.messages.at(-1);
3979
+ assert(restoredFanout != null && restoredFanout.type === "fanout");
3980
+ const restoredFanoutJson = detachSignature(restoredFanout.activity);
3981
+ const restoredProofs = Array.isArray(restoredFanoutJson.proof) ? restoredFanoutJson.proof : [restoredFanoutJson.proof];
3982
+ assertEquals(restoredProofs.length, 1);
3983
+ const [transformedProof] = restoredProofs;
3984
+ assertEquals(transformedProof.created, "2026-01-04T00:00:00Z");
3985
+ assert(Array.isArray(restoredFanoutJson["@context"]) && restoredFanoutJson["@context"].includes("https://w3id.org/security/v1"));
3986
+ const staleTimestampJson = await (await signObject(new vocab.Create({
3987
+ id: new URL("https://example.com/activity/stale-timestamp"),
3988
+ actor: ctx3.getActorUri("rsa-only")
3989
+ }), ed25519PrivateKey, ed25519Multikey.id, {
3990
+ contextLoader: documentLoader,
3991
+ context: oldContext
3992
+ })).toJsonLd({
3993
+ format: "compact",
3994
+ contextLoader: documentLoader,
3995
+ context: oldContext
3996
+ });
3997
+ const staleTimestampProof = Array.isArray(staleTimestampJson.proof) ? staleTimestampJson.proof[0] : staleTimestampJson.proof;
3998
+ staleTimestampProof.created = "2026-01-01T00:00:00+00:00";
3999
+ const staleTimestamp = await vocab.Create.fromJsonLd(staleTimestampJson, {
4000
+ contextLoader: documentLoader,
4001
+ documentLoader
4002
+ });
4003
+ queue.clear();
4004
+ await ctx3.sendActivity({ identifier: "rsa-only" }, {
4005
+ id: new URL("https://example.com/recipient"),
4006
+ inboxId: new URL("https://example.com/inbox")
4007
+ }, staleTimestamp, { fanout: "force" });
4008
+ const staleTimestampFanout = queue.messages.at(-1);
4009
+ assert(staleTimestampFanout != null && staleTimestampFanout.type === "fanout");
4010
+ assertEquals(detachSignature(staleTimestampFanout.activity), staleTimestampJson);
4011
+ const proofless = new vocab.Create({
4012
+ id: new URL("https://example.com/activity/proofless"),
4013
+ actor: ctx3.getActorUri("rsa-only")
4014
+ });
4015
+ let unformattedSerializations = 0;
4016
+ const originalToJsonLd = proofless.toJsonLd.bind(proofless);
4017
+ Object.defineProperty(proofless, "toJsonLd", { value: async (options) => {
4018
+ if (options?.format == null) unformattedSerializations++;
4019
+ return await originalToJsonLd(options);
4020
+ } });
4021
+ queue.clear();
4022
+ await ctx3.sendActivity({ identifier: "rsa-only" }, {
4023
+ id: new URL("https://example.com/recipient"),
4024
+ inboxId: new URL("https://example.com/inbox")
4025
+ }, proofless, { fanout: "skip" });
4026
+ assertEquals(unformattedSerializations, 0);
3654
4027
  });
3655
4028
  queue.clear();
3656
4029
  await t.step("fanout: \"skip\"", async () => {
@@ -2,7 +2,7 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
4
  require("../chunk-DDcVe30Y.cjs");
5
- const require_middleware = require("../middleware-DThg01d8.cjs");
5
+ const require_middleware = require("../middleware-CXoG7ZAW.cjs");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  //#region src/federation/kv.ts
8
8
  /**
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "../middleware-CQRCnFB4.js";
3
+ import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "../middleware-BKs_a9P1.js";
4
4
  import { isEqual } from "es-toolkit";
5
5
  //#region src/federation/kv.ts
6
6
  /**
@@ -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-DGD9d8-A.mjs";
11
+ import { u as verifyRequest } from "../http-C3d2DXwF.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-BI33UeIv.mjs";
14
- import { i as sendActivity, n as extractInboxes, r as fetchWithValidatedRedirects, t as SendActivityError } from "../send-nImUK91D.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";
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-CfNFB7M_.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-Dd-J410Z.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-DDM0j-X6.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-BhYpLGA_.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
@@ -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-D_rTMbAD.mjs";
5
- import { o as validateCryptoKey, r as fetchKey } from "./key-1Gf85RN1.mjs";
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";
6
6
  import { CryptographicKey } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { FetchError } from "@fedify/vocab-runtime";
@@ -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.2551+8b012df4";
14
+ var version = "2.0.36-dev.2598+90504ae2";
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.2551+8b012df4";
13
+ var version = "2.0.36-dev.2598+90504ae2";
14
14
  //#endregion
15
15
  //#region src/sig/key.ts
16
16
  /** Classifies decoding failures without hiding unexpected loader errors. */
@@ -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-D_rTMbAD.mjs";
4
+ import { n as version, t as name } from "./deno--OYa_lxj.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-D_rTMbAD.mjs";
4
+ import { n as version, t as name } from "./deno--OYa_lxj.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";