From 778b393c43cdf5bfd5cb45d3ec7f8e6b31facbda Mon Sep 17 00:00:00 2001 From: Grant Date: Sun, 28 Jun 2026 20:58:50 -0600 Subject: [PATCH 1/7] update fedify to ^2.3.1 Assisted-by: deepseek:v4-flash --- ...@fedify-fedify-npm-1.10.0-eb96e7364a.patch | 1740 ----------------- backend/package.json | 8 +- backend/src/__tests__/federation.test.ts | 2 +- backend/src/apub/federation.ts | 12 +- backend/src/apub/utils.live.ts | 38 +- backend/src/apub/utils.stub.ts | 18 +- backend/src/apub/utils.ts | 21 +- backend/src/handoff/activitypub.ts | 4 +- backend/src/handoff/sidecar.ts | 2 +- backend/src/models/AuthSession.ts | 17 +- backend/src/models/SentAP.redis.ts | 10 +- backend/src/models/TransientNote.ts | 19 +- backend/src/types/env.d.ts | 4 +- doc/dev/patches/fedify.md | 3 - yarn.lock | 355 ++-- 15 files changed, 267 insertions(+), 1986 deletions(-) delete mode 100644 .yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch delete mode 100644 doc/dev/patches/fedify.md diff --git a/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch b/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch deleted file mode 100644 index 07c2494..0000000 --- a/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch +++ /dev/null @@ -1,1740 +0,0 @@ -diff --git a/dist/actor-CD3vk4f0.cjs b/dist/actor-CD3vk4f0.cjs -index dadce19470de6e881eb790cdfe4b8364e201ac1d..9774ee4c98342a0cc4a5a0cfff8441d1536bf393 100644 ---- a/dist/actor-CD3vk4f0.cjs -+++ b/dist/actor-CD3vk4f0.cjs -@@ -8017,7 +8017,7 @@ var Activity = class Activity extends Object$1 { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1" -@@ -8346,7 +8346,7 @@ var EmojiReact = class EmojiReact extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -10613,7 +10613,7 @@ var Accept = class Accept extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -10775,7 +10775,7 @@ var Add = class Add extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -10935,7 +10935,7 @@ var Announce = class Announce extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -14484,7 +14484,7 @@ var IntransitiveActivity = class IntransitiveActivity extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -14647,7 +14647,7 @@ var Arrive = class Arrive extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -15489,7 +15489,7 @@ var Ignore = class Ignore extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -15651,7 +15651,7 @@ var Block = class Block extends Ignore { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -18941,7 +18941,7 @@ var Create = class Create extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -19120,7 +19120,7 @@ var Delete = class Delete extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -19294,7 +19294,7 @@ var Dislike = class Dislike extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -20069,7 +20069,7 @@ var Flag = class Flag extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -20230,7 +20230,7 @@ var Follow = class Follow extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -24882,7 +24882,7 @@ var Offer = class Offer extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25042,7 +25042,7 @@ var Invite = class Invite extends Offer { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25201,7 +25201,7 @@ var Join = class Join extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25360,7 +25360,7 @@ var Leave = class Leave extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25519,7 +25519,7 @@ var Like = class Like extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -25681,7 +25681,7 @@ var Listen = class Listen extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -26004,7 +26004,7 @@ var Move = class Move extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -35453,7 +35453,7 @@ var Question = class Question extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -35710,7 +35710,7 @@ var Read = class Read extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -35869,7 +35869,7 @@ var Reject = class Reject extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -36840,7 +36840,7 @@ var Remove = class Remove extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -40656,7 +40656,7 @@ var TentativeAccept = class TentativeAccept extends Accept { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -40815,7 +40815,7 @@ var TentativeReject = class TentativeReject extends Reject { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -41188,7 +41188,7 @@ var Travel = class Travel extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -41352,7 +41352,7 @@ var Undo = class Undo extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -41523,7 +41523,7 @@ var Update = class Update extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -41896,7 +41896,7 @@ var View = class View extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -diff --git a/dist/actor-bgf-5lfW.js b/dist/actor-bgf-5lfW.js -index 4ac54e7711b13c086922982f4d8b3bfd200cfba8..e0fdf85487bf5ffe93524406dc7e186e65e3b03f 100644 ---- a/dist/actor-bgf-5lfW.js -+++ b/dist/actor-bgf-5lfW.js -@@ -8016,7 +8016,7 @@ var Activity = class Activity extends Object$1 { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1" -@@ -8345,7 +8345,7 @@ var EmojiReact = class EmojiReact extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -10612,7 +10612,7 @@ var Accept = class Accept extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -10774,7 +10774,7 @@ var Add = class Add extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -10934,7 +10934,7 @@ var Announce = class Announce extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -14483,7 +14483,7 @@ var IntransitiveActivity = class IntransitiveActivity extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -14646,7 +14646,7 @@ var Arrive = class Arrive extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -15488,7 +15488,7 @@ var Ignore = class Ignore extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -15650,7 +15650,7 @@ var Block = class Block extends Ignore { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -18940,7 +18940,7 @@ var Create = class Create extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -19119,7 +19119,7 @@ var Delete = class Delete extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -19293,7 +19293,7 @@ var Dislike = class Dislike extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -20068,7 +20068,7 @@ var Flag = class Flag extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -20229,7 +20229,7 @@ var Follow = class Follow extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -24881,7 +24881,7 @@ var Offer = class Offer extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25041,7 +25041,7 @@ var Invite = class Invite extends Offer { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25200,7 +25200,7 @@ var Join = class Join extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25359,7 +25359,7 @@ var Leave = class Leave extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25518,7 +25518,7 @@ var Like = class Like extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -25680,7 +25680,7 @@ var Listen = class Listen extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -26003,7 +26003,7 @@ var Move = class Move extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -35452,7 +35452,7 @@ var Question = class Question extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -35709,7 +35709,7 @@ var Read = class Read extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -35868,7 +35868,7 @@ var Reject = class Reject extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -36839,7 +36839,7 @@ var Remove = class Remove extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -40655,7 +40655,7 @@ var TentativeAccept = class TentativeAccept extends Accept { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -40814,7 +40814,7 @@ var TentativeReject = class TentativeReject extends Reject { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -41187,7 +41187,7 @@ var Travel = class Travel extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -41351,7 +41351,7 @@ var Undo = class Undo extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -41522,7 +41522,7 @@ var Update = class Update extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -41895,7 +41895,7 @@ var View = class View extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -diff --git a/dist/federation/handler.test.js b/dist/federation/handler.test.js -index 4e5d5f045684ff4447c9687ef00cd176d06df9ee..f8d9bdbbbd96c6851845d9ab350a6d512f7e8cfb 100644 ---- a/dist/federation/handler.test.js -+++ b/dist/federation/handler.test.js -@@ -635,7 +635,7 @@ test("handleCollection()", async () => { - assertEquals(response.status, 200); - assertEquals(response.headers.get("Content-Type"), "application/activity+json"); - const createCtx = [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -1395,7 +1395,7 @@ test("handleCustomCollection()", async () => { - assertEquals(response.status, 200); - assertEquals(response.headers.get("Content-Type"), "application/activity+json"); - const createCtx = [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -diff --git a/dist/ld-C3DOGrIw.js b/dist/ld-C3DOGrIw.js -index f98975ab3ce51811652f7c8e371585177ab45e2f..42d8cb606a32e22db28ad44a8e9a4141afc853a9 100644 ---- a/dist/ld-C3DOGrIw.js -+++ b/dist/ld-C3DOGrIw.js -@@ -48,7 +48,7 @@ async function createSignature(jsonLd, privateKey, keyId, { contextLoader, creat - validateCryptoKey(privateKey, "private"); - if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name); - const options = { -- "@context": "https://w3id.org/identity/v1", -+ "@context": "https://w3id.org/security/v1", - creator: keyId.href, - created: created?.toString() ?? (/* @__PURE__ */ new Date()).toISOString() - }; -@@ -152,7 +152,7 @@ async function verifySignature(jsonLd, options = {}) { - if (key == null) return null; - const sigOpts = { - ...sig, -- "@context": "https://w3id.org/identity/v1" -+ "@context": "https://w3id.org/security/v1" - }; - delete sigOpts.type; - delete sigOpts.id; -diff --git a/dist/mod-BZfdiPBo.d.ts b/dist/mod-BZfdiPBo.d.ts -index 861963f5d67277ec7b0b9a16909badf489b9efb4..0b62aa96887a5c825f3b9321ef43c230ea33ae3e 100644 ---- a/dist/mod-BZfdiPBo.d.ts -+++ b/dist/mod-BZfdiPBo.d.ts -@@ -1,7 +1,12 @@ - import { Temporal } from "@js-temporal/polyfill"; - import { URLPattern } from "urlpattern-polyfill"; - import { DocumentLoader } from "./docloader-BucCRHZI.js"; --import { CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "./vocab-BASuuzcJ.js"; -+import { -+ CryptographicKey, -+ DataIntegrityProof, -+ Multikey, -+ Object as Object$1, -+} from "./vocab-BASuuzcJ.js"; - import { KeyCache } from "./http-DS9z_HzB.js"; - import { TracerProvider } from "@opentelemetry/api"; - -@@ -11,7 +16,7 @@ import { TracerProvider } from "@opentelemetry/api"; - * @since 1.0.0 - */ - interface Signature { -- "@context"?: "https://w3id.org/identity/v1"; -+ "@context"?: "https://w3id.org/security/v1"; - type: "RsaSignature2017"; - id?: string; - creator: string; -@@ -27,7 +32,10 @@ interface Signature { - * @throws {TypeError} If the input document is not a valid JSON-LD document. - * @since 1.0.0 - */ --declare function attachSignature(jsonLd: unknown, signature: Signature): { -+declare function attachSignature( -+ jsonLd: unknown, -+ signature: Signature -+): { - signature: Signature; - }; - /** -@@ -56,10 +64,12 @@ interface CreateSignatureOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 1.0.0 - */ --declare function createSignature(jsonLd: unknown, privateKey: CryptoKey, keyId: URL, { -- contextLoader, -- created --}?: CreateSignatureOptions): Promise; -+declare function createSignature( -+ jsonLd: unknown, -+ privateKey: CryptoKey, -+ keyId: URL, -+ { contextLoader, created }?: CreateSignatureOptions -+): Promise; - /** - * Options for signing JSON-LD documents. - * @since 1.0.0 -@@ -85,7 +95,12 @@ interface SignJsonLdOptions extends CreateSignatureOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 1.0.0 - */ --declare function signJsonLd(jsonLd: unknown, privateKey: CryptoKey, keyId: URL, options: SignJsonLdOptions): Promise<{ -+declare function signJsonLd( -+ jsonLd: unknown, -+ privateKey: CryptoKey, -+ keyId: URL, -+ options: SignJsonLdOptions -+): Promise<{ - signature: Signature; - }>; - /** -@@ -128,7 +143,10 @@ interface VerifySignatureOptions { - * is invalid or the key is not found. - * @since 1.0.0 - */ --declare function verifySignature(jsonLd: unknown, options?: VerifySignatureOptions): Promise; -+declare function verifySignature( -+ jsonLd: unknown, -+ options?: VerifySignatureOptions -+): Promise; - /** - * Options for verifying JSON-LD documents. - */ -@@ -142,7 +160,10 @@ interface VerifyJsonLdOptions extends VerifySignatureOptions {} - * @param options Options for verifying the document. - * @returns `true` if the document is authentic; `false` otherwise. - */ --declare function verifyJsonLd(jsonLd: unknown, options?: VerifyJsonLdOptions): Promise; -+declare function verifyJsonLd( -+ jsonLd: unknown, -+ options?: VerifyJsonLdOptions -+): Promise; - //#endregion - //#region src/sig/proof.d.ts - /** -@@ -157,7 +178,10 @@ interface CreateProofOptions { - /** - * The JSON-LD context to use for serializing the object to sign. - */ -- context?: string | Record | (string | Record)[]; -+ context?: -+ | string -+ | Record -+ | (string | Record)[]; - /** - * The time when the proof was created. If not specified, the current time - * will be used. -@@ -174,11 +198,12 @@ interface CreateProofOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 0.10.0 - */ --declare function createProof(object: Object$1, privateKey: CryptoKey, keyId: URL, { -- contextLoader, -- context, -- created --}?: CreateProofOptions): Promise; -+declare function createProof( -+ object: Object$1, -+ privateKey: CryptoKey, -+ keyId: URL, -+ { contextLoader, context, created }?: CreateProofOptions -+): Promise; - /** - * Options for {@link signObject}. - * @since 0.10.0 -@@ -205,7 +230,12 @@ interface SignObjectOptions extends CreateProofOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 0.10.0 - */ --declare function signObject(object: T, privateKey: CryptoKey, keyId: URL, options?: SignObjectOptions): Promise; -+declare function signObject( -+ object: T, -+ privateKey: CryptoKey, -+ keyId: URL, -+ options?: SignObjectOptions -+): Promise; - /** - * Options for {@link verifyProof}. - * @since 0.10.0 -@@ -241,7 +271,11 @@ interface VerifyProofOptions { - * proof is invalid. - * @since 0.10.0 - */ --declare function verifyProof(jsonLd: unknown, proof: DataIntegrityProof, options?: VerifyProofOptions): Promise; -+declare function verifyProof( -+ jsonLd: unknown, -+ proof: DataIntegrityProof, -+ options?: VerifyProofOptions -+): Promise; - /** - * Options for {@link verifyObject}. - * @since 0.10.0 -@@ -261,8 +295,31 @@ interface VerifyObjectOptions extends VerifyProofOptions {} - * @throws {TypeError} If the object is invalid or unsupported. - * @since 0.10.0 - */ --declare function verifyObject(cls: (new (...args: any[]) => T) & { -- fromJsonLd(jsonLd: unknown, options: VerifyObjectOptions): Promise; --}, jsonLd: unknown, options?: VerifyObjectOptions): Promise; -+declare function verifyObject( -+ cls: (new (...args: any[]) => T) & { -+ fromJsonLd(jsonLd: unknown, options: VerifyObjectOptions): Promise; -+ }, -+ jsonLd: unknown, -+ options?: VerifyObjectOptions -+): Promise; - //#endregion --export { CreateProofOptions, CreateSignatureOptions, SignJsonLdOptions, SignObjectOptions, VerifyJsonLdOptions, VerifyObjectOptions, VerifyProofOptions, VerifySignatureOptions, attachSignature, createProof, createSignature, detachSignature, signJsonLd, signObject, verifyJsonLd, verifyObject, verifyProof, verifySignature }; -\ No newline at end of file -+export { -+ CreateProofOptions, -+ CreateSignatureOptions, -+ SignJsonLdOptions, -+ SignObjectOptions, -+ VerifyJsonLdOptions, -+ VerifyObjectOptions, -+ VerifyProofOptions, -+ VerifySignatureOptions, -+ attachSignature, -+ createProof, -+ createSignature, -+ detachSignature, -+ signJsonLd, -+ signObject, -+ verifyJsonLd, -+ verifyObject, -+ verifyProof, -+ verifySignature, -+}; -diff --git a/dist/mod-Dz5Y15Uy.d.cts b/dist/mod-Dz5Y15Uy.d.cts -index b95cb28acb117e4fa3111867c7ece92f5e1f65a7..61df31f0c96da2d7ec431ff93c631e2aa33c2b3b 100644 ---- a/dist/mod-Dz5Y15Uy.d.cts -+++ b/dist/mod-Dz5Y15Uy.d.cts -@@ -1,5 +1,10 @@ - import { DocumentLoader } from "./docloader-ChxNLZAA.cjs"; --import { CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "./vocab-DPMmFPJ1.cjs"; -+import { -+ CryptographicKey, -+ DataIntegrityProof, -+ Multikey, -+ Object as Object$1, -+} from "./vocab-DPMmFPJ1.cjs"; - import { KeyCache } from "./http-C_1RU1U_.cjs"; - import { TracerProvider } from "@opentelemetry/api"; - -@@ -9,7 +14,7 @@ import { TracerProvider } from "@opentelemetry/api"; - * @since 1.0.0 - */ - interface Signature { -- "@context"?: "https://w3id.org/identity/v1"; -+ "@context"?: "https://w3id.org/security/v1"; - type: "RsaSignature2017"; - id?: string; - creator: string; -@@ -25,7 +30,10 @@ interface Signature { - * @throws {TypeError} If the input document is not a valid JSON-LD document. - * @since 1.0.0 - */ --declare function attachSignature(jsonLd: unknown, signature: Signature): { -+declare function attachSignature( -+ jsonLd: unknown, -+ signature: Signature -+): { - signature: Signature; - }; - /** -@@ -54,10 +62,12 @@ interface CreateSignatureOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 1.0.0 - */ --declare function createSignature(jsonLd: unknown, privateKey: CryptoKey, keyId: URL, { -- contextLoader, -- created --}?: CreateSignatureOptions): Promise; -+declare function createSignature( -+ jsonLd: unknown, -+ privateKey: CryptoKey, -+ keyId: URL, -+ { contextLoader, created }?: CreateSignatureOptions -+): Promise; - /** - * Options for signing JSON-LD documents. - * @since 1.0.0 -@@ -83,7 +93,12 @@ interface SignJsonLdOptions extends CreateSignatureOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 1.0.0 - */ --declare function signJsonLd(jsonLd: unknown, privateKey: CryptoKey, keyId: URL, options: SignJsonLdOptions): Promise<{ -+declare function signJsonLd( -+ jsonLd: unknown, -+ privateKey: CryptoKey, -+ keyId: URL, -+ options: SignJsonLdOptions -+): Promise<{ - signature: Signature; - }>; - /** -@@ -126,7 +141,10 @@ interface VerifySignatureOptions { - * is invalid or the key is not found. - * @since 1.0.0 - */ --declare function verifySignature(jsonLd: unknown, options?: VerifySignatureOptions): Promise; -+declare function verifySignature( -+ jsonLd: unknown, -+ options?: VerifySignatureOptions -+): Promise; - /** - * Options for verifying JSON-LD documents. - */ -@@ -140,7 +158,10 @@ interface VerifyJsonLdOptions extends VerifySignatureOptions {} - * @param options Options for verifying the document. - * @returns `true` if the document is authentic; `false` otherwise. - */ --declare function verifyJsonLd(jsonLd: unknown, options?: VerifyJsonLdOptions): Promise; -+declare function verifyJsonLd( -+ jsonLd: unknown, -+ options?: VerifyJsonLdOptions -+): Promise; - //#endregion - //#region src/sig/proof.d.ts - /** -@@ -155,7 +176,10 @@ interface CreateProofOptions { - /** - * The JSON-LD context to use for serializing the object to sign. - */ -- context?: string | Record | (string | Record)[]; -+ context?: -+ | string -+ | Record -+ | (string | Record)[]; - /** - * The time when the proof was created. If not specified, the current time - * will be used. -@@ -172,11 +196,12 @@ interface CreateProofOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 0.10.0 - */ --declare function createProof(object: Object$1, privateKey: CryptoKey, keyId: URL, { -- contextLoader, -- context, -- created --}?: CreateProofOptions): Promise; -+declare function createProof( -+ object: Object$1, -+ privateKey: CryptoKey, -+ keyId: URL, -+ { contextLoader, context, created }?: CreateProofOptions -+): Promise; - /** - * Options for {@link signObject}. - * @since 0.10.0 -@@ -203,7 +228,12 @@ interface SignObjectOptions extends CreateProofOptions { - * @throws {TypeError} If the private key is invalid or unsupported. - * @since 0.10.0 - */ --declare function signObject(object: T, privateKey: CryptoKey, keyId: URL, options?: SignObjectOptions): Promise; -+declare function signObject( -+ object: T, -+ privateKey: CryptoKey, -+ keyId: URL, -+ options?: SignObjectOptions -+): Promise; - /** - * Options for {@link verifyProof}. - * @since 0.10.0 -@@ -239,7 +269,11 @@ interface VerifyProofOptions { - * proof is invalid. - * @since 0.10.0 - */ --declare function verifyProof(jsonLd: unknown, proof: DataIntegrityProof, options?: VerifyProofOptions): Promise; -+declare function verifyProof( -+ jsonLd: unknown, -+ proof: DataIntegrityProof, -+ options?: VerifyProofOptions -+): Promise; - /** - * Options for {@link verifyObject}. - * @since 0.10.0 -@@ -259,8 +293,31 @@ interface VerifyObjectOptions extends VerifyProofOptions {} - * @throws {TypeError} If the object is invalid or unsupported. - * @since 0.10.0 - */ --declare function verifyObject(cls: (new (...args: any[]) => T) & { -- fromJsonLd(jsonLd: unknown, options: VerifyObjectOptions): Promise; --}, jsonLd: unknown, options?: VerifyObjectOptions): Promise; -+declare function verifyObject( -+ cls: (new (...args: any[]) => T) & { -+ fromJsonLd(jsonLd: unknown, options: VerifyObjectOptions): Promise; -+ }, -+ jsonLd: unknown, -+ options?: VerifyObjectOptions -+): Promise; - //#endregion --export { CreateProofOptions, CreateSignatureOptions, SignJsonLdOptions, SignObjectOptions, VerifyJsonLdOptions, VerifyObjectOptions, VerifyProofOptions, VerifySignatureOptions, attachSignature, createProof, createSignature, detachSignature, signJsonLd, signObject, verifyJsonLd, verifyObject, verifyProof, verifySignature }; -\ No newline at end of file -+export { -+ CreateProofOptions, -+ CreateSignatureOptions, -+ SignJsonLdOptions, -+ SignObjectOptions, -+ VerifyJsonLdOptions, -+ VerifyObjectOptions, -+ VerifyProofOptions, -+ VerifySignatureOptions, -+ attachSignature, -+ createProof, -+ createSignature, -+ detachSignature, -+ signJsonLd, -+ signObject, -+ verifyJsonLd, -+ verifyObject, -+ verifyProof, -+ verifySignature, -+}; -diff --git a/dist/proof-Ea3ykPsy.js b/dist/proof-Ea3ykPsy.js -index 843160b38f61188d586e6d36ac907558acc7f879..0be333df071b379831e18f7cee09c632f3adba35 100644 ---- a/dist/proof-Ea3ykPsy.js -+++ b/dist/proof-Ea3ykPsy.js -@@ -49,7 +49,7 @@ async function createSignature(jsonLd, privateKey, keyId, { contextLoader, creat - validateCryptoKey(privateKey, "private"); - if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name); - const options = { -- "@context": "https://w3id.org/identity/v1", -+ "@context": "https://w3id.org/security/v1", - creator: keyId.href, - created: created?.toString() ?? (/* @__PURE__ */ new Date()).toISOString() - }; -@@ -153,7 +153,7 @@ async function verifySignature(jsonLd, options = {}) { - if (key == null) return null; - const sigOpts = { - ...sig, -- "@context": "https://w3id.org/identity/v1" -+ "@context": "https://w3id.org/security/v1" - }; - delete sigOpts.type; - delete sigOpts.id; -diff --git a/dist/proof-gU4Y_14I.cjs b/dist/proof-gU4Y_14I.cjs -index ffd9090832b31b77373025856e040b2a7fc7b974..d11b20da1e756502601152b85d845ec37040a704 100644 ---- a/dist/proof-gU4Y_14I.cjs -+++ b/dist/proof-gU4Y_14I.cjs -@@ -50,7 +50,7 @@ async function createSignature(jsonLd, privateKey, keyId, { contextLoader, creat - require_key.validateCryptoKey(privateKey, "private"); - if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name); - const options = { -- "@context": "https://w3id.org/identity/v1", -+ "@context": "https://w3id.org/security/v1", - creator: keyId.href, - created: created?.toString() ?? (/* @__PURE__ */ new Date()).toISOString() - }; -@@ -154,7 +154,7 @@ async function verifySignature(jsonLd, options = {}) { - if (key == null) return null; - const sigOpts = { - ...sig, -- "@context": "https://w3id.org/identity/v1" -+ "@context": "https://w3id.org/security/v1" - }; - delete sigOpts.type; - delete sigOpts.id; -diff --git a/dist/sig/ld.test.js b/dist/sig/ld.test.js -index 5746336fee296387709a0d9bebf9199113ec0042..c0cb9857eb9671c67d7b7833f8944eb31df9c684 100644 ---- a/dist/sig/ld.test.js -+++ b/dist/sig/ld.test.js -@@ -20,7 +20,7 @@ import { encodeBase64 } from "byte-encodings/base64"; - //#region src/sig/ld.test.ts - test("attachSignature()", () => { - const sig = { -- "@context": "https://w3id.org/identity/v1", -+ "@context": "https://w3id.org/security/v1", - type: "RsaSignature2017", - creator: "https://activitypub.academy/users/brauca_darradiul#main-key", - created: "2024-09-12T16:50:46Z", -diff --git a/dist/src/vocab/accept.yaml b/dist/src/vocab/accept.yaml -index 1145fca566de88f4f9870938c33ad910a94e6a75..8a02c3b9874092580254b34635c9056c325780e5 100644 ---- a/dist/src/vocab/accept.yaml -+++ b/dist/src/vocab/accept.yaml -@@ -9,7 +9,7 @@ description: | - used in certain circumstances to indicate the context into which the `object` - has been accepted. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/activity.yaml b/dist/src/vocab/activity.yaml -index e4216ca8d994427aca9fb75015ea584b81b62d52..1c0d1675b86ee5952292d2bb5be1050f9860fe90 100644 ---- a/dist/src/vocab/activity.yaml -+++ b/dist/src/vocab/activity.yaml -@@ -11,7 +11,7 @@ description: | - of activities. It is important to note that the {@link Activity} type itself - does not carry any specific semantics about the kind of action being taken. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/v1" - - "https://w3id.org/security/data-integrity/v1" -diff --git a/dist/src/vocab/add.yaml b/dist/src/vocab/add.yaml -index 189f07dbb62174fe187e0e72872113c745491b4e..1537609296f4049d3ab9cf3122433f8c42858f5e 100644 ---- a/dist/src/vocab/add.yaml -+++ b/dist/src/vocab/add.yaml -@@ -10,7 +10,7 @@ description: | - to be determined implicitly by context. The `origin` can be used to identify - the context from which the `object` originated. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/announce.yaml b/dist/src/vocab/announce.yaml -index 6663c10bf278b2db32f283333124728b166b5e16..a928189c32fa4dd3763d19fcb96d64d4be03189d 100644 ---- a/dist/src/vocab/announce.yaml -+++ b/dist/src/vocab/announce.yaml -@@ -9,7 +9,7 @@ description: | - - The `origin` typically has no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - toot: "http://joinmastodon.org/ns#" -diff --git a/dist/src/vocab/arrive.yaml b/dist/src/vocab/arrive.yaml -index 67dd84a05f34263e6324d66c7431f202247beae2..79d9ada3e55417e3a9880ced6e335694dc4835f4 100644 ---- a/dist/src/vocab/arrive.yaml -+++ b/dist/src/vocab/arrive.yaml -@@ -9,7 +9,7 @@ description: | - The `origin` can be used to identify the context from which the `actor` originated. - The `target` typically has no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/block.yaml b/dist/src/vocab/block.yaml -index 25a8231b86a7ebdde65dac0ebe4d2ee1cede53d9..a513b34d79c392cdfe4413e671d39b0fff47e0e0 100644 ---- a/dist/src/vocab/block.yaml -+++ b/dist/src/vocab/block.yaml -@@ -10,7 +10,7 @@ description: | - allow one user to block activities or content of other users. The `target` - and `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/create.yaml b/dist/src/vocab/create.yaml -index b6befc5497215c9d83e8ca7cb0e012577d745cc9..e75ca377639bc3ad4efc1dcdd900206971f4d7a5 100644 ---- a/dist/src/vocab/create.yaml -+++ b/dist/src/vocab/create.yaml -@@ -6,7 +6,7 @@ extends: "https://www.w3.org/ns/activitystreams#Activity" - entity: true - description: Indicates that the `actor` has created the `object`. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - toot: "http://joinmastodon.org/ns#" -diff --git a/dist/src/vocab/delete.yaml b/dist/src/vocab/delete.yaml -index 4818eb994e2dfe086fcdc10e67689f7222341ab5..b4893773a83852dfe6889e9c09f80aaaf02690ac 100644 ---- a/dist/src/vocab/delete.yaml -+++ b/dist/src/vocab/delete.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` has deleted the `object`. If specified, - the `origin` indicates the context from which the `object` was deleted. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - toot: "http://joinmastodon.org/ns#" -diff --git a/dist/src/vocab/dislike.yaml b/dist/src/vocab/dislike.yaml -index b39f5c23e8c70400f360ae0ff55526146c01aa9a..8fb157af78ece7e2469c7e491255f7e6b9e6897c 100644 ---- a/dist/src/vocab/dislike.yaml -+++ b/dist/src/vocab/dislike.yaml -@@ -6,7 +6,7 @@ extends: "https://www.w3.org/ns/activitystreams#Activity" - entity: true - description: Indicates that the `actor` dislikes the `object`. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - toot: "http://joinmastodon.org/ns#" -diff --git a/dist/src/vocab/emojireact.yaml b/dist/src/vocab/emojireact.yaml -index 03360ba24cde74c221da601d0476357e183f3c64..7aa1bff8566058d6aeb58f4d04eefc41fc0864aa 100644 ---- a/dist/src/vocab/emojireact.yaml -+++ b/dist/src/vocab/emojireact.yaml -@@ -7,7 +7,7 @@ entity: true - description: | - Represents an emoji reaction. See also [FEP-c0e0](https://w3id.org/fep/c0e0). - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - litepub: "http://litepub.social/ns#" -diff --git a/dist/src/vocab/flag.yaml b/dist/src/vocab/flag.yaml -index caa47e580e76cf373cc9e99ca553925c6cbabe22..2c73894b7ee87655c865b6330eb2c5bf73888d77 100644 ---- a/dist/src/vocab/flag.yaml -+++ b/dist/src/vocab/flag.yaml -@@ -9,7 +9,7 @@ description: | - in the sense common to many social platforms as reporting content as being - inappropriate for any number of reasons. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/follow.yaml b/dist/src/vocab/follow.yaml -index 4565eeda70e6572872703bd7141596f38eea498a..8335117efd8b3680ca5de73f146e70bf609db16b 100644 ---- a/dist/src/vocab/follow.yaml -+++ b/dist/src/vocab/follow.yaml -@@ -10,7 +10,7 @@ description: | - interested in any activity performed by or on the object. The `target` and - `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/v1" - - "https://w3id.org/security/data-integrity/v1" -diff --git a/dist/src/vocab/ignore.yaml b/dist/src/vocab/ignore.yaml -index cc9d39f620baa828228d056e4a0724754bdf635d..ab936fc45fef5410c28261b01d589989f0b89e91 100644 ---- a/dist/src/vocab/ignore.yaml -+++ b/dist/src/vocab/ignore.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` is ignoring the `object`. The `target` and - `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/intransitiveactivity.yaml b/dist/src/vocab/intransitiveactivity.yaml -index e6e06609b53e5377b91b6b46bb1043cb414b5dc2..d785eeea5aeefe920ffe8a8f3cd42d539a6c4598 100644 ---- a/dist/src/vocab/intransitiveactivity.yaml -+++ b/dist/src/vocab/intransitiveactivity.yaml -@@ -9,7 +9,7 @@ description: | - representing intransitive actions. The `object` property is therefore - inappropriate for these activities. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/invite.yaml b/dist/src/vocab/invite.yaml -index e3f314f895fcfeb2543f80e33fb3756668c0dfc2..d60c575ece3b48f9a51de6e3ba3c15f7f47cf3e0 100644 ---- a/dist/src/vocab/invite.yaml -+++ b/dist/src/vocab/invite.yaml -@@ -8,7 +8,7 @@ description: | - A specialization of `Offer` in which the `actor` is extending an invitation - for the `object` to the `target`. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/join.yaml b/dist/src/vocab/join.yaml -index f0c0dfcf25409d342a07d85770274ff1c4864a9c..358b1b306dda2c54e84e48f2db0f4ad8a9726af0 100644 ---- a/dist/src/vocab/join.yaml -+++ b/dist/src/vocab/join.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` has joined the `object`. - The `target` and `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/leave.yaml b/dist/src/vocab/leave.yaml -index 37be38538da2c5edbd3d9a87a743843e0e38351f..851216e1f9ae1fc0ed97fbac5ee0416e696f7089 100644 ---- a/dist/src/vocab/leave.yaml -+++ b/dist/src/vocab/leave.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` has left the `object`. - The `target` and `origin` typically have no meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/like.yaml b/dist/src/vocab/like.yaml -index 43b63368cd5c023e140df4536d33e40c395bf522..61ee1280c589bee29c72d074c07a419c092202ee 100644 ---- a/dist/src/vocab/like.yaml -+++ b/dist/src/vocab/like.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` likes, recommends or endorses the `object`. - The `target` and `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - toot: "http://joinmastodon.org/ns#" -diff --git a/dist/src/vocab/listen.yaml b/dist/src/vocab/listen.yaml -index 8d45179770a189bfb16011b921e52bcd700912fc..48e034891010bf321f5827c24541a71f3f5eab5b 100644 ---- a/dist/src/vocab/listen.yaml -+++ b/dist/src/vocab/listen.yaml -@@ -6,7 +6,7 @@ extends: "https://www.w3.org/ns/activitystreams#Activity" - entity: true - description: Indicates that the `actor` has listened to the `object`. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/move.yaml b/dist/src/vocab/move.yaml -index acc32cfe323f3a1df40830473c02b5327dee3860..c7073b6597d0b7cc4979d83c2c497f4dabd17faf 100644 ---- a/dist/src/vocab/move.yaml -+++ b/dist/src/vocab/move.yaml -@@ -9,7 +9,7 @@ description: | - If the `origin` or `target` are not specified, - either can be determined by context. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/offer.yaml b/dist/src/vocab/offer.yaml -index c22d5c28887515447b21e2294f1dfad7b6d259cb..92ed4478e265036141339baf269bf81bb020872c 100644 ---- a/dist/src/vocab/offer.yaml -+++ b/dist/src/vocab/offer.yaml -@@ -9,7 +9,7 @@ description: | - If specified, the target indicates the entity to which - the object is being offered. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/question.yaml b/dist/src/vocab/question.yaml -index 5a2de11a8f7ca98f3e02395e05055d8193ea4a16..3e78060444a1702005a24bbd9afab182a6a2e02c 100644 ---- a/dist/src/vocab/question.yaml -+++ b/dist/src/vocab/question.yaml -@@ -14,7 +14,7 @@ description: | - used to express possible answers, but a Question object *must not* have both - properties. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - - toot: "http://joinmastodon.org/ns#" -diff --git a/dist/src/vocab/read.yaml b/dist/src/vocab/read.yaml -index e00257b91a2cc9178fa19ba3598b0eb826b1eb7f..7ee76614948252ef8de8e72634925b6998ede5f7 100644 ---- a/dist/src/vocab/read.yaml -+++ b/dist/src/vocab/read.yaml -@@ -7,7 +7,7 @@ entity: true - description: | - Indicates that the `actor` has read the `object`. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/reject.yaml b/dist/src/vocab/reject.yaml -index 89f34e9b90971008fcc86cba2c31d15027d192c4..292c772fdd4a113216dabaf7e8c974a1191a3a5c 100644 ---- a/dist/src/vocab/reject.yaml -+++ b/dist/src/vocab/reject.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` is rejecting the `object`. The `target` and - `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/remove.yaml b/dist/src/vocab/remove.yaml -index 870c09a7da2e1932c599b1cffbc8227264c796d9..a37d63ea1e59a4bd20d706c80c68d3f972d7609d 100644 ---- a/dist/src/vocab/remove.yaml -+++ b/dist/src/vocab/remove.yaml -@@ -8,7 +8,7 @@ description: | - Indicates that the `actor` is removing the `object`. If specified, - the `origin` indicates the context from which the `object` is being removed. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/tentativeaccept.yaml b/dist/src/vocab/tentativeaccept.yaml -index fd5d2a5f0bf115e0ade24c6806904d8e8ce342e3..18517eaf2ed0a11b7745fd818d78f63b94b98eb5 100644 ---- a/dist/src/vocab/tentativeaccept.yaml -+++ b/dist/src/vocab/tentativeaccept.yaml -@@ -8,7 +8,7 @@ description: | - A specialization of {@link Accept} indicating that - the acceptance is tentative. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/tentativereject.yaml b/dist/src/vocab/tentativereject.yaml -index a691b769687b5320d7042056b48b7986c9a19594..b18eae71435b106a32753c8f8b609db250c07205 100644 ---- a/dist/src/vocab/tentativereject.yaml -+++ b/dist/src/vocab/tentativereject.yaml -@@ -8,7 +8,7 @@ description: | - A specialization of {@link Reject} in which - the rejection is considered tentative. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/travel.yaml b/dist/src/vocab/travel.yaml -index 3293463feb56eea75cf3aada782741a69758e189..62fc959b549d32a28143cb7d53f9b164dca73b98 100644 ---- a/dist/src/vocab/travel.yaml -+++ b/dist/src/vocab/travel.yaml -@@ -10,7 +10,7 @@ description: | - If the `target` or `origin` are not specified, - either can be determined by context. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/src/vocab/undo.yaml b/dist/src/vocab/undo.yaml -index efb789d8860ea1f1c21d4ff73cfba6d0d0a8001f..e87c42af5f8d51281ae596a9dc744fb1beee2f8d 100644 ---- a/dist/src/vocab/undo.yaml -+++ b/dist/src/vocab/undo.yaml -@@ -13,7 +13,7 @@ description: | - - The `target` and `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/v1" - - "https://w3id.org/security/data-integrity/v1" -diff --git a/dist/src/vocab/update.yaml b/dist/src/vocab/update.yaml -index 53cad4fe566176bc183fd379402bccfa1fe88d5e..91dbcccdfb7db1bf790efdbbfda872d7338e8f2a 100644 ---- a/dist/src/vocab/update.yaml -+++ b/dist/src/vocab/update.yaml -@@ -11,7 +11,7 @@ description: | - - The `target` and `origin` typically have no defined meaning. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/v1" - - "https://w3id.org/security/data-integrity/v1" -diff --git a/dist/src/vocab/view.yaml b/dist/src/vocab/view.yaml -index 55bd35479f810a4ee78b7b4dc57117e833687130..eae3349c3824fa719a2402324663517501c51b61 100644 ---- a/dist/src/vocab/view.yaml -+++ b/dist/src/vocab/view.yaml -@@ -7,7 +7,7 @@ entity: true - description: | - Indicates that the `actor` has viewed the object. - defaultContext: --- "https://w3id.org/identity/v1" -+- "https://w3id.org/security/v1" - - "https://www.w3.org/ns/activitystreams" - - "https://w3id.org/security/data-integrity/v1" - properties: [] -diff --git a/dist/type-DqEM8B7_.js b/dist/type-DqEM8B7_.js -index b50c498ddd8a148e9a730bfb98113ab7c1aad578..c0fb81d156f7c54eee3fcdd1abca87d52ae0aeb4 100644 ---- a/dist/type-DqEM8B7_.js -+++ b/dist/type-DqEM8B7_.js -@@ -12936,7 +12936,7 @@ var Activity = class Activity extends Object$1 { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1" -@@ -13265,7 +13265,7 @@ var EmojiReact = class EmojiReact extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -15532,7 +15532,7 @@ var Accept = class Accept extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -15694,7 +15694,7 @@ var Add = class Add extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -15854,7 +15854,7 @@ var Announce = class Announce extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -19403,7 +19403,7 @@ var IntransitiveActivity = class IntransitiveActivity extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -19566,7 +19566,7 @@ var Arrive = class Arrive extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -20408,7 +20408,7 @@ var Ignore = class Ignore extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -20570,7 +20570,7 @@ var Block = class Block extends Ignore { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -23860,7 +23860,7 @@ var Create = class Create extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -24039,7 +24039,7 @@ var Delete = class Delete extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -24213,7 +24213,7 @@ var Dislike = class Dislike extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -24988,7 +24988,7 @@ var Flag = class Flag extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -25149,7 +25149,7 @@ var Follow = class Follow extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -29801,7 +29801,7 @@ var Offer = class Offer extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -29961,7 +29961,7 @@ var Invite = class Invite extends Offer { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -30120,7 +30120,7 @@ var Join = class Join extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -30279,7 +30279,7 @@ var Leave = class Leave extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -30438,7 +30438,7 @@ var Like = class Like extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -30600,7 +30600,7 @@ var Listen = class Listen extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -30923,7 +30923,7 @@ var Move = class Move extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -40372,7 +40372,7 @@ var Question = class Question extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1", - { -@@ -40629,7 +40629,7 @@ var Read = class Read extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -40788,7 +40788,7 @@ var Reject = class Reject extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -41759,7 +41759,7 @@ var Remove = class Remove extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -45575,7 +45575,7 @@ var TentativeAccept = class TentativeAccept extends Accept { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -45734,7 +45734,7 @@ var TentativeReject = class TentativeReject extends Reject { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -46107,7 +46107,7 @@ var Travel = class Travel extends IntransitiveActivity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -@@ -46271,7 +46271,7 @@ var Undo = class Undo extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -46442,7 +46442,7 @@ var Update = class Update extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1", -@@ -46815,7 +46815,7 @@ var View = class View extends Activity { - if (this.id != null) values["@id"] = this.id.href; - if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader }); - const docContext = options.context ?? [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/data-integrity/v1" - ]; -diff --git a/dist/vocab/vocab.test.js b/dist/vocab/vocab.test.js -index 5e2d36dbcca3eb3fbf08b77c7b1f20c5c4d2399f..e95e0efeb5095c295f6aaa3b5210a3c8ff6101db 100644 ---- a/dist/vocab/vocab.test.js -+++ b/dist/vocab/vocab.test.js -@@ -2723,7 +2723,7 @@ test({ - const jsonLd = await activity.toJsonLd(); - assertEquals(jsonLd, { - "@context": [ -- "https://w3id.org/identity/v1", -+ "https://w3id.org/security/v1", - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - "https://w3id.org/security/data-integrity/v1" diff --git a/backend/package.json b/backend/package.json index 79fae83..15ecc0b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -6,9 +6,11 @@ "private": true, "type": "module", "dependencies": { - "@fedify/express": "^0.2.1", - "@fedify/fedify": "patch:@fedify/fedify@npm%3A1.10.0#~/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch", - "@fedify/redis": "^1.10.10", + "@fedify/express": "^2.3.1", + "@fedify/fedify": "^2.3.1", + "@fedify/redis": "^2.3.1", + "@fedify/vocab": "^2.3.1", + "@fedify/webfinger": "^2.3.1", "@js-temporal/polyfill": "^0.5.1", "@logtape/logtape": "^0.9.2", "@prisma/client": "^5.22.0", diff --git a/backend/src/__tests__/federation.test.ts b/backend/src/__tests__/federation.test.ts index 09cba39..d397552 100644 --- a/backend/src/__tests__/federation.test.ts +++ b/backend/src/__tests__/federation.test.ts @@ -315,7 +315,7 @@ describe.for( ]); // Reply using the real received object - const { Note, Mention } = await import("@fedify/fedify"); + const { Note, Mention } = await import("@fedify/vocab"); replyContent = `Reply to real message ${sessionId}`; const replyNote = new Note({ to: capturedActor, diff --git a/backend/src/apub/federation.ts b/backend/src/apub/federation.ts index e2fb80b..289060f 100644 --- a/backend/src/apub/federation.ts +++ b/backend/src/apub/federation.ts @@ -1,18 +1,20 @@ import { - ChatMessage, - Create, createFederation, - Endpoints, exportJwk, - Follow, generateCryptoKeyPair, importJwk, +} from "@fedify/fedify"; +import { + ChatMessage, + Create, + Endpoints, + Follow, isActor, lookupObject, Note, Reject, Service, -} from "@fedify/fedify"; +} from "@fedify/vocab"; import { RedisKvStore, RedisMessageQueue } from "@fedify/redis"; import { Redis } from "ioredis"; import { FedifyTransformers } from "./transformers.js"; diff --git a/backend/src/apub/utils.live.ts b/backend/src/apub/utils.live.ts index 18c77ff..85704e3 100644 --- a/backend/src/apub/utils.live.ts +++ b/backend/src/apub/utils.live.ts @@ -1,23 +1,16 @@ +import { Context, ConstructorWithTypeId } from "@fedify/fedify"; import { Actor, - ChatMessage, - ConstructorWithTypeId, - Context, Create, Delete, isActor, lookupObject, LookupObjectOptions, - lookupWebFinger, - Mention, - Note, Object, - Tombstone, -} from "@fedify/fedify"; -import * as fedify from "@fedify/fedify"; +} from "@fedify/vocab"; +import { lookupWebFinger } from "@fedify/webfinger"; +import * as vocab from "@fedify/vocab"; import { federation, USER_IDENTIFIER } from "./federation.js"; -import { Temporal } from "@js-temporal/polyfill"; -import { AuthSession } from "../models/AuthSession.js"; import { IProfile } from "../lib/instance/userMeta.js"; import { _staticType, getSafeURL } from "../lib/utils.js"; import { @@ -29,13 +22,6 @@ import { import { hash } from "node:crypto"; import { SentAP } from "../models/SentAP.redis.js"; -type BuildObjectOpts = { - id: string; - one_time_code: string; - createdAt: Date; - target: Actor; -}; - /** * @internal -- See apub/utils.ts */ @@ -142,8 +128,8 @@ export class APubLive implements IAPubUtils { const apub = this.get(); const ts = Date.now(); const outbox = [ - await message.build(fedify.Note), - await message.build(fedify.ChatMessage), + await message.build(vocab.Note), + await message.build(vocab.ChatMessage), ].map((obj) => apub.prepareObject(obj, ts)); return await Promise.allSettled( @@ -180,7 +166,7 @@ export class APubLive implements IAPubUtils { ); } - static async reply(replyTo: T, reply: T) { + static async reply(replyTo: T, reply: T) { const apub = this.get(); const recipients = await apub.getRecipients(reply); @@ -243,7 +229,7 @@ export class APubLive implements IAPubUtils { ); } - private async getRecipients(object: fedify.Object) { + private async getRecipients(object: vocab.Object) { const docLoader = await this.ctx.getDocumentLoader({ identifier: USER_IDENTIFIER, }); @@ -254,21 +240,21 @@ export class APubLive implements IAPubUtils { ); const recipients = recipientsLoader .filter((l) => l.status === "fulfilled") - .filter((l): l is { value: fedify.Object; status: "fulfilled" } => + .filter((l): l is { value: vocab.Object; status: "fulfilled" } => Boolean(l.value), ) .map((l) => l.value) - .filter((l) => fedify.isActor(l)); + .filter((l) => vocab.isActor(l)); return recipients; } - private prepareObject( + private prepareObject( object: TObject, timestamp: number, ): TObject { // the class that instansiates this object - const BoundingObject = object.constructor as typeof fedify.Object; + const BoundingObject = object.constructor as typeof vocab.Object; const objectId = hash( "sha256", diff --git a/backend/src/apub/utils.stub.ts b/backend/src/apub/utils.stub.ts index 86ad015..c30e0d3 100644 --- a/backend/src/apub/utils.stub.ts +++ b/backend/src/apub/utils.stub.ts @@ -3,23 +3,13 @@ // to avoid having to setup full TLS-termination reverse proxy, this will // supply the responses to authenticate as any user -import { - Actor, - ChatMessage, - ConstructorWithTypeId, - Context, - Note, - Object, - Person, - ResourceDescriptor, -} from "@fedify/fedify"; +import { Actor, Person } from "@fedify/vocab"; +import { ResourceDescriptor } from "@fedify/webfinger"; import { IProfile } from "../lib/instance/userMeta.js"; import { USER_IDENTIFIER } from "./federation.js"; -import { APubLive } from "./utils.live.js"; -import { AuthSession } from "../models/AuthSession.js"; import { _staticType } from "../lib/utils.js"; import { IAPubUtils, IAPubUtils_Static, IMessageBuilder } from "./utils.js"; -import * as fedify from "@fedify/fedify"; +import * as vocab from "@fedify/vocab"; /** * @internal -- See apub/utils.ts @@ -76,7 +66,7 @@ export class APubStub implements IAPubUtils { ]); } - static reply(replyTo: T, reply: T) { + static reply(replyTo: T, reply: T) { return Promise.resolve(new URL("http://localhost/#reply")); } diff --git a/backend/src/apub/utils.ts b/backend/src/apub/utils.ts index 2ede58f..aaac619 100644 --- a/backend/src/apub/utils.ts +++ b/backend/src/apub/utils.ts @@ -1,17 +1,10 @@ -import { - Actor, - ChatMessage, - Context, - LookupObjectOptions, - Note, - ResourceDescriptor, -} from "@fedify/fedify"; -import * as fedify from "@fedify/fedify"; +import { ConstructorWithTypeId, Context } from "@fedify/fedify"; +import { Actor, LookupObjectOptions, Object } from "@fedify/vocab"; +import { ResourceDescriptor } from "@fedify/webfinger"; import { Flags } from "../lib/flags.js"; import { APubLive } from "./utils.live.js"; import { APubStub } from "./utils.stub.js"; import { IProfile } from "../lib/instance/userMeta.js"; -import { AuthSession } from "../models/AuthSession.js"; export const APub: (new (...args: any) => IAPubUtils) & IAPubUtils_Static = Flags.Dev.UseAPubStub ? APubStub : APubLive; @@ -71,7 +64,7 @@ export interface IAPubUtils_Static { * * @param reply the object to reply with (augmented with id, attribution, replyTarget, to) */ - reply(replyTo: T, reply: T): Promise; + reply(replyTo: T, reply: T): Promise; /** * Delete one or multiple messages @@ -90,7 +83,7 @@ export type BuildObjectOpts = { target: Actor; }; -export interface IMessageBuilder { +export interface IMessageBuilder { /** * Build message as specified object * @@ -103,7 +96,7 @@ export interface IMessageBuilder { * @throws */ build( - cls: fedify.ConstructorWithTypeId, + cls: ConstructorWithTypeId, ): Promise; /** @@ -111,7 +104,7 @@ export interface IMessageBuilder { * * Objects will be buit with {#build}, then when sent, this method will be called to store the metadata (for deletes) */ - markSent(object: fedify.Object): Promise; + markSent(object: Object): Promise; /** * Get all sent object URIs diff --git a/backend/src/handoff/activitypub.ts b/backend/src/handoff/activitypub.ts index 8b4b7da..663f49c 100644 --- a/backend/src/handoff/activitypub.ts +++ b/backend/src/handoff/activitypub.ts @@ -1,8 +1,6 @@ -import { Actor, ChatMessage, Create, Mention, Note } from "@fedify/fedify"; +import { Actor, ChatMessage, Create, Mention, Note } from "@fedify/vocab"; import { HandoffSession } from "../models/HandoffSession.js"; import { APub } from "../apub/utils.js"; -import { USER_IDENTIFIER } from "../apub/federation.js"; -import { Temporal } from "@js-temporal/polyfill"; import { stripHtml } from "string-strip-html"; import { Handoff } from "./index.js"; diff --git a/backend/src/handoff/sidecar.ts b/backend/src/handoff/sidecar.ts index a084470..80988af 100644 --- a/backend/src/handoff/sidecar.ts +++ b/backend/src/handoff/sidecar.ts @@ -1,4 +1,4 @@ -import { Actor, ChatMessage, Note } from "@fedify/fedify"; +import { Actor, ChatMessage, Note } from "@fedify/vocab"; import { SidecarApps } from "./sidecar.apps.js"; import { SidecarSession, SidecarSessionID } from "../models/SidecarSession.js"; import { APub } from "../apub/utils.js"; diff --git a/backend/src/models/AuthSession.ts b/backend/src/models/AuthSession.ts index a863fe1..ca73b70 100644 --- a/backend/src/models/AuthSession.ts +++ b/backend/src/models/AuthSession.ts @@ -1,12 +1,13 @@ import { AuthSession as DBAuthSession } from "@prisma/client"; import { prisma } from "../lib/prisma.js"; import { APub, IMessageBuilder } from "../apub/utils.js"; -import * as fedify from "@fedify/fedify"; +import * as vocab from "@fedify/vocab"; +import { ConstructorWithTypeId } from "@fedify/fedify"; import { _staticType, tryURL } from "../lib/utils.js"; import { redis } from "../lib/redis.js"; export class AuthSession implements IMessageBuilder< - fedify.ChatMessage | fedify.Note + vocab.ChatMessage | vocab.Note > { static generateCode(): string { return "." @@ -122,8 +123,8 @@ export class AuthSession implements IMessageBuilder< return this._code; } - async build( - cls: fedify.ConstructorWithTypeId, + async build( + cls: ConstructorWithTypeId, ): Promise { const to = await APub.lookupActor(this.user_sub); @@ -144,19 +145,19 @@ Do not share this code. This code is used to identify you.`; switch (String(cls.typeId) ?? String(cls.name)) { case "ChatMessage": case "http://litepub.social/ns#ChatMessage": - return new fedify.ChatMessage({ + return new vocab.ChatMessage({ to, published: this.createdAt.toTemporalInstant(), content, }) as any; case "Note": case "https://www.w3.org/ns/activitystreams#Note": - return new fedify.Note({ + return new vocab.Note({ to, published: this.createdAt.toTemporalInstant(), content, tags: [ - new fedify.Mention({ + new vocab.Mention({ href: to.id!, name: String(to.id!), }), @@ -171,7 +172,7 @@ Do not share this code. This code is used to identify you.`; return `auth-session-${this._id}`; } - async markSent(object: fedify.Object) { + async markSent(object: vocab.Object) { await redis.lpush(this.REDIS_KEY, String(object.id!)); } diff --git a/backend/src/models/SentAP.redis.ts b/backend/src/models/SentAP.redis.ts index 9d174d5..9de05f9 100644 --- a/backend/src/models/SentAP.redis.ts +++ b/backend/src/models/SentAP.redis.ts @@ -1,4 +1,4 @@ -import * as fedify from "@fedify/fedify"; +import * as vocab from "@fedify/vocab"; import { APub } from "../apub/utils.js"; import { redis } from "../lib/redis.js"; @@ -13,7 +13,7 @@ export class SentAP { return this.instance ?? (this.instance = new this()); } - static async store(obj: fedify.Object) { + static async store(obj: vocab.Object) { if (!obj.id) throw new Error("Attempted to store an object w/o an id"); const squashed = JSON.stringify(await obj.toJsonLd({ format: "compact" })); @@ -34,13 +34,13 @@ export class SentAP { const rawData = JSON.parse(data); - return await fedify.Object.fromJsonLd(rawData, APub.options(null, {})); + return await vocab.Object.fromJsonLd(rawData, APub.options(null, {})); } - static async delete(objOrId: string | URL | fedify.Object) { + static async delete(objOrId: string | URL | vocab.Object) { let key = `${this.PREFIX}`; - if (objOrId instanceof fedify.Object) { + if (objOrId instanceof vocab.Object) { if (!objOrId.id) throw new Error("Given object with no id"); key += String(objOrId.id); diff --git a/backend/src/models/TransientNote.ts b/backend/src/models/TransientNote.ts index 75073cd..3e32a28 100644 --- a/backend/src/models/TransientNote.ts +++ b/backend/src/models/TransientNote.ts @@ -1,35 +1,36 @@ +import { ConstructorWithTypeId } from "@fedify/fedify"; +import * as vocab from "@fedify/vocab"; import { IMessageBuilder } from "../apub/utils.js"; -import * as fedify from "@fedify/fedify"; export class TransientNote implements IMessageBuilder< - fedify.ChatMessage | fedify.Note + vocab.ChatMessage | vocab.Note > { constructor( - private toActor: fedify.Actor, + private toActor: vocab.Actor, private message: string, ) {} - build( - cls: fedify.ConstructorWithTypeId, + build( + cls: ConstructorWithTypeId, ): Promise { const published = new Date().toTemporalInstant(); switch (String(cls.typeId) ?? String(cls.name)) { case "ChatMessage": case "http://litepub.social/ns#ChatMessage": - return new fedify.ChatMessage({ + return new vocab.ChatMessage({ to: this.toActor, published, content: this.message, }) as any; case "Note": case "https://www.w3.org/ns/activitystreams#Note": - return new fedify.Note({ + return new vocab.Note({ to: this.toActor, published, content: this.message, tags: [ - new fedify.Mention({ + new vocab.Mention({ href: this.toActor.id!, name: String(this.toActor.id!), }), @@ -40,7 +41,7 @@ export class TransientNote implements IMessageBuilder< throw new Error(`Unhandled type ${cls.typeId ?? cls.name}`); } - async markSent(object: fedify.Object) {} + async markSent(object: vocab.Object) {} async getSent() { return []; diff --git a/backend/src/types/env.d.ts b/backend/src/types/env.d.ts index 9e9f800..b964053 100644 --- a/backend/src/types/env.d.ts +++ b/backend/src/types/env.d.ts @@ -1,4 +1,4 @@ -import * as fedify from "@fedify/fedify"; +import * as vocab from "@fedify/vocab"; declare global { namespace NodeJS { @@ -50,7 +50,7 @@ declare global { * Test hook to intercept create activites */ var TEST_FEDERATION_INCOMING_CREATE: - | ((actor: fedify.Actor, object: fedify.Object) => unknown) + | ((actor: vocab.Actor, object: vocab.Object) => unknown) | undefined; } diff --git a/doc/dev/patches/fedify.md b/doc/dev/patches/fedify.md deleted file mode 100644 index 6522984..0000000 --- a/doc/dev/patches/fedify.md +++ /dev/null @@ -1,3 +0,0 @@ -@fedify/fedify was patched to remove `w3id.org/identity/v1` context from being sent as it is now a broken redirect, which will cause Piefed to 500 as it fails to load the context - -See also: https://socialhub.activitypub.rocks/t/what-are-projects-doing-about-ld-signatures-since-https-w3id-org-security-v1-went-away/3005/5 diff --git a/yarn.lock b/yarn.lock index 97781c9..82f37bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -711,81 +711,117 @@ __metadata: languageName: node linkType: hard -"@fedify/express@npm:^0.2.1": - version: 0.2.1 - resolution: "@fedify/express@npm:0.2.1" +"@fedify/express@npm:^2.3.1": + version: 2.3.1 + resolution: "@fedify/express@npm:2.3.1" peerDependencies: - "@fedify/fedify": ">=0.12.0 <2" - checksum: 10c0/d0854dc940646ff42cfd815210ddf7ea0853a4bd68c2e4c599699d4ba7c74e13a72e013c4c2212015f78711f47a49f1afd27619f9c901a3e7f45ba7b314f6e5d + "@fedify/fedify": ^2.3.1 + express: ">=4.0.0" + checksum: 10c0/d7664a600fed360f445459a018938bb86fac61c354b47409df2ae52caf7620848ec8b57cd79ab03b14c34a406709db3738e9a2342512a95226ecf923844ad885 languageName: node linkType: hard -"@fedify/fedify@npm:1.10.0": - version: 1.10.0 - resolution: "@fedify/fedify@npm:1.10.0" +"@fedify/fedify@npm:^2.3.1": + version: 2.3.1 + resolution: "@fedify/fedify@npm:2.3.1" dependencies: - "@cfworker/json-schema": "npm:^4.1.1" + "@fedify/uri-template": "npm:2.3.1" + "@fedify/vocab": "npm:2.3.1" + "@fedify/vocab-runtime": "npm:2.3.1" + "@fedify/webfinger": "npm:2.3.1" "@js-temporal/polyfill": "npm:^0.5.1" - "@logtape/logtape": "npm:^1.2.2" - "@multiformats/base-x": "npm:^4.0.1" - "@opentelemetry/api": "npm:^1.9.0" - "@opentelemetry/core": "npm:^1.30.1" - "@opentelemetry/sdk-trace-base": "npm:^1.30.1" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@phensley/language-tag": "npm:^1.9.0" - asn1js: "npm:^3.0.5" + "@logtape/logtape": "npm:^2.2.0" + "@opentelemetry/api": "npm:^1.9.1" + "@opentelemetry/core": "npm:^2.7.1" + "@opentelemetry/sdk-metrics": "npm:2.7.1" + "@opentelemetry/sdk-trace-base": "npm:^2.7.1" + "@opentelemetry/semantic-conventions": "npm:^1.40.0" byte-encodings: "npm:^1.0.11" - es-toolkit: "npm:^1.39.5" + es-toolkit: "npm:1.46.1" json-canon: "npm:^1.0.1" jsonld: "npm:^9.0.0" - multicodec: "npm:^3.2.1" - pkijs: "npm:^3.2.4" structured-field-values: "npm:^2.0.4" - uri-template-router: "npm:^1.0.0" - url-template: "npm:^3.1.1" urlpattern-polyfill: "npm:^10.1.0" - checksum: 10c0/905bd151381ff044cf64b215662a776982be402b977c98cb174bf3b612411ae2358e303fcdeed590c4bd65682121389f9585eb8966193d825f7245561b305597 + checksum: 10c0/65ee3e6d3c7b5f295a6fdf9eaf0ffb388e25b146e3a7f97c4be5342f05bea55ed34b1010ba77114e20d58b393fdb3e02883dfd49d78ba244139b8a57b6f171a2 languageName: node linkType: hard -"@fedify/fedify@patch:@fedify/fedify@npm%3A1.10.0#~/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch": - version: 1.10.0 - resolution: "@fedify/fedify@patch:@fedify/fedify@npm%3A1.10.0#~/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch::version=1.10.0&hash=858005" +"@fedify/redis@npm:^2.3.1": + version: 2.3.1 + resolution: "@fedify/redis@npm:2.3.1" dependencies: - "@cfworker/json-schema": "npm:^4.1.1" "@js-temporal/polyfill": "npm:^0.5.1" - "@logtape/logtape": "npm:^1.2.2" + "@logtape/logtape": "npm:^2.2.0" + peerDependencies: + "@fedify/fedify": ^2.3.1 + ioredis: ^5.8.2 + checksum: 10c0/84ace42b4a60ee5107f572bcb3c7ac04e4b053e15726a0e57a8245d35ba1b2438802e5b061b1d5f5639cfed914369bfcfcf4ea024502aaa0341a0ddf02eebf85 + languageName: node + linkType: hard + +"@fedify/uri-template@npm:2.3.1": + version: 2.3.1 + resolution: "@fedify/uri-template@npm:2.3.1" + checksum: 10c0/0dc8f452eec3463f4a4b4de94226d87b944f3256cbb62237a47057163fa5ec813ddaa29637a4f07c1eb874042d342996b8b12828cb43ac7e73e38eb4c5c74269 + languageName: node + linkType: hard + +"@fedify/vocab-runtime@npm:2.3.1": + version: 2.3.1 + resolution: "@fedify/vocab-runtime@npm:2.3.1" + dependencies: + "@js-temporal/polyfill": "npm:^0.5.1" + "@logtape/logtape": "npm:^2.2.0" "@multiformats/base-x": "npm:^4.0.1" - "@opentelemetry/api": "npm:^1.9.0" - "@opentelemetry/core": "npm:^1.30.1" - "@opentelemetry/sdk-trace-base": "npm:^1.30.1" - "@opentelemetry/semantic-conventions": "npm:^1.27.0" - "@phensley/language-tag": "npm:^1.9.0" - asn1js: "npm:^3.0.5" + "@opentelemetry/api": "npm:^1.9.1" + asn1js: "npm:^3.0.10" byte-encodings: "npm:^1.0.11" - es-toolkit: "npm:^1.39.5" - json-canon: "npm:^1.0.1" jsonld: "npm:^9.0.0" - multicodec: "npm:^3.2.1" - pkijs: "npm:^3.2.4" - structured-field-values: "npm:^2.0.4" - uri-template-router: "npm:^1.0.0" - url-template: "npm:^3.1.1" - urlpattern-polyfill: "npm:^10.1.0" - checksum: 10c0/abef7d33a31ae98e40cba912a0ba2cfc5a45372f8667c08898cec9e40356119453372238455e171c662f52a41fd9f584595e4e60a147212cd42125c7e1af6a1d + pkijs: "npm:^3.3.3" + checksum: 10c0/571f693b2559076ddc3e1f1267cbfc5494769496fd19714d2515784c1cbd254c866710aa31110a7936442b2961ffed3408fa8199927f19628885e025655ebe5c + languageName: node + linkType: hard + +"@fedify/vocab-tools@npm:2.3.1": + version: 2.3.1 + resolution: "@fedify/vocab-tools@npm:2.3.1" + dependencies: + "@cfworker/json-schema": "npm:^4.1.1" + byte-encodings: "npm:^1.0.11" + es-toolkit: "npm:^1.46.1" + yaml: "npm:^2.9.0" + checksum: 10c0/8b1ac17dfccaa9f4633f129e91ddef858d0302508aa5df33f5b2771ec2cdb1469afc0913a887511e9f3989ee9b9c8b985edc884eb78fe9bc457412e4e08aa428 languageName: node linkType: hard -"@fedify/redis@npm:^1.10.10": - version: 1.10.10 - resolution: "@fedify/redis@npm:1.10.10" +"@fedify/vocab@npm:2.3.1, @fedify/vocab@npm:^2.3.1": + version: 2.3.1 + resolution: "@fedify/vocab@npm:2.3.1" dependencies: + "@fedify/vocab-runtime": "npm:2.3.1" + "@fedify/vocab-tools": "npm:2.3.1" + "@fedify/webfinger": "npm:2.3.1" "@js-temporal/polyfill": "npm:^0.5.1" - "@logtape/logtape": "npm:^1.2.2" - peerDependencies: - "@fedify/fedify": ^1.10.10 - ioredis: ^5.6.1 - checksum: 10c0/7bc5daf8f24f5e52d90bddb1721def9d1f59aa3a7ced264d93d19e1a974b89adf187f1010f638824a51fd9f478be2cc07c8b5ac31b2a67b356c5403a8401a8ba + "@logtape/logtape": "npm:^2.2.0" + "@multiformats/base-x": "npm:^4.0.1" + "@opentelemetry/api": "npm:^1.9.1" + asn1js: "npm:^3.0.10" + es-toolkit: "npm:1.46.1" + jsonld: "npm:^9.0.0" + pkijs: "npm:^3.3.3" + checksum: 10c0/592df71023521b000a88f47f72b794bbbcc5eb048eba2be4f68d77e6f483763133db47a3a23a042b33c8c90c4cef99320583ee276fb7d922ac8ea7219b2a9684 + languageName: node + linkType: hard + +"@fedify/webfinger@npm:2.3.1, @fedify/webfinger@npm:^2.3.1": + version: 2.3.1 + resolution: "@fedify/webfinger@npm:2.3.1" + dependencies: + "@fedify/vocab-runtime": "npm:2.3.1" + "@logtape/logtape": "npm:^2.2.0" + "@opentelemetry/api": "npm:^1.9.1" + es-toolkit: "npm:1.46.1" + checksum: 10c0/ae2036e16d0ff497c6576a6b58a3077879b3df8831d0a353ac5c7c2bad56258183d689b11b4a0046abd71f23ea75cf62ffad903d2e2f9627b4d6624471f5c056 languageName: node linkType: hard @@ -793,9 +829,11 @@ __metadata: version: 0.0.0-use.local resolution: "@fediverse-auth/backend@workspace:backend" dependencies: - "@fedify/express": "npm:^0.2.1" - "@fedify/fedify": "patch:@fedify/fedify@npm%3A1.10.0#~/.yarn/patches/@fedify-fedify-npm-1.10.0-eb96e7364a.patch" - "@fedify/redis": "npm:^1.10.10" + "@fedify/express": "npm:^2.3.1" + "@fedify/fedify": "npm:^2.3.1" + "@fedify/redis": "npm:^2.3.1" + "@fedify/vocab": "npm:^2.3.1" + "@fedify/webfinger": "npm:^2.3.1" "@hongminhee/localtunnel": "npm:^0.3.0" "@js-temporal/polyfill": "npm:^0.5.1" "@logtape/logtape": "npm:^0.9.2" @@ -1038,13 +1076,20 @@ __metadata: languageName: node linkType: hard -"@logtape/logtape@npm:^1.0.4, @logtape/logtape@npm:^1.2.2": +"@logtape/logtape@npm:^1.0.4": version: 1.3.5 resolution: "@logtape/logtape@npm:1.3.5" checksum: 10c0/49c3aa93236685ed907db6134220026e5c7253169eb4fa0b32edc680d16b34ba8e59c1ae96a1ec931633d7cd085dab5fa1635b7a45ef12ef690d7c9bf63794db languageName: node linkType: hard +"@logtape/logtape@npm:^2.2.0": + version: 2.2.1 + resolution: "@logtape/logtape@npm:2.2.1" + checksum: 10c0/8348d871c93f40c3587c85de91c8404661f819d1c670d5ecab5174bb805b0a531f0864bea877eeb29a7edaeaf089a330c6cc9ff8e49ead86361347db1a32fc58 + languageName: node + linkType: hard + "@mui/base@npm:5.0.0-beta.40-1": version: 5.0.0-beta.40-1 resolution: "@mui/base@npm:5.0.0-beta.40-1" @@ -1326,60 +1371,88 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api@npm:^1.9.0": - version: 1.9.0 - resolution: "@opentelemetry/api@npm:1.9.0" - checksum: 10c0/9aae2fe6e8a3a3eeb6c1fdef78e1939cf05a0f37f8a4fae4d6bf2e09eb1e06f966ece85805626e01ba5fab48072b94f19b835449e58b6d26720ee19a58298add +"@opentelemetry/api@npm:^1.9.1": + version: 1.9.1 + resolution: "@opentelemetry/api@npm:1.9.1" + checksum: 10c0/c608485fc8b5a91e1f7e05e843b45b509307456b31cd2ad365933d90813e40ebfedf179f1451c762037e82d7c76aa8500e95d2da3609f640a1206cde5322cd14 languageName: node linkType: hard -"@opentelemetry/core@npm:1.30.1, @opentelemetry/core@npm:^1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/core@npm:1.30.1" +"@opentelemetry/core@npm:2.7.1": + version: 2.7.1 + resolution: "@opentelemetry/core@npm:2.7.1" dependencies: - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10c0/4c25ba50a6137c2ba9ca563fb269378f3c9ca6fd1b3f15dbb6eff78eebf5656f281997cbb7be8e51c01649fd6ad091083fcd8a42dd9b5dfac907dc06d7cfa092 + checksum: 10c0/a8ce7bb08f51cfce094b98febc63101ccbc00dddf845be600b059cd7877c48d88b111f46a4df94c9cfcc42f595200722caf230cdba080cdc8ab304cf664d00e5 languageName: node linkType: hard -"@opentelemetry/resources@npm:1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/resources@npm:1.30.1" +"@opentelemetry/core@npm:2.8.0, @opentelemetry/core@npm:^2.7.1": + version: 2.8.0 + resolution: "@opentelemetry/core@npm:2.8.0" dependencies: - "@opentelemetry/core": "npm:1.30.1" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10c0/688e73258283c80662bfa9a858aaf73bf3b832a18d96e546d0dddfa6dcec556cdfa087a1d0df643435293406009e4122d7fb7eeea69aa87b539d3bab756fba74 + checksum: 10c0/35b8a464b359a0699fcbcea8c11a883f0f634ee7638719b89fa0c0cbbaaa38c57db22e9ac19ffb15ce18014751dc7db11a26d7fb6ad6259f89a26bdc4d167e4b languageName: node linkType: hard -"@opentelemetry/sdk-trace-base@npm:^1.30.1": - version: 1.30.1 - resolution: "@opentelemetry/sdk-trace-base@npm:1.30.1" +"@opentelemetry/resources@npm:2.7.1": + version: 2.7.1 + resolution: "@opentelemetry/resources@npm:2.7.1" dependencies: - "@opentelemetry/core": "npm:1.30.1" - "@opentelemetry/resources": "npm:1.30.1" - "@opentelemetry/semantic-conventions": "npm:1.28.0" + "@opentelemetry/core": "npm:2.7.1" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" peerDependencies: - "@opentelemetry/api": ">=1.0.0 <1.10.0" - checksum: 10c0/77019dc3efaeceb41b4c54dd83b92f0ccd81ecceca544cbbe8e0aee4b2c8727724bdb9dcecfe00622c16d60946ae4beb69a5c0e7d85c4bc7ef425bd84f8b970c + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10c0/f752c432ff9aaaec818dc5b5dc69bb22881bf20e6f361c917fce3715d7839274aacf94d2fe06e765cabc5e08193f65bfc438917c19ddf17f21b30252d9ad81ae + languageName: node + linkType: hard + +"@opentelemetry/resources@npm:2.8.0": + version: 2.8.0 + resolution: "@opentelemetry/resources@npm:2.8.0" + dependencies: + "@opentelemetry/core": "npm:2.8.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" + peerDependencies: + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10c0/60948bf1a69b9f3f5173cb4db7f317bd24399379a899254519af3f00d22b1da1caf27eb3d893c6118de8984e6d22484750cf924b52dc499bd6e9b8aac9089ef6 + languageName: node + linkType: hard + +"@opentelemetry/sdk-metrics@npm:2.7.1": + version: 2.7.1 + resolution: "@opentelemetry/sdk-metrics@npm:2.7.1" + dependencies: + "@opentelemetry/core": "npm:2.7.1" + "@opentelemetry/resources": "npm:2.7.1" + peerDependencies: + "@opentelemetry/api": ">=1.9.0 <1.10.0" + checksum: 10c0/31e21e5b4357cb33a29ab180e0e1ad0bd7516ebeca4712285809c1b89f3069b94d7dbdd6b1877ac813c172eca1a1c87727f9c4bcbf1c4580b3dffb3559f671c2 languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:1.28.0": - version: 1.28.0 - resolution: "@opentelemetry/semantic-conventions@npm:1.28.0" - checksum: 10c0/deb8a0f744198071e70fea27143cf7c9f7ecb7e4d7b619488c917834ea09b31543c1c2bcea4ec5f3cf68797f0ef3549609c14e859013d9376400ac1499c2b9cb +"@opentelemetry/sdk-trace-base@npm:^2.7.1": + version: 2.8.0 + resolution: "@opentelemetry/sdk-trace-base@npm:2.8.0" + dependencies: + "@opentelemetry/core": "npm:2.8.0" + "@opentelemetry/resources": "npm:2.8.0" + "@opentelemetry/semantic-conventions": "npm:^1.29.0" + peerDependencies: + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 10c0/ab7cf46ecd29d52ed76a82f98b3b3f95c733cfd8162683d8eaa47d53ca5e93d9b21a8c57a3dc679d13c6b968b2cfff16b74d413af7370188160bcc3f8ceb78a0 languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:^1.27.0": - version: 1.38.0 - resolution: "@opentelemetry/semantic-conventions@npm:1.38.0" - checksum: 10c0/ae93e39ac18bf47df2b11d43e9a0dc1673b9d33e5f1e7f357c92968e6329fb9a67cf8a447e9a7150948ee3f8178b38274db365b8fa775a8c54802e0c6ccdd2ca +"@opentelemetry/semantic-conventions@npm:^1.29.0, @opentelemetry/semantic-conventions@npm:^1.40.0": + version: 1.41.1 + resolution: "@opentelemetry/semantic-conventions@npm:1.41.1" + checksum: 10c0/c54b1edf845766e93026d30fd95e15da9dba8d7a5b58f8c320c5d36ab542c77b37868f3e8e3d78ec162da8ee2afd24781f0a65934c9bdbc1aea86b47b12f074c languageName: node linkType: hard @@ -1390,15 +1463,6 @@ __metadata: languageName: node linkType: hard -"@phensley/language-tag@npm:^1.9.0": - version: 1.14.0 - resolution: "@phensley/language-tag@npm:1.14.0" - dependencies: - tslib: "npm:^2.8.1" - checksum: 10c0/006b23e628699e58746da4e50425daaa0d72f9988e79ca178170c08429773a3bb983b215b78ffc09c8644b11c9c8f39cbcf394c7233d62149e424d9cbee047b3 - languageName: node - linkType: hard - "@popperjs/core@npm:^2.11.8": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" @@ -2625,7 +2689,18 @@ __metadata: languageName: node linkType: hard -"asn1js@npm:^3.0.5, asn1js@npm:^3.0.6": +"asn1js@npm:^3.0.10": + version: 3.0.10 + resolution: "asn1js@npm:3.0.10" + dependencies: + pvtsutils: "npm:^1.3.6" + pvutils: "npm:^1.1.5" + tslib: "npm:^2.8.1" + checksum: 10c0/04056106522e4d0db4eb992299bb76d73438bfd59ffd975ac9c1f15d14e7326161dad383c54a5ccfa203b73ae7b7bf4668f42c2fed01e1f4bf79a58de71e4dc6 + languageName: node + linkType: hard + +"asn1js@npm:^3.0.6": version: 3.0.7 resolution: "asn1js@npm:3.0.7" dependencies: @@ -3431,15 +3506,29 @@ __metadata: languageName: node linkType: hard -"es-toolkit@npm:^1.39.5": - version: 1.43.0 - resolution: "es-toolkit@npm:1.43.0" +"es-toolkit@npm:1.46.1": + version: 1.46.1 + resolution: "es-toolkit@npm:1.46.1" dependenciesMeta: "@trivago/prettier-plugin-sort-imports@4.3.0": unplugged: true prettier-plugin-sort-re-exports@0.0.1: unplugged: true - checksum: 10c0/bbff0b591fd01be9f37a34dad7964b590e4952fc594c1230140771687f05136caa6ab21962a6e9cde7c4b529a149171ed5179d6379d4a8e656dbf7e8d126999c + checksum: 10c0/6a4c3dd0ddc2138fa13d983d93ebaf8061759c52c2cf7c3101315139fc1fca826d253daa67fe85ad880c03cc4c092bd53a83a7cbf58b4721c251479122ba5303 + languageName: node + linkType: hard + +"es-toolkit@npm:^1.46.1": + version: 1.49.0 + resolution: "es-toolkit@npm:1.49.0" + dependenciesMeta: + "@trivago/prettier-plugin-sort-imports@4.3.0": + unplugged: true + prettier-plugin-sort-re-exports@0.0.1: + unplugged: true + vitepress-plugin-sandpack@1.1.4: + unplugged: true + checksum: 10c0/ab0864bb0c5c494ed09043d53a74b58a0ab9df1b89b9b54bce72a63de2869152d7d65e489dc89ab671f0fea243728922c8a8f8c873f1b2a53350a23360b3e2df languageName: node linkType: hard @@ -5256,23 +5345,6 @@ __metadata: languageName: node linkType: hard -"multicodec@npm:^3.2.1": - version: 3.2.1 - resolution: "multicodec@npm:3.2.1" - dependencies: - uint8arrays: "npm:^3.0.0" - varint: "npm:^6.0.0" - checksum: 10c0/3ab585bfebc472057b6cdd50c4bdf3c2eae1d92bdb63b865eeb3963908c15f038b5778cd2a7db6530f56f47efec10aa075200cf7251c29f517d7a82ee8303c6a - languageName: node - linkType: hard - -"multiformats@npm:^9.4.2": - version: 9.9.0 - resolution: "multiformats@npm:9.9.0" - checksum: 10c0/1fdb34fd2fb085142665e8bd402570659b50a5fae5994027e1df3add9e1ce1283ed1e0c2584a5c63ac0a58e871b8ee9665c4a99ca36ce71032617449d48aa975 - languageName: node - linkType: hard - "nanoid@npm:^3.3.11": version: 3.3.11 resolution: "nanoid@npm:3.3.11" @@ -5672,9 +5744,9 @@ __metadata: languageName: node linkType: hard -"pkijs@npm:^3.2.4": - version: 3.3.3 - resolution: "pkijs@npm:3.3.3" +"pkijs@npm:^3.3.3": + version: 3.4.0 + resolution: "pkijs@npm:3.4.0" dependencies: "@noble/hashes": "npm:1.4.0" asn1js: "npm:^3.0.6" @@ -5682,7 +5754,7 @@ __metadata: pvtsutils: "npm:^1.3.6" pvutils: "npm:^1.1.3" tslib: "npm:^2.8.1" - checksum: 10c0/7b60f3398c35538ce05b613b5ff86c0df6b7e236e2ba6063fec2f89a80eb214d45c175e19cf13e20bed0c474000f1d3653a5234efc42e9528d1912d2edae5914 + checksum: 10c0/33cfab9283702782ae228bd2d4a51b1e9b2e0d6e2141207f29ee95716101ac4fe6e6821882da5f5eca28c74be3964b181b09e95cbbb757b2bd9dca918a5765fd languageName: node linkType: hard @@ -5855,7 +5927,7 @@ __metadata: languageName: node linkType: hard -"pvutils@npm:^1.1.3": +"pvutils@npm:^1.1.3, pvutils@npm:^1.1.5": version: 1.1.5 resolution: "pvutils@npm:1.1.5" checksum: 10c0/e968b07b78a58fec9377fe7aa6342c8cfa21c8fb4afc4e51e1489bd42bec6dc71b8a52541d0aede0aea17adec7ca3f89f29f56efdc31d0083cc02e9bb5721bcf @@ -6926,15 +6998,6 @@ __metadata: languageName: node linkType: hard -"uint8arrays@npm:^3.0.0": - version: 3.1.1 - resolution: "uint8arrays@npm:3.1.1" - dependencies: - multiformats: "npm:^9.4.2" - checksum: 10c0/9946668e04f29b46bbb73cca3d190f63a2fbfe5452f8e6551ef4257d9d597b72da48fa895c15ef2ef772808a5335b3305f69da5f13a09f8c2924896b409565ff - languageName: node - linkType: hard - "undici-types@npm:~6.21.0": version: 6.21.0 resolution: "undici-types@npm:6.21.0" @@ -6990,20 +7053,6 @@ __metadata: languageName: node linkType: hard -"uri-template-router@npm:^1.0.0": - version: 1.0.0 - resolution: "uri-template-router@npm:1.0.0" - checksum: 10c0/66a9d9987920f66d886313e3355c6ba9d1c02355240f9936d7f4aef3b6bb38b80b837cb41ad43cb2f4d1337e697f9a8c3025f9b3aec00fe87a18eff43875e0c4 - languageName: node - linkType: hard - -"url-template@npm:^3.1.1": - version: 3.1.1 - resolution: "url-template@npm:3.1.1" - checksum: 10c0/0947f4978665ced04bb0fe456f8a60ca4e1db283ce36da15193ee52c4a5461633dc9b5116ef8cf34bae4a31285ac6e7079f309badf211fe8bd1428d6ac56d28a - languageName: node - linkType: hard - "urlpattern-polyfill@npm:^10.1.0": version: 10.1.0 resolution: "urlpattern-polyfill@npm:10.1.0" @@ -7018,13 +7067,6 @@ __metadata: languageName: node linkType: hard -"varint@npm:^6.0.0": - version: 6.0.0 - resolution: "varint@npm:6.0.0" - checksum: 10c0/737fc37088a62ed3bd21466e318d21ca7ac4991d0f25546f518f017703be4ed0f9df1c5559f1dd533dddba4435a1b758fd9230e4772c1a930ef72b42f5c750fd - languageName: node - linkType: hard - "vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" @@ -7321,6 +7363,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.9.0": + version: 2.9.0 + resolution: "yaml@npm:2.9.0" + bin: + yaml: bin.mjs + checksum: 10c0/f340718df45e97a9551b9bf9dac61c80050bc464513b710debfb5067c380c8472e3b67809cffacb4ab5ffb5e66ef9310816c88b05f371cec60abfedd8c88e0a2 + languageName: node + linkType: hard + "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" -- GitLab From 274043dd18e190cc7972aedf47bf8814c00bca6d Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Jun 2026 17:55:54 -0600 Subject: [PATCH 2/7] testkit: implement base testkit rewrite Assisted-by: deepseek:v4-flash --- backend/package.json | 5 +- backend/src/__tests__/federation.test.ts | 597 ++++++------------ backend/src/__tests__/helpers/actor-server.ts | 113 ++++ backend/src/__tests__/helpers/config.ts | 146 +++++ backend/src/apub/utils.ts | 2 + yarn.lock | 153 ++++- 6 files changed, 622 insertions(+), 394 deletions(-) create mode 100644 backend/src/__tests__/helpers/actor-server.ts create mode 100644 backend/src/__tests__/helpers/config.ts diff --git a/backend/package.json b/backend/package.json index 15ecc0b..57dcc51 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,7 +14,7 @@ "@js-temporal/polyfill": "^0.5.1", "@logtape/logtape": "^0.9.2", "@prisma/client": "^5.22.0", - "@sc07/fedi-testkit": "^1.1.5", + "@sc07/fedi-testkit": "file:../../fedi-testkit", "@tsconfig/recommended": "^1.0.13", "body-parser": "^1.20.5", "cookie-parser": "^1.4.7", @@ -49,6 +49,7 @@ "test:types": "tsc --noEmit", "start": "node dist/index.js", "test": "vitest", - "ci:test": "vitest --reporter=default --reporter=junit --outputFile=./vitest.xml" + "ci:test": "vitest --reporter=default --reporter=junit --outputFile=./vitest.xml", + "ci:test:federation": "vitest run src/__tests__/federation.test.ts --reporter=default --reporter=junit --outputFile=./vitest.xml" } } diff --git a/backend/src/__tests__/federation.test.ts b/backend/src/__tests__/federation.test.ts index d397552..1e7c8c9 100644 --- a/backend/src/__tests__/federation.test.ts +++ b/backend/src/__tests__/federation.test.ts @@ -1,412 +1,235 @@ import { afterAll, beforeAll, describe, expect, test } from "vitest"; -import { type Express as TExpress } from "express"; -import { - FediTestKit, - type Software as FTK_Software, - SOFTWARES, -} from "@sc07/fedi-testkit"; -import { openTunnel, Tunnel } from "@hongminhee/localtunnel"; -import { Server } from "node:http"; -import type { IAPubUtils, IAPubUtils_Static } from "../apub/utils.js"; +import { FediTestKit } from "@sc07/fedi-testkit"; import type { AuthSession } from "../models/AuthSession.js"; -import type { Federation } from "@fedify/fedify"; import { randomUUID } from "node:crypto"; -import { configure, getConsoleSink } from "@logtape/logtape"; import { toTemporalInstant } from "@js-temporal/polyfill"; +import { startActorServer } from "./helpers/actor-server.js"; +import { getTestConfig } from "./helpers/config.js"; +import { type APub as TAPub } from "../apub/utils.js"; Date.prototype.toTemporalInstant = toTemporalInstant; -/** - * Send ap object without initiating testkit - */ const DRY_SEND = !!process.env.TEST_DRY_SEND; -interface ITestAccount extends FTK_Software {} - -const getTestConfig = async (): Promise<{ - accounts: (ITestAccount & { label: string })[]; -}> => { - const mode = process.env.TEST_FEDERATION_MODE; - - if (mode === "KEYRING") { - const host = process.env.TEST_FEDERATION_KEYRING_HOST; - const auth = process.env.TEST_FEDERATION_KEYRING_AUTH; - const service = process.env.TEST_FEDERATION_KEYRING_SERVICE; - - const req = await fetch(new URL(`/service/${service}`, host), { - headers: { - authorization: `Bearer ${auth}`, - }, - }); - - if (!req.ok) throw new Error("[Keyring] Failed to get service config"); - - const data = await req.json(); - console.log("[Keyring] Loaded service from keyring"); - - return { - accounts: [ - { - label: service, - ...(data as any), - }, - ], - }; - } - - const input = process.env.TEST_FEDERATION_ACCOUNTS; - if (!input) throw new Error("TEST_FEDERATION_ACCOUNTS is not set"); - - const parsing = JSON.parse(input); - if ( - Array.isArray(parsing) && - parsing.every( - (entry): entry is ITestAccount & { label: string } => - typeof entry === "object" && - // - "type" in entry && - typeof entry.type === "string" && - SOFTWARES.indexOf(entry.type) > -1 && - // - "host" in entry && - typeof entry.host === "string" && - entry.host.startsWith("https://") && - // - "user" in entry && - typeof entry.user === "string" && - entry.user.indexOf("@") > 1 && - entry.user.indexOf("@") === entry.user.lastIndexOf("@") && - // - "auth" in entry && - typeof entry.auth === "string" && - // - "label" in entry && - typeof entry.label === "string", - ) - ) { - return { - accounts: parsing, - }; - } - - throw new Error("TEST_FEDERATION_ACCOUNTS is not valid"); -}; - -let Express: TExpress; -let APub: (new (...args: any) => IAPubUtils) & IAPubUtils_Static; -let federation: Federation; -let USER_IDENTIFIER: string; -let HANDOFF_TOKEN: string; - -/** - * Load modules we are testing - * These modules may use process.env immediately - */ -const load = async () => { - const lib_express = await import("../routes/express.js"); - const lib_apub_utils = await import("../apub/utils.js"); - const lib_apub_federation = await import("../apub/federation.js"); - - Express = lib_express.app; - APub = lib_apub_utils.APub; - federation = lib_apub_federation.federation; - USER_IDENTIFIER = lib_apub_federation.USER_IDENTIFIER; -}; - -const PORT = Math.floor(Math.random() * (30_000 - 20_001)) + 20_001; -let ActiveTunnel: Tunnel; -let ActiveExpress: Server; -let ActiveFederation: AbortController; - -let TestConfig = await getTestConfig(); +const MODE = process.env.FEDERATION_MODE === "docker" ? "docker" : "production"; + +let actorStop: (() => Promise) | null = null; let ourHandle: `${string}@${string}`; +let APub: TAPub; +let configStop: (() => Promise) | null = null; beforeAll(async () => { - await configure({ - sinks: { console: getConsoleSink() }, - loggers: [ - { - category: "fedify", - sinks: ["console"], - lowestLevel: "debug", - }, - ], - filters: {}, - }); - - ActiveTunnel = await openTunnel({ port: PORT, service: "localhost.run" }); - console.log( - `[Prepare] Tunnel localhost:${PORT} -> ${ActiveTunnel.url} (pid: ${ActiveTunnel.pid})`, - ); - - // modify environment - - process.env.PORT = PORT + ""; - process.env.OIDC_ISSUER = ActiveTunnel.url.toString(); - - // Generate and set a handoff token before modules are loaded, - // since Handoff.HANDOFF_TOKEN captures the env value at import time. - HANDOFF_TOKEN = "test-handoff-" + randomUUID(); - process.env.HANDOFF_TOKEN = HANDOFF_TOKEN; - - // load modules - await load(); - - // derive our actor handle after OIDC_ISSUER is stable - ourHandle = USER_IDENTIFIER + "@" + new URL(process.env.OIDC_ISSUER).host; - - ActiveFederation = new AbortController(); - process.once("SIGINT", () => ActiveFederation?.abort()); - void federation.startQueue(undefined, { - signal: ActiveFederation.signal, - }); - - await new Promise((res) => { - ActiveExpress = Express.listen(PORT, () => res()); - }); - - console.log(`[Prepare] Express running on localhost:${PORT}`); + // Start our Fedify actor + const { result, stop } = await startActorServer(MODE); + actorStop = stop; + APub = result.APub; + ourHandle = result.handle as `${string}@${string}`; }); afterAll(async () => { - await ActiveTunnel.close(); - await new Promise((res) => { - ActiveExpress.close(() => res()); - }); - ActiveFederation.abort(); + await actorStop?.(); + await configStop?.(); }); test("HANDOFF_TOKEN loaded", async () => { const { Handoff } = await import("../handoff/index.js"); - - expect(Handoff.HANDOFF_TOKEN).toBe(HANDOFF_TOKEN); + expect(Handoff.HANDOFF_TOKEN).toBe(process.env.HANDOFF_TOKEN); }); -describe.for( - TestConfig.accounts.map(({ label, ...account }) => ({ label, account })), -)("Deliver to $label", { concurrent: true }, async ({ label, account }) => { - let TestKit: FediTestKit; - let sessionId: string; - let sessionCode: string; - let authSession: AuthSession; - - beforeAll( - async () => { - const { AuthSession } = await import("../models/AuthSession.js"); - - if (!DRY_SEND) TestKit = await FediTestKit.create(account); - sessionId = "test-" + label + "-" + randomUUID(); - sessionCode = AuthSession.generateCode(); - - // @ts-ignore This has a private constructor - authSession = new AuthSession({ - id: sessionId, - one_time_code: sessionCode, - user_sub: account.user, - createdAt: new Date(), - expiresAt: new Date(), +describe("Federation tests", () => { + // We'll run against all configured accounts in sequence + const runTests = async () => { + const { accounts, stop } = await getTestConfig(); + configStop = stop ?? null; + + for (const account of accounts) { + describe(`Deliver to ${account.label}`, { concurrent: false }, () => { + let testKit: FediTestKit; + let sessionId: string; + let sessionCode: string; + let authSession: AuthSession; + + beforeAll( + async () => { + const { AuthSession } = await import("../models/AuthSession.js"); + + testKit = await FediTestKit.create(account); + sessionId = "test-" + account.label + "-" + randomUUID(); + sessionCode = AuthSession.generateCode(); + // @ts-ignore Private constructor + authSession = new AuthSession({ + id: sessionId, + one_time_code: sessionCode, + user_sub: account.user, + createdAt: new Date(), + expiresAt: new Date(), + }); + await testKit.setup(); + }, + account.type === "MBIN" ? 60000 : 10000, + ); + + afterAll(async () => { + if (!DRY_SEND) await testKit.cleanup(); + }); + + test.sequential("APub#sendDM", async () => { + await APub.send(authSession); + }); + + test.sequential("Delivery", { timeout: 30_000 }, async (ctx) => { + if (DRY_SEND) return; + const version = await testKit.getVersion(); + await ctx.annotate( + `${account.label} reports as using ${account.type} ${version}`, + ); + await testKit.expectToHave(sessionCode, 1000); + }); + + test.sequential("APub#delete", async () => { + await APub.delete(authSession); + }); + + test.sequential("Delivery - Delete", { timeout: 30_000 }, async () => { + if (DRY_SEND) return; + await expect( + testKit.expectToHave(sessionCode, 500), + ).rejects.toThrow(); + }); + + // ── TransientNote ────────────────────────────────────────── + + let transientNoteContent: string; + + test.sequential("APub#send with TransientNote", async () => { + const actor = await APub.lookupActor(account.user); + if (!actor) + throw new Error(`Could not look up actor for ${account.user}`); + + const { TransientNote } = await import("../models/TransientNote.js"); + transientNoteContent = `Transient note test ${sessionId}`; + const note = new TransientNote(actor, transientNoteContent); + await APub.send(note); + }); + + test.sequential( + "Delivery - TransientNote", + { timeout: 30_000 }, + async () => { + if (DRY_SEND) return; + await testKit.expectToHave(transientNoteContent, 1000); + }, + ); + + // ── Reply ────────────────────────────────────────────────── + + let replyContent: string; + + test.sequential("APub#reply", { timeout: 60_000 }, async () => { + if (DRY_SEND) return; + + let capturedObject: any = null; + let capturedActor: any = null; + let captureResolve: (value: void) => void; + const captured = new Promise((resolve) => { + captureResolve = resolve; + }); + + global.TEST_FEDERATION_INCOMING_CREATE = ( + actor: any, + object: any, + ) => { + capturedActor = actor; + capturedObject = object; + captureResolve!(); + }; + + try { + await testKit.send( + ourHandle, + `Reply test original message ${sessionId}`, + ); + + await Promise.race([ + captured, + new Promise((_, reject) => + setTimeout( + () => + reject(new Error("Timed out waiting for incoming Create")), + 30_000, + ), + ), + ]); + + const { Note, Mention } = await import("@fedify/vocab"); + replyContent = `Reply to real message ${sessionId}`; + const replyNote = new Note({ + to: capturedActor, + content: replyContent, + published: new Date().toTemporalInstant(), + tags: [ + new Mention({ + href: capturedActor.id!, + name: String(capturedActor.id!), + }), + ], + }); + + await APub.reply(capturedObject, replyNote); + } finally { + global.TEST_FEDERATION_INCOMING_CREATE = undefined; + } + }); + + test.sequential("Delivery - Reply", { timeout: 30_000 }, async () => { + if (DRY_SEND) return; + await testKit.expectToHave(replyContent, 1000); + }); + + // ── Handoff flow ─────────────────────────────────────────── + + test.sequential( + "APub#send via HandoffSession", + { timeout: 30_000 }, + async () => { + if (DRY_SEND) return; + const HANDOFF_TOKEN = process.env.HANDOFF_TOKEN!; + await testKit.send(ourHandle, HANDOFF_TOKEN); + }, + ); + + test.sequential( + "Delivery - HandoffSession", + { timeout: 60_000 }, + async (ctx) => { + if (DRY_SEND) return; + await ctx.annotate("Expecting handoff URL in reply"); + await testKit.expectToHave("/handoff/", 3000); + }, + ); + + // ── Sidecar flow ─────────────────────────────────────────── + + test.sequential("APub#send via SidecarSession", async () => { + if (DRY_SEND) return; + const { SidecarSession } = + await import("../models/SidecarSession.js"); + const sidecar = await SidecarSession.create("internal"); + await testKit.send(ourHandle, `${sidecar.id} please authenticate me`); + }); + + test.sequential( + "Delivery - SidecarSession", + { timeout: 60_000 }, + async (ctx) => { + if (DRY_SEND) return; + await ctx.annotate("Expecting sidecar authenticated message"); + await testKit.expectToHave("Authenticated as", 3000); + }, + ); }); - - if (!DRY_SEND) await TestKit.setup(); - }, - account.type === "MBIN" ? 60000 : 10000, - ); - - // ── Auth session (existing) ──────────────────────────────────────── - - test.sequential("APub#sendDM", async () => { - await APub.send(authSession); - }); - - test.sequential("Delivery", { timeout: 30_000 }, async (ctx) => { - if (DRY_SEND) { - await new Promise((res) => {}); - } else { - const version = await TestKit.getVersion(); - await ctx.annotate( - `${label} reports as using version ${account.type} ${version}`, - ); - await TestKit.expectToHave(sessionCode, 1000); - } - }); - - // ── APub#delete ──────────────────────────────────────────────────── - - test.sequential("APub#delete", async () => { - await APub.delete(authSession); - }); - - test.sequential("Delivery - Delete", { timeout: 30_000 }, async (ctx) => { - if (DRY_SEND) { - await new Promise((res) => {}); - } else { - // After deletion the message should no longer appear in the inbox - await expect(TestKit.expectToHave(sessionCode, 500)).rejects.toThrow(); - await ctx.annotate( - `Confirmed deletion: "${sessionCode}" no longer visible`, - ); } - }); - - // ── APub#send with TransientNote ─────────────────────────────────── - - let transientNoteContent: string; - - test.sequential("APub#send with TransientNote", async () => { - const actor = await APub.lookupActor(account.user); - if (!actor) throw new Error(`Could not look up actor for ${account.user}`); - - const { TransientNote } = await import("../models/TransientNote.js"); - transientNoteContent = `Transient note test ${sessionId}`; - const note = new TransientNote(actor, transientNoteContent); - await APub.send(note); - }); - - test.sequential( - "Delivery - TransientNote", - { timeout: 30_000 }, - async (ctx) => { - if (DRY_SEND) { - await new Promise((res) => {}); - } else { - await ctx.annotate(`Expecting transient note content`); - await TestKit.expectToHave(transientNoteContent, 1000); - } - }, - ); - - // ── APub#reply ───────────────────────────────────────────────────── - // Uses the TEST_FEDERATION_INCOMING_CREATE global hook to capture the - // actual Object received via ActivityPub, then replies to it. - - let replyContent: string; - - test.sequential("APub#reply", { timeout: 60_000 }, async () => { - // Set up the capture hook before the remote sends us a DM - let capturedObject: any = null; - let capturedActor: any = null; - let captureResolve: (value: void) => void; - const captured = new Promise((resolve) => { - captureResolve = resolve; - }); - - global.TEST_FEDERATION_INCOMING_CREATE = (actor, object) => { - capturedActor = actor; - capturedObject = object; - captureResolve!(); - }; - - try { - // Have the remote send us a DM — our Fedify inbox listener - // deserializes it and fires the Create handler, which invokes - // the capture hook above. - await TestKit.send(ourHandle, `Reply test original message ${sessionId}`); - - // Wait for Fedify's queue to process the incoming activity - const timeout = 30_000; - await Promise.race([ - captured, - new Promise((_, reject) => - setTimeout( - () => reject(new Error("Timed out waiting for incoming Create")), - timeout, - ), - ), - ]); - - // Reply using the real received object - const { Note, Mention } = await import("@fedify/vocab"); - replyContent = `Reply to real message ${sessionId}`; - const replyNote = new Note({ - to: capturedActor, - content: replyContent, - published: new Date().toTemporalInstant(), - tags: [ - new Mention({ - href: capturedActor.id!, - name: String(capturedActor.id!), - }), - ], - }); + }; - await APub.reply(capturedObject, replyNote); - } finally { - // Clean up the hook - global.TEST_FEDERATION_INCOMING_CREATE = undefined; - } - }); - - test.sequential("Delivery - Reply", { timeout: 30_000 }, async (ctx) => { - if (DRY_SEND) { - await new Promise((res) => {}); - } else { - await ctx.annotate(`Expecting reply content`); - await TestKit.expectToHave(replyContent, 1000); - } - }); - - // ── APub#send via HandoffSession (handoff flow) ──────────────────── - - test.sequential( - "APub#send via HandoffSession", - { timeout: 30_000 }, - async () => { - if (DRY_SEND) return; - - // The remote sends us a DM containing the handoff token. - // Our inbox handler (HandoffActivityPub.handle) processes it, - // creates a HandoffSession, and replies via APub.reply() - // with a URL containing "/handoff/". - await TestKit.send(ourHandle, HANDOFF_TOKEN); - }, - ); - - test.sequential( - "Delivery - HandoffSession response", - { timeout: 60_000 }, - async (ctx) => { - if (DRY_SEND) { - await new Promise((res) => {}); - } else { - await ctx.annotate(`Expecting handoff URL in reply`); - // The reply from the handoff handler contains the handoff page URL - await TestKit.expectToHave("/handoff/", 3000); - } - }, - ); - - // ── APub#send via SidecarSession (sidecar flow) ──────────────────── - - let sidecarId: string; - - test.sequential("APub#send via SidecarSession", async () => { - if (DRY_SEND) return; - - const { SidecarSession } = await import("../models/SidecarSession.js"); - const sidecar = await SidecarSession.create("internal"); - sidecarId = sidecar.id; - - // The remote sends us a DM containing the sidecar session ID. - // Our inbox handler (HandoffSidecar.handle) processes it, - // claims the session, and sends a TransientNote via APub.send() - // with text that includes "Authenticated as". - await TestKit.send(ourHandle, `${sidecar.id} please authenticate me`); - }); - - test.sequential( - "Delivery - SidecarSession response", - { timeout: 60_000 }, - async (ctx) => { - if (DRY_SEND) { - await new Promise((res) => {}); - } else { - await ctx.annotate(`Expecting sidecar authenticated message`); - await TestKit.expectToHave("Authenticated as", 3000); - } - }, - ); - - afterAll(async () => { - if (!DRY_SEND) await TestKit.cleanup(); - }); + runTests(); }); diff --git a/backend/src/__tests__/helpers/actor-server.ts b/backend/src/__tests__/helpers/actor-server.ts new file mode 100644 index 0000000..75391a0 --- /dev/null +++ b/backend/src/__tests__/helpers/actor-server.ts @@ -0,0 +1,113 @@ +import { type Express as TExpress } from "express"; +import { Server } from "node:http"; +import { openTunnel, Tunnel } from "@hongminhee/localtunnel"; +import { randomUUID } from "node:crypto"; +import type { APub } from "../../apub/utils.js"; +import type { Federation } from "@fedify/fedify"; +import { configure, getConsoleSink } from "@logtape/logtape"; + +export interface ActorServerResult { + url: URL; + handle: string; + federation: Federation; + APub: APub; + USER_IDENTIFIER: string; +} + +/** + * Boots the Express + Fedify actor behind either a Caddy reverse proxy + * (Docker mode) or a public tunnel (production mode). + */ +export async function startActorServer(mode: "docker" | "production"): Promise<{ + result: ActorServerResult; + stop: () => Promise; +}> { + await configure({ + sinks: { console: getConsoleSink() }, + loggers: [ + { + category: "fedify", + sinks: ["console"], + lowestLevel: "debug", + }, + { + category: ["logtape", "meta"], + lowestLevel: "warning", + }, + ], + filters: {}, + }); + + const PORT = Math.floor(Math.random() * (30_000 - 20_001)) + 20_001; + let tunnelUrl: URL; + let activeTunnel: Tunnel | null = null; + + if (mode === "docker") { + // Docker mode: Caddy proxies auth.ci.local → host.docker.internal:PORT + // We need to tell DockerInstanceManager which port we're on. + // The Caddyfile has a placeholder — we pass it via env to compose. + tunnelUrl = new URL("https://auth.ci.local"); + process.env.ACTOR_PORT = String(PORT); + } else { + // Production mode: start a public tunnel + activeTunnel = await openTunnel({ port: PORT, service: "localhost.run" }); + tunnelUrl = new URL(activeTunnel.url); + console.log( + `[ActorServer] Tunnel localhost:${PORT} -> ${tunnelUrl} (pid: ${activeTunnel.pid})`, + ); + } + + // Set environment before loading modules + process.env.PORT = String(PORT); + process.env.OIDC_ISSUER = tunnelUrl.toString(); + + const HANDOFF_TOKEN = "test-handoff-" + randomUUID(); + process.env.HANDOFF_TOKEN = HANDOFF_TOKEN; + + // Load modules (they read process.env at import time) + const lib_express = await import("../../routes/express.js"); + const lib_apub_utils = await import("../../apub/utils.js"); + const lib_apub_federation = await import("../../apub/federation.js"); + + const Express: TExpress = lib_express.app; + const APub = lib_apub_utils.APub; + const federation: Federation = lib_apub_federation.federation; + const USER_IDENTIFIER: string = lib_apub_federation.USER_IDENTIFIER; + + const ourHandle = + `${USER_IDENTIFIER}@${tunnelUrl.host}` as `${string}@${string}`; + + const activeFederation = new AbortController(); + process.once("SIGINT", () => activeFederation?.abort()); + void federation.startQueue(undefined, { + signal: activeFederation.signal, + }); + + const activeExpress: Server = await new Promise((res) => { + const srv = Express.listen(PORT, () => res(srv)); + }); + + console.log(`[ActorServer] Express running on localhost:${PORT}`); + console.log(`[ActorServer] Actor handle: ${ourHandle}`); + + const result: ActorServerResult = { + url: tunnelUrl, + handle: ourHandle, + federation, + APub, + USER_IDENTIFIER, + }; + + const stop = async () => { + if (activeTunnel) { + await activeTunnel.close(); + } + await new Promise((res) => { + activeExpress.close(() => res()); + }); + activeFederation.abort(); + console.log("[ActorServer] Stopped"); + }; + + return { result, stop }; +} diff --git a/backend/src/__tests__/helpers/config.ts b/backend/src/__tests__/helpers/config.ts new file mode 100644 index 0000000..573ea9a --- /dev/null +++ b/backend/src/__tests__/helpers/config.ts @@ -0,0 +1,146 @@ +import { + type Software, + SOFTWARES, + DockerInstanceManager, +} from "@sc07/fedi-testkit"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +interface TestAccount extends Software { + label: string; +} + +interface TestConfig { + accounts: TestAccount[]; + stop?: () => Promise; +} + +/** + * Resolve the compose directory from the testkit package location. + * In development (portal link), this is under node_modules/@sc07/fedi-testkit. + */ +function resolveComposeDir(): string { + // Try to find the testkit's dist directory via module resolution + // The compose files are at: src/docker/compose/ relative to the testkit root + const testkitRoot = join( + fileURLToPath(import.meta.url), + "../../../../node_modules/@sc07/fedi-testkit", + ); + return join(testkitRoot, "src/docker/compose"); +} + +export async function getTestConfig(): Promise { + const mode = process.env.FEDERATION_MODE; + + if (!mode || mode === "production") { + return getKeyringConfig(); + } + + if (mode === "docker") { + return getDockerConfig(); + } + + throw new Error( + `Unknown FEDERATION_MODE: "${mode}". Expected "docker" or "production".`, + ); +} + +/** + * Fetch credentials from the keyring service (production mode). + * This is the same as the original getTestConfig() in federation.test.ts. + */ +async function getKeyringConfig(): Promise { + const keyringMode = process.env.TEST_FEDERATION_MODE; + + if (keyringMode === "KEYRING") { + const host = process.env.TEST_FEDERATION_KEYRING_HOST; + const auth = process.env.TEST_FEDERATION_KEYRING_AUTH; + const service = process.env.TEST_FEDERATION_KEYRING_SERVICE; + if (!host || !auth || !service) { + throw new Error( + "KEYRING mode requires TEST_FEDERATION_KEYRING_HOST, _AUTH, and _SERVICE", + ); + } + + const req = await fetch(new URL(`/service/${service}`, host), { + headers: { authorization: `Bearer ${auth}` }, + }); + if (!req.ok) throw new Error("[Keyring] Failed to get service config"); + + const data = (await req.json()) as any; + console.log("[Keyring] Loaded service from keyring"); + + return { + accounts: [{ label: service, ...data }], + }; + } + + // Fall back to TEST_FEDERATION_ACCOUNTS env var + const input = process.env.TEST_FEDERATION_ACCOUNTS; + if (!input) throw new Error("TEST_FEDERATION_ACCOUNTS is not set"); + + const parsed = JSON.parse(input); + if ( + !Array.isArray(parsed) || + !parsed.every( + (e: any) => + typeof e === "object" && + "type" in e && + typeof e.type === "string" && + SOFTWARES.indexOf(e.type) > -1 && + "host" in e && + typeof e.host === "string" && + "user" in e && + typeof e.user === "string" && + "auth" in e && + typeof e.auth === "string" && + "label" in e && + typeof e.label === "string", + ) + ) { + throw new Error("TEST_FEDERATION_ACCOUNTS is not valid"); + } + + return { accounts: parsed }; +} + +/** + * Start a Docker instance and return its credentials (Docker mode). + */ +async function getDockerConfig(): Promise { + const software = process.env.TEST_SOFTWARE; + if (!software) { + throw new Error("Docker mode requires TEST_SOFTWARE env var"); + } + + // Validate against known software types + const upper = software.toUpperCase(); + if (!SOFTWARES.includes(upper as any)) { + throw new Error( + `Unknown software: "${software}". Valid: ${SOFTWARES.join(", ")}`, + ); + } + + console.log(`[Config] Starting Docker instance for ${upper}...`); + + const composeDir = resolveComposeDir(); + const manager = new DockerInstanceManager(composeDir); + const info = await manager.start(upper as any); + + console.log(`[Config] Instance ready: ${info.instanceUrl}`); + + const account: TestAccount = { + label: upper, + type: info.account.type, + host: info.account.host as `https://${string}`, + user: info.account.user, + auth: info.account.auth, + }; + + return { + accounts: [account], + stop: async () => { + await manager.stop(upper as any); + }, + }; +} diff --git a/backend/src/apub/utils.ts b/backend/src/apub/utils.ts index aaac619..c8f45c2 100644 --- a/backend/src/apub/utils.ts +++ b/backend/src/apub/utils.ts @@ -6,6 +6,8 @@ import { APubLive } from "./utils.live.js"; import { APubStub } from "./utils.stub.js"; import { IProfile } from "../lib/instance/userMeta.js"; +export type APub = (new (...args: any) => IAPubUtils) & IAPubUtils_Static; + export const APub: (new (...args: any) => IAPubUtils) & IAPubUtils_Static = Flags.Dev.UseAPubStub ? APubStub : APubLive; diff --git a/yarn.lock b/yarn.lock index 82f37bc..c4bb103 100644 --- a/yarn.lock +++ b/yarn.lock @@ -838,7 +838,7 @@ __metadata: "@js-temporal/polyfill": "npm:^0.5.1" "@logtape/logtape": "npm:^0.9.2" "@prisma/client": "npm:^5.22.0" - "@sc07/fedi-testkit": "npm:^1.1.5" + "@sc07/fedi-testkit": "file:../../fedi-testkit" "@tsconfig/recommended": "npm:^1.0.13" "@types/cookie-parser": "npm:^1.4.10" "@types/cors": "npm:^2.8.19" @@ -1829,13 +1829,21 @@ __metadata: languageName: node linkType: hard -"@sc07/fedi-testkit@npm:^1.1.5": +"@sc07/fedi-testkit@file:../../fedi-testkit::locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend": version: 1.1.5 - resolution: "@sc07/fedi-testkit@npm:1.1.5::__archiveUrl=https%3A%2F%2Fsc07.dev%2Fapi%2Fv4%2Fprojects%2F78%2Fpackages%2Fnpm%2F%40sc07%2Ffedi-testkit%2F-%2F%40sc07%2Ffedi-testkit-1.1.5.tgz" + resolution: "@sc07/fedi-testkit@file:../../fedi-testkit#../../fedi-testkit::hash=ec0c0e&locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend" dependencies: + execa: "npm:^9.6.1" puppeteer: "npm:^24.35.0" tsx: "npm:^4.21.0" - checksum: 10c0/d5a280dc39433b80bfaccc5f0a244922c1262a30875e63ced8435dbea564e6199a29a5114ff7d1d511bd7ec107b20d3685c85aaf050d1a9013abdf625932a255 + checksum: 10c0/2567ac1ed85682dd2dd12b8778f65c814d27260ade89107137b4a4aabbd9ab0cf23cc1af630bf81f38fa6fd5af081eb2d4a67ac5dd9a40a55d1c70e76f5baf0a + languageName: node + linkType: hard + +"@sec-ant/readable-stream@npm:^0.4.1": + version: 0.4.1 + resolution: "@sec-ant/readable-stream@npm:0.4.1" + checksum: 10c0/64e9e9cf161e848067a5bf60cdc04d18495dc28bb63a8d9f8993e4dd99b91ad34e4b563c85de17d91ffb177ec17a0664991d2e115f6543e73236a906068987af languageName: node linkType: hard @@ -1846,6 +1854,13 @@ __metadata: languageName: node linkType: hard +"@sindresorhus/merge-streams@npm:^4.0.0": + version: 4.0.0 + resolution: "@sindresorhus/merge-streams@npm:4.0.0" + checksum: 10c0/482ee543629aa1933b332f811a1ae805a213681ecdd98c042b1c1b89387df63e7812248bb4df3910b02b3cc5589d3d73e4393f30e197c9dde18046ccd471fc6b + languageName: node + linkType: hard + "@standard-schema/spec@npm:^1.1.0": version: 1.1.0 resolution: "@standard-schema/spec@npm:1.1.0" @@ -3225,7 +3240,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.2": +"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -3917,6 +3932,26 @@ __metadata: languageName: node linkType: hard +"execa@npm:^9.6.1": + version: 9.6.1 + resolution: "execa@npm:9.6.1" + dependencies: + "@sindresorhus/merge-streams": "npm:^4.0.0" + cross-spawn: "npm:^7.0.6" + figures: "npm:^6.1.0" + get-stream: "npm:^9.0.0" + human-signals: "npm:^8.0.1" + is-plain-obj: "npm:^4.1.0" + is-stream: "npm:^4.0.1" + npm-run-path: "npm:^6.0.0" + pretty-ms: "npm:^9.2.0" + signal-exit: "npm:^4.1.0" + strip-final-newline: "npm:^4.0.0" + yoctocolors: "npm:^2.1.1" + checksum: 10c0/636b36585306a3c8bc3a9d7b25d2d915fb06d8c9b9b02a804280d62562de3b34535affc1b7702b039320e0953daa6545a073f3c4b63fe974c1fe11336c56b467 + languageName: node + linkType: hard + "expect-type@npm:^1.3.0": version: 1.3.0 resolution: "expect-type@npm:1.3.0" @@ -4082,6 +4117,15 @@ __metadata: languageName: unknown linkType: soft +"figures@npm:^6.1.0": + version: 6.1.0 + resolution: "figures@npm:6.1.0" + dependencies: + is-unicode-supported: "npm:^2.0.0" + checksum: 10c0/9159df4264d62ef447a3931537de92f5012210cf5135c35c010df50a2169377581378149abfe1eb238bd6acbba1c0d547b1f18e0af6eee49e30363cedaffcfe4 + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -4271,6 +4315,16 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^9.0.0": + version: 9.0.1 + resolution: "get-stream@npm:9.0.1" + dependencies: + "@sec-ant/readable-stream": "npm:^0.4.1" + is-stream: "npm:^4.0.1" + checksum: 10c0/d70e73857f2eea1826ac570c3a912757dcfbe8a718a033fa0c23e12ac8e7d633195b01710e0559af574cbb5af101009b42df7b6f6b29ceec8dbdf7291931b948 + languageName: node + linkType: hard + "get-uri@npm:^6.0.1": version: 6.0.5 resolution: "get-uri@npm:6.0.5" @@ -4509,6 +4563,13 @@ __metadata: languageName: node linkType: hard +"human-signals@npm:^8.0.1": + version: 8.0.1 + resolution: "human-signals@npm:8.0.1" + checksum: 10c0/195ac607108c56253757717242e17cd2e21b29f06c5d2dad362e86c672bf2d096e8a3bbb2601841c376c2301c4ae7cff129e87f740aa4ebff1390c163114c7c4 + languageName: node + linkType: hard + "iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -4679,6 +4740,13 @@ __metadata: languageName: node linkType: hard +"is-plain-obj@npm:^4.1.0": + version: 4.1.0 + resolution: "is-plain-obj@npm:4.1.0" + checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e + languageName: node + linkType: hard + "is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -4691,6 +4759,20 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^4.0.1": + version: 4.0.1 + resolution: "is-stream@npm:4.0.1" + checksum: 10c0/2706c7f19b851327ba374687bc4a3940805e14ca496dc672b9629e744d143b1ad9c6f1b162dece81c7bfbc0f83b32b61ccc19ad2e05aad2dd7af347408f60c7f + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10c0/a0f53e9a7c1fdbcf2d2ef6e40d4736fdffff1c9f8944c75e15425118ff3610172c87bf7bc6c34d3903b04be59790bb2212ddbe21ee65b5a97030fc50370545a5 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -5438,6 +5520,16 @@ __metadata: languageName: node linkType: hard +"npm-run-path@npm:^6.0.0": + version: 6.0.0 + resolution: "npm-run-path@npm:6.0.0" + dependencies: + path-key: "npm:^4.0.0" + unicorn-magic: "npm:^0.3.0" + checksum: 10c0/b223c8a0dcd608abf95363ea5c3c0ccc3cd877daf0102eaf1b0f2390d6858d8337fbb7c443af2403b067a7d2c116d10691ecd22ab3c5273c44da1ff8d07753bd + languageName: node + linkType: hard + "oauth4webapi@npm:^3.8.5": version: 3.8.6 resolution: "oauth4webapi@npm:3.8.6" @@ -5636,6 +5728,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 10c0/a7900f4f1ebac24cbf5e9708c16fb2fd482517fad353aecd7aefb8c2ba2f85ce017913ccb8925d231770404780df46244ea6fec598b3bde6490882358b4d2d16 + languageName: node + linkType: hard + "parseurl@npm:^1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -5664,6 +5763,13 @@ __metadata: languageName: node linkType: hard +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 10c0/794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3 + languageName: node + linkType: hard + "path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" @@ -5787,6 +5893,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^9.2.0": + version: 9.3.0 + resolution: "pretty-ms@npm:9.3.0" + dependencies: + parse-ms: "npm:^4.0.0" + checksum: 10c0/555ea39a1de48a30601938aedb76d682871d33b6dee015281c37108921514b11e1792928b1648c2e5589acc73c8ef0fb5e585fb4c718e340a28b86799e90fb34 + languageName: node + linkType: hard + "prisma@npm:^5.22.0": version: 5.22.0 resolution: "prisma@npm:5.22.0" @@ -6553,6 +6668,13 @@ __metadata: languageName: node linkType: hard +"signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -6730,6 +6852,13 @@ __metadata: languageName: node linkType: hard +"strip-final-newline@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-final-newline@npm:4.0.0" + checksum: 10c0/b0cf2b62d597a1b0e3ebc42b88767f0a0d45601f89fd379a928a1812c8779440c81abba708082c946445af1d6b62d5f16e2a7cf4f30d9d6587b89425fae801ff + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -7019,6 +7148,13 @@ __metadata: languageName: node linkType: hard +"unicorn-magic@npm:^0.3.0": + version: 0.3.0 + resolution: "unicorn-magic@npm:0.3.0" + checksum: 10c0/0a32a997d6c15f1c2a077a15b1c4ca6f268d574cf5b8975e778bb98e6f8db4ef4e86dfcae4e158cd4c7e38fb4dd383b93b13eefddc7f178dea13d3ac8a603271 + languageName: node + linkType: hard + "unique-filename@npm:^5.0.0": version: 5.0.0 resolution: "unique-filename@npm:5.0.0" @@ -7418,6 +7554,13 @@ __metadata: languageName: node linkType: hard +"yoctocolors@npm:^2.1.1": + version: 2.1.2 + resolution: "yoctocolors@npm:2.1.2" + checksum: 10c0/b220f30f53ebc2167330c3adc86a3c7f158bcba0236f6c67e25644c3188e2571a6014ffc1321943bb619460259d3d27eb4c9cc58c2d884c1b195805883ec7066 + languageName: node + linkType: hard + "zod@npm:^3.24.1": version: 3.25.76 resolution: "zod@npm:3.25.76" -- GitLab From 70128b40437172cdde3384ba4a74f86e4e04603b Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Jun 2026 22:12:27 -0600 Subject: [PATCH 3/7] testkit: add test scenarios Assisted-by: deepseek:v4-flash --- backend/src/__tests__/federation.test.ts | 192 +++--------------- backend/src/__tests__/helpers/actor-server.ts | 16 +- backend/src/__tests__/scenarios/index.ts | 154 ++++++++++++++ package.json | 1 + yarn.lock | 16 +- 5 files changed, 206 insertions(+), 173 deletions(-) create mode 100644 backend/src/__tests__/scenarios/index.ts diff --git a/backend/src/__tests__/federation.test.ts b/backend/src/__tests__/federation.test.ts index 1e7c8c9..cb1006f 100644 --- a/backend/src/__tests__/federation.test.ts +++ b/backend/src/__tests__/federation.test.ts @@ -5,12 +5,20 @@ import { randomUUID } from "node:crypto"; import { toTemporalInstant } from "@js-temporal/polyfill"; import { startActorServer } from "./helpers/actor-server.js"; import { getTestConfig } from "./helpers/config.js"; +import { + sendDmScenario, + deleteScenario, + sendTransientNoteScenario, + replyScenario, + handoffScenario, + sidecarScenario, +} from "./scenarios/index.js"; +import type { ScenarioContext } from "./scenarios/index.js"; import { type APub as TAPub } from "../apub/utils.js"; Date.prototype.toTemporalInstant = toTemporalInstant; const DRY_SEND = !!process.env.TEST_DRY_SEND; - const MODE = process.env.FEDERATION_MODE === "docker" ? "docker" : "production"; let actorStop: (() => Promise) | null = null; @@ -19,7 +27,6 @@ let APub: TAPub; let configStop: (() => Promise) | null = null; beforeAll(async () => { - // Start our Fedify actor const { result, stop } = await startActorServer(MODE); actorStop = stop; APub = result.APub; @@ -37,17 +44,16 @@ test("HANDOFF_TOKEN loaded", async () => { }); describe("Federation tests", () => { - // We'll run against all configured accounts in sequence const runTests = async () => { const { accounts, stop } = await getTestConfig(); configStop = stop ?? null; for (const account of accounts) { describe(`Deliver to ${account.label}`, { concurrent: false }, () => { - let testKit: FediTestKit; - let sessionId: string; - let sessionCode: string; - let authSession: AuthSession; + let testKit!: FediTestKit; + let sessionId!: string; + let sessionCode!: string; + let authSession!: AuthSession; beforeAll( async () => { @@ -73,160 +79,24 @@ describe("Federation tests", () => { if (!DRY_SEND) await testKit.cleanup(); }); - test.sequential("APub#sendDM", async () => { - await APub.send(authSession); - }); - - test.sequential("Delivery", { timeout: 30_000 }, async (ctx) => { - if (DRY_SEND) return; - const version = await testKit.getVersion(); - await ctx.annotate( - `${account.label} reports as using ${account.type} ${version}`, - ); - await testKit.expectToHave(sessionCode, 1000); - }); - - test.sequential("APub#delete", async () => { - await APub.delete(authSession); - }); - - test.sequential("Delivery - Delete", { timeout: 30_000 }, async () => { - if (DRY_SEND) return; - await expect( - testKit.expectToHave(sessionCode, 500), - ).rejects.toThrow(); - }); - - // ── TransientNote ────────────────────────────────────────── - - let transientNoteContent: string; - - test.sequential("APub#send with TransientNote", async () => { - const actor = await APub.lookupActor(account.user); - if (!actor) - throw new Error(`Could not look up actor for ${account.user}`); - - const { TransientNote } = await import("../models/TransientNote.js"); - transientNoteContent = `Transient note test ${sessionId}`; - const note = new TransientNote(actor, transientNoteContent); - await APub.send(note); - }); - - test.sequential( - "Delivery - TransientNote", - { timeout: 30_000 }, - async () => { - if (DRY_SEND) return; - await testKit.expectToHave(transientNoteContent, 1000); - }, - ); - - // ── Reply ────────────────────────────────────────────────── - - let replyContent: string; - - test.sequential("APub#reply", { timeout: 60_000 }, async () => { - if (DRY_SEND) return; - - let capturedObject: any = null; - let capturedActor: any = null; - let captureResolve: (value: void) => void; - const captured = new Promise((resolve) => { - captureResolve = resolve; - }); - - global.TEST_FEDERATION_INCOMING_CREATE = ( - actor: any, - object: any, - ) => { - capturedActor = actor; - capturedObject = object; - captureResolve!(); - }; - - try { - await testKit.send( - ourHandle, - `Reply test original message ${sessionId}`, - ); - - await Promise.race([ - captured, - new Promise((_, reject) => - setTimeout( - () => - reject(new Error("Timed out waiting for incoming Create")), - 30_000, - ), - ), - ]); - - const { Note, Mention } = await import("@fedify/vocab"); - replyContent = `Reply to real message ${sessionId}`; - const replyNote = new Note({ - to: capturedActor, - content: replyContent, - published: new Date().toTemporalInstant(), - tags: [ - new Mention({ - href: capturedActor.id!, - name: String(capturedActor.id!), - }), - ], - }); - - await APub.reply(capturedObject, replyNote); - } finally { - global.TEST_FEDERATION_INCOMING_CREATE = undefined; - } - }); - - test.sequential("Delivery - Reply", { timeout: 30_000 }, async () => { - if (DRY_SEND) return; - await testKit.expectToHave(replyContent, 1000); - }); - - // ── Handoff flow ─────────────────────────────────────────── - - test.sequential( - "APub#send via HandoffSession", - { timeout: 30_000 }, - async () => { - if (DRY_SEND) return; - const HANDOFF_TOKEN = process.env.HANDOFF_TOKEN!; - await testKit.send(ourHandle, HANDOFF_TOKEN); - }, - ); - - test.sequential( - "Delivery - HandoffSession", - { timeout: 60_000 }, - async (ctx) => { - if (DRY_SEND) return; - await ctx.annotate("Expecting handoff URL in reply"); - await testKit.expectToHave("/handoff/", 3000); - }, - ); - - // ── Sidecar flow ─────────────────────────────────────────── - - test.sequential("APub#send via SidecarSession", async () => { - if (DRY_SEND) return; - const { SidecarSession } = - await import("../models/SidecarSession.js"); - const sidecar = await SidecarSession.create("internal"); - await testKit.send(ourHandle, `${sidecar.id} please authenticate me`); - }); - - test.sequential( - "Delivery - SidecarSession", - { timeout: 60_000 }, - async (ctx) => { - if (DRY_SEND) return; - await ctx.annotate("Expecting sidecar authenticated message"); - await testKit.expectToHave("Authenticated as", 3000); - }, - ); + const ctx: ScenarioContext = { + testKit, + APub, + ourHandle, + sessionId, + sessionCode, + authSession, + account, + DRY_SEND, + }; + + // Run scenarios in sequence — these are vitest.sequential calls + sendDmScenario(ctx); + deleteScenario(ctx); + sendTransientNoteScenario(ctx); + replyScenario(ctx); + handoffScenario(ctx); + sidecarScenario(ctx); }); } }; diff --git a/backend/src/__tests__/helpers/actor-server.ts b/backend/src/__tests__/helpers/actor-server.ts index 75391a0..b345103 100644 --- a/backend/src/__tests__/helpers/actor-server.ts +++ b/backend/src/__tests__/helpers/actor-server.ts @@ -1,6 +1,6 @@ import { type Express as TExpress } from "express"; import { Server } from "node:http"; -import { openTunnel, Tunnel } from "@hongminhee/localtunnel"; +import { createTunnel } from "@sc07/fedi-testkit"; import { randomUUID } from "node:crypto"; import type { APub } from "../../apub/utils.js"; import type { Federation } from "@fedify/fedify"; @@ -40,7 +40,7 @@ export async function startActorServer(mode: "docker" | "production"): Promise<{ const PORT = Math.floor(Math.random() * (30_000 - 20_001)) + 20_001; let tunnelUrl: URL; - let activeTunnel: Tunnel | null = null; + let closeTunnel: (() => Promise) | null = null; if (mode === "docker") { // Docker mode: Caddy proxies auth.ci.local → host.docker.internal:PORT @@ -50,11 +50,9 @@ export async function startActorServer(mode: "docker" | "production"): Promise<{ process.env.ACTOR_PORT = String(PORT); } else { // Production mode: start a public tunnel - activeTunnel = await openTunnel({ port: PORT, service: "localhost.run" }); - tunnelUrl = new URL(activeTunnel.url); - console.log( - `[ActorServer] Tunnel localhost:${PORT} -> ${tunnelUrl} (pid: ${activeTunnel.pid})`, - ); + const tunnel = await createTunnel(PORT); + tunnelUrl = tunnel.url; + closeTunnel = tunnel.close; } // Set environment before loading modules @@ -99,9 +97,7 @@ export async function startActorServer(mode: "docker" | "production"): Promise<{ }; const stop = async () => { - if (activeTunnel) { - await activeTunnel.close(); - } + await closeTunnel?.(); await new Promise((res) => { activeExpress.close(() => res()); }); diff --git a/backend/src/__tests__/scenarios/index.ts b/backend/src/__tests__/scenarios/index.ts new file mode 100644 index 0000000..3c2dd27 --- /dev/null +++ b/backend/src/__tests__/scenarios/index.ts @@ -0,0 +1,154 @@ +import { test, expect } from "vitest"; +import type { FediTestKit, Software } from "@sc07/fedi-testkit"; +import type { AuthSession } from "../../models/AuthSession.js"; + +export interface ScenarioContext { + testKit: FediTestKit; + APub: any; + ourHandle: `${string}@${string}`; + sessionId: string; + sessionCode: string; + authSession: AuthSession; + account: Software & { label: string }; + DRY_SEND: boolean; +} + +export function sendDmScenario(ctx: ScenarioContext): void { + test.sequential("APub#sendDM", async () => { + await ctx.APub.send(ctx.authSession); + }); + + test.sequential("Delivery", { timeout: 30_000 }, async (t) => { + if (ctx.DRY_SEND) return; + const version = await ctx.testKit.getVersion(); + await t.annotate( + `${ctx.account.label} reports as using ${ctx.account.type} ${version}`, + ); + await ctx.testKit.expectToHave(ctx.sessionCode, 1000); + }); +} + +export function deleteScenario(ctx: ScenarioContext): void { + test.sequential("APub#delete", async () => { + await ctx.APub.delete(ctx.authSession); + }); + + test.sequential("Delivery - Delete", { timeout: 30_000 }, async () => { + if (ctx.DRY_SEND) return; + await expect(ctx.testKit.expectToHave(ctx.sessionCode, 500)).rejects + .toThrow(); + }); +} + +export function sendTransientNoteScenario(ctx: ScenarioContext): void { + let transientNoteContent: string; + + test.sequential("APub#send with TransientNote", async () => { + const actor = await ctx.APub.lookupActor(ctx.account.user); + if (!actor) + throw new Error(`Could not look up actor for ${ctx.account.user}`); + + const { TransientNote } = await import("../../models/TransientNote.js"); + transientNoteContent = `Transient note test ${ctx.sessionId}`; + const note = new TransientNote(actor, transientNoteContent); + await ctx.APub.send(note); + }); + + test.sequential("Delivery - TransientNote", { timeout: 30_000 }, async () => { + if (ctx.DRY_SEND) return; + await ctx.testKit.expectToHave(transientNoteContent, 1000); + }); +} + +export function replyScenario(ctx: ScenarioContext): void { + let replyContent: string; + + test.sequential("APub#reply", { timeout: 60_000 }, async () => { + if (ctx.DRY_SEND) return; + + let capturedObject: any = null; + let capturedActor: any = null; + let captureResolve: (value: void) => void; + const captured = new Promise((resolve) => { + captureResolve = resolve; + }); + + global.TEST_FEDERATION_INCOMING_CREATE = (actor: any, object: any) => { + capturedActor = actor; + capturedObject = object; + captureResolve!(); + }; + + try { + await ctx.testKit.send( + ctx.ourHandle, + `Reply test original message ${ctx.sessionId}`, + ); + + await Promise.race([ + captured, + new Promise((_, reject) => + setTimeout( + () => reject(new Error("Timed out waiting for incoming Create")), + 30_000, + ), + ), + ]); + + const { Note, Mention } = await import("@fedify/vocab"); + replyContent = `Reply to real message ${ctx.sessionId}`; + const replyNote = new Note({ + to: capturedActor, + content: replyContent, + published: new Date().toTemporalInstant(), + tags: [ + new Mention({ + href: capturedActor.id!, + name: String(capturedActor.id!), + }), + ], + }); + + await ctx.APub.reply(capturedObject, replyNote); + } finally { + global.TEST_FEDERATION_INCOMING_CREATE = undefined; + } + }); + + test.sequential("Delivery - Reply", { timeout: 30_000 }, async () => { + if (ctx.DRY_SEND) return; + await ctx.testKit.expectToHave(replyContent, 1000); + }); +} + +export function handoffScenario(ctx: ScenarioContext): void { + test.sequential("APub#send via HandoffSession", { timeout: 30_000 }, async () => { + if (ctx.DRY_SEND) return; + const HANDOFF_TOKEN = process.env.HANDOFF_TOKEN!; + await ctx.testKit.send(ctx.ourHandle, HANDOFF_TOKEN); + }); + + test.sequential("Delivery - HandoffSession", { timeout: 60_000 }, async (t) => { + if (ctx.DRY_SEND) return; + await t.annotate("Expecting handoff URL in reply"); + await ctx.testKit.expectToHave("/handoff/", 3000); + }); +} + +export function sidecarScenario(ctx: ScenarioContext): void { + test.sequential("APub#send via SidecarSession", async () => { + if (ctx.DRY_SEND) return; + const { SidecarSession } = await import("../../models/SidecarSession.js"); + const sidecar = await SidecarSession.create("internal"); + await ctx.testKit.send( + ctx.ourHandle, + `${sidecar.id} please authenticate me`, + ); + }); + + test.sequential("Delivery - SidecarSession", { timeout: 60_000 }, async (t) => { + if (ctx.DRY_SEND) return; + await t.annotate("Expecting sidecar authenticated message"); + await ctx.testKit.expectToHave("Authenticated as", 3000); + }); +} \ No newline at end of file diff --git a/package.json b/package.json index a45dc1a..a4a1e39 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "script:setup-jwks": "tsx scripts/setup-jwks.ts" }, "devDependencies": { + "@sc07/fedi-testkit": "file:../fedi-testkit", "tsx": "^4.22.4" } } diff --git a/yarn.lock b/yarn.lock index c4bb103..1d2cb60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1831,12 +1831,23 @@ __metadata: "@sc07/fedi-testkit@file:../../fedi-testkit::locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend": version: 1.1.5 - resolution: "@sc07/fedi-testkit@file:../../fedi-testkit#../../fedi-testkit::hash=ec0c0e&locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend" + resolution: "@sc07/fedi-testkit@file:../../fedi-testkit#../../fedi-testkit::hash=af4c2b&locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend" dependencies: execa: "npm:^9.6.1" puppeteer: "npm:^24.35.0" tsx: "npm:^4.21.0" - checksum: 10c0/2567ac1ed85682dd2dd12b8778f65c814d27260ade89107137b4a4aabbd9ab0cf23cc1af630bf81f38fa6fd5af081eb2d4a67ac5dd9a40a55d1c70e76f5baf0a + checksum: 10c0/beb813c3fd10ed67783d80f134172b0102a433b5e7834df1f7a9d9d6d50c8cd069e678adabd86067556f2c97de4926f427be36d2d45743df2231c5fd63061272 + languageName: node + linkType: hard + +"@sc07/fedi-testkit@file:../fedi-testkit::locator=fediverse-auth%40workspace%3A.": + version: 1.1.5 + resolution: "@sc07/fedi-testkit@file:../fedi-testkit#../fedi-testkit::hash=af4c2b&locator=fediverse-auth%40workspace%3A." + dependencies: + execa: "npm:^9.6.1" + puppeteer: "npm:^24.35.0" + tsx: "npm:^4.21.0" + checksum: 10c0/beb813c3fd10ed67783d80f134172b0102a433b5e7834df1f7a9d9d6d50c8cd069e678adabd86067556f2c97de4926f427be36d2d45743df2231c5fd63061272 languageName: node linkType: hard @@ -4113,6 +4124,7 @@ __metadata: version: 0.0.0-use.local resolution: "fediverse-auth@workspace:." dependencies: + "@sc07/fedi-testkit": "file:../fedi-testkit" tsx: "npm:^4.22.4" languageName: unknown linkType: soft -- GitLab From 0800347b41e5f2c8c5c3a5c626319e4df18991a6 Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Jun 2026 23:07:23 -0600 Subject: [PATCH 4/7] testkit: update ci Assisted-by: deepseek:v4-flash --- .gitlab-ci.yml | 4 + .gitlab/ci/federation_test.yml | 139 +++++++++++++++++++++------------ 2 files changed, 91 insertions(+), 52 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a721923..e318a40 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,10 @@ include: inputs: wiki_token: $CI_PUSH_TOKEN +stages: + - build + - test-federation + build image: stage: build image: docker:latest diff --git a/.gitlab/ci/federation_test.yml b/.gitlab/ci/federation_test.yml index 5b8df64..e239bd3 100644 --- a/.gitlab/ci/federation_test.yml +++ b/.gitlab/ci/federation_test.yml @@ -1,66 +1,101 @@ -# -# TODO: different modes of testing based on branch -# - inside MR: test against testing instances -# - main branch: test against important public instances -# TODO: require manual trigger inside MRs as not every test is needed every commit -# +# Federation test CI jobs. +# Two modes: Docker (MR) / Production (main). -.fed test: &fed_test - stage: test - dependencies: [] +.fed_job: &fed_job + stage: test-federation needs: [] - # image: node:24-alpine image: registry.sc07.dev/sc07/fedi-testkit/node:24-pptr - services: - - name: postgres:14-alpine - alias: postgres - variables: - POSTGRES_HOST_AUTH_METHOD: trust - - name: redis:7-alpine - alias: redis variables: - DATABASE_URL: postgres://postgres@postgres:5432/fediauth - REDIS_URI: redis://redis - SESSION_SECRET: test - TEST_FEDERATION_MODE: KEYRING - PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium-browser - TESTKIT_PUPPETEER_ARGS: --no-sandbox + DATABASE_URL: postgres://postgres@postgres/postgres + REDIS_URI: redis://redis:6379/0 before_script: - - corepack enable && corepack prepare - - yarn - - npx -w backend prisma migrate deploy - - npx -w backend prisma generate + - corepack enable + - yarn workspaces focus @fediverse-auth/backend + - yarn workspace @fediverse-auth/backend prisma generate script: - - yarn workspace @fediverse-auth/backend run ci:test + - yarn workspace @fediverse-auth/backend run ci:test:federation + after_script: + - docker compose -f ./node_modules/@sc07/fedi-testkit/src/docker/compose/${TEST_SOFTWARE}/docker-compose.yml down --volumes --remove-orphans 2>/dev/null || true artifacts: when: always - paths: - - backend/vitest.xml reports: junit: backend/vitest.xml + paths: + - backend/vitest.xml -mr test federation: - when: manual - parallel: - matrix: - - TEST_FEDERATION_KEYRING_SERVICE: - - grants.cafe - - toast.ooo - - piefed.grant.rip - - mbin.grant.rip +.docker_job: &docker_job + <<: *fed_job + variables: + FEDERATION_MODE: docker + services: + - name: docker:dind + - name: postgres:14-alpine + alias: postgres + variables: + POSTGRES_HOST_AUTH_METHOD: trust + - name: redis:7-alpine + alias: redis rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - <<: *fed_test + - if: ${CI_PIPELINE_SOURCE} == "merge_request_event" + when: manual + +mr:federation:mastodon: + <<: *docker_job + variables: + TEST_SOFTWARE: mastodon + +mr:federation:lemmy: + <<: *docker_job + variables: + TEST_SOFTWARE: lemmy -test federation: - parallel: - matrix: - - TEST_FEDERATION_KEYRING_SERVICE: - - mastodon.social - - mastodon.world - - lemmy.world - - piefed.social - - pixelfed.social +mr:federation:piefed: + <<: *docker_job + variables: + TEST_SOFTWARE: piefed + +mr:federation:mbin: + <<: *docker_job + variables: + TEST_SOFTWARE: mbin + +mr:federation:pixelfed: + <<: *docker_job + variables: + TEST_SOFTWARE: pixelfed + +.prod_job: &prod_job + <<: *fed_job + variables: + FEDERATION_MODE: production + TEST_FEDERATION_MODE: KEYRING + services: + - name: postgres:14-alpine + alias: postgres + variables: + POSTGRES_HOST_AUTH_METHOD: trust + - name: redis:7-alpine + alias: redis rules: - - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - <<: *fed_test \ No newline at end of file + - if: ${CI_PIPELINE_SOURCE} == "push" && ${CI_COMMIT_BRANCH} == ${CI_DEFAULT_BRANCH} + when: on_success + +prod:federation:mastodon: + <<: *prod_job + variables: + TEST_FEDERATION_KEYRING_SERVICE: mastodon.social + +prod:federation:lemmy: + <<: *prod_job + variables: + TEST_FEDERATION_KEYRING_SERVICE: lemmy.world + +prod:federation:piefed: + <<: *prod_job + variables: + TEST_FEDERATION_KEYRING_SERVICE: piefed.social + +prod:federation:pixelfed: + <<: *prod_job + variables: + TEST_FEDERATION_KEYRING_SERVICE: pixelfed.social -- GitLab From 70d7e63811d6fdb24a5d39d249575c836f812529 Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Jun 2026 23:29:21 -0600 Subject: [PATCH 5/7] ci: remove curly --- .gitlab/ci/federation_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/federation_test.yml b/.gitlab/ci/federation_test.yml index e239bd3..1ca9c3e 100644 --- a/.gitlab/ci/federation_test.yml +++ b/.gitlab/ci/federation_test.yml @@ -36,7 +36,7 @@ - name: redis:7-alpine alias: redis rules: - - if: ${CI_PIPELINE_SOURCE} == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: manual mr:federation:mastodon: @@ -77,7 +77,7 @@ mr:federation:pixelfed: - name: redis:7-alpine alias: redis rules: - - if: ${CI_PIPELINE_SOURCE} == "push" && ${CI_COMMIT_BRANCH} == ${CI_DEFAULT_BRANCH} + - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: on_success prod:federation:mastodon: -- GitLab From e33dc198c82e05fb6200fe94ebc0ac7544f65a64 Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Jun 2026 23:40:21 -0600 Subject: [PATCH 6/7] remove local path for feditestkit --- backend/package.json | 1 - package.json | 2 +- yarn.lock | 22 +++++----------------- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/backend/package.json b/backend/package.json index 57dcc51..9709eb7 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,7 +14,6 @@ "@js-temporal/polyfill": "^0.5.1", "@logtape/logtape": "^0.9.2", "@prisma/client": "^5.22.0", - "@sc07/fedi-testkit": "file:../../fedi-testkit", "@tsconfig/recommended": "^1.0.13", "body-parser": "^1.20.5", "cookie-parser": "^1.4.7", diff --git a/package.json b/package.json index a4a1e39..c177ca5 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "script:setup-jwks": "tsx scripts/setup-jwks.ts" }, "devDependencies": { - "@sc07/fedi-testkit": "file:../fedi-testkit", + "@sc07/fedi-testkit": "^1.2.5", "tsx": "^4.22.4" } } diff --git a/yarn.lock b/yarn.lock index 1d2cb60..acc5a8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -838,7 +838,6 @@ __metadata: "@js-temporal/polyfill": "npm:^0.5.1" "@logtape/logtape": "npm:^0.9.2" "@prisma/client": "npm:^5.22.0" - "@sc07/fedi-testkit": "file:../../fedi-testkit" "@tsconfig/recommended": "npm:^1.0.13" "@types/cookie-parser": "npm:^1.4.10" "@types/cors": "npm:^2.8.19" @@ -1829,25 +1828,14 @@ __metadata: languageName: node linkType: hard -"@sc07/fedi-testkit@file:../../fedi-testkit::locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend": - version: 1.1.5 - resolution: "@sc07/fedi-testkit@file:../../fedi-testkit#../../fedi-testkit::hash=af4c2b&locator=%40fediverse-auth%2Fbackend%40workspace%3Abackend" - dependencies: - execa: "npm:^9.6.1" - puppeteer: "npm:^24.35.0" - tsx: "npm:^4.21.0" - checksum: 10c0/beb813c3fd10ed67783d80f134172b0102a433b5e7834df1f7a9d9d6d50c8cd069e678adabd86067556f2c97de4926f427be36d2d45743df2231c5fd63061272 - languageName: node - linkType: hard - -"@sc07/fedi-testkit@file:../fedi-testkit::locator=fediverse-auth%40workspace%3A.": - version: 1.1.5 - resolution: "@sc07/fedi-testkit@file:../fedi-testkit#../fedi-testkit::hash=af4c2b&locator=fediverse-auth%40workspace%3A." +"@sc07/fedi-testkit@npm:^1.2.5": + version: 1.2.5 + resolution: "@sc07/fedi-testkit@npm:1.2.5::__archiveUrl=https%3A%2F%2Fsc07.dev%2Fapi%2Fv4%2Fprojects%2F78%2Fpackages%2Fnpm%2F%40sc07%2Ffedi-testkit%2F-%2F%40sc07%2Ffedi-testkit-1.2.5.tgz" dependencies: execa: "npm:^9.6.1" puppeteer: "npm:^24.35.0" tsx: "npm:^4.21.0" - checksum: 10c0/beb813c3fd10ed67783d80f134172b0102a433b5e7834df1f7a9d9d6d50c8cd069e678adabd86067556f2c97de4926f427be36d2d45743df2231c5fd63061272 + checksum: 10c0/d054843791f5446ad6934382c7b7ec7146ee22b1271043fc3bd33a4066e3b0bca5ab9bc20d07d02ef1ad16a6e2721a9b31ddef614f0cc211a519ef4e8c671e39 languageName: node linkType: hard @@ -4124,7 +4112,7 @@ __metadata: version: 0.0.0-use.local resolution: "fediverse-auth@workspace:." dependencies: - "@sc07/fedi-testkit": "file:../fedi-testkit" + "@sc07/fedi-testkit": "npm:^1.2.5" tsx: "npm:^4.22.4" languageName: unknown linkType: soft -- GitLab From c718df8781138e5d3b2c3a61548075084ba431d9 Mon Sep 17 00:00:00 2001 From: Grant Date: Mon, 29 Jun 2026 23:43:36 -0600 Subject: [PATCH 7/7] add feditestkit to backend --- backend/package.json | 1 + yarn.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/package.json b/backend/package.json index 9709eb7..d494c90 100644 --- a/backend/package.json +++ b/backend/package.json @@ -30,6 +30,7 @@ }, "devDependencies": { "@hongminhee/localtunnel": "^0.3.0", + "@sc07/fedi-testkit": "^1.2.5", "@types/cookie-parser": "^1.4.10", "@types/cors": "^2.8.19", "@types/express": "^4.17.25", diff --git a/yarn.lock b/yarn.lock index acc5a8a..f8fccad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -838,6 +838,7 @@ __metadata: "@js-temporal/polyfill": "npm:^0.5.1" "@logtape/logtape": "npm:^0.9.2" "@prisma/client": "npm:^5.22.0" + "@sc07/fedi-testkit": "npm:^1.2.5" "@tsconfig/recommended": "npm:^1.0.13" "@types/cookie-parser": "npm:^1.4.10" "@types/cors": "npm:^2.8.19" -- GitLab