diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts
index d939266207..720249ef53 100644
--- a/packages/backend-rs/index.d.ts
+++ b/packages/backend-rs/index.d.ts
@@ -412,6 +412,13 @@ export declare function fetchMeta(): Promise
/** Fetches and returns the NodeInfo (version 2.0) of a remote server. */
export declare function fetchNodeinfo(host: string): Promise
+export interface Follow {
+ id: string
+ type: Activity
+ actor: string
+ object: string
+}
+
export interface Following {
id: string
createdAt: DateTimeWithTimeZone
@@ -425,13 +432,6 @@ export interface Following {
followeeSharedInbox: string | null
}
-export interface FollowRelay {
- id: string
- type: Activity
- actor: string
- object: string
-}
-
export interface FollowRequest {
id: string
createdAt: DateTimeWithTimeZone
@@ -1265,7 +1265,9 @@ export type RelayStatus = 'accepted'|
/** Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago */
export declare function removeOldAttestationChallenges(): Promise
-export declare function renderFollowRelay(relayId: string): Promise
+export declare function renderFollow(follower: UserLike, followee: UserLike, requestId?: string | undefined | null): Follow
+
+export declare function renderFollowRelay(relayId: string): Promise
export interface RenoteMuting {
id: string
@@ -1537,6 +1539,12 @@ export interface UserKeypair {
privateKey: string
}
+export interface UserLike {
+ id: string
+ host: string | null
+ uri: string
+}
+
export interface UserList {
id: string
createdAt: DateTimeWithTimeZone
diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js
index 9ca4963455..2955ef672d 100644
--- a/packages/backend-rs/index.js
+++ b/packages/backend-rs/index.js
@@ -437,6 +437,7 @@ module.exports.PushNotificationKind = nativeBinding.PushNotificationKind
module.exports.PushSubscriptionType = nativeBinding.PushSubscriptionType
module.exports.RelayStatus = nativeBinding.RelayStatus
module.exports.removeOldAttestationChallenges = nativeBinding.removeOldAttestationChallenges
+module.exports.renderFollow = nativeBinding.renderFollow
module.exports.renderFollowRelay = nativeBinding.renderFollowRelay
module.exports.safeForSql = nativeBinding.safeForSql
module.exports.sendPushNotification = nativeBinding.sendPushNotification
diff --git a/packages/backend-rs/src/federation/activitypub/object/follow.rs b/packages/backend-rs/src/federation/activitypub/object/follow.rs
new file mode 100644
index 0000000000..10ccbcd600
--- /dev/null
+++ b/packages/backend-rs/src/federation/activitypub/object/follow.rs
@@ -0,0 +1,65 @@
+use super::*;
+use crate::{config::CONFIG, federation::internal_actor, misc::user};
+use serde::Serialize;
+
+#[macros::export(object)]
+pub struct UserLike {
+ pub id: String,
+ pub host: Option,
+ pub uri: String,
+}
+
+#[derive(Serialize)]
+#[macros::export(object)]
+pub struct Follow {
+ pub id: String,
+ pub r#type: Activity,
+ pub actor: String,
+ pub object: String,
+}
+
+impl ActivityPubObject for Follow {}
+
+impl Follow {
+ #[allow(dead_code)] // TODO: remove this line
+ fn new(follower: UserLike, followee: UserLike, request_id: Option) -> Self {
+ Self {
+ id: request_id.unwrap_or_else(|| {
+ format!("{}/follows/{}/{}", CONFIG.url, follower.id, followee.id)
+ }),
+ r#type: Activity::Follow,
+ actor: match user::is_local!(follower) {
+ true => format!("{}/users/{}", CONFIG.url, follower.id),
+ false => follower.uri,
+ },
+ object: match user::is_local!(followee) {
+ true => format!("{}/users/{}", CONFIG.url, followee.id),
+ false => followee.uri,
+ },
+ }
+ }
+
+ #[allow(dead_code)] // TODO: remove this line
+ async fn new_relay(relay_id: String) -> Result {
+ Ok(Self {
+ id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id),
+ r#type: Activity::Follow,
+ actor: format!(
+ "{}/users/{}",
+ CONFIG.url,
+ internal_actor::relay::get_id().await?
+ ),
+ object: AS_PUBLIC_URL.to_owned(),
+ })
+ }
+}
+
+#[macros::ts_export]
+pub fn render_follow(follower: UserLike, followee: UserLike, request_id: Option) -> Follow {
+ Follow::new(follower, followee, request_id)
+}
+
+#[macros::ts_export]
+pub async fn render_follow_relay(relay_id: String) -> Result {
+ Follow::new_relay(relay_id).await
+}
diff --git a/packages/backend-rs/src/federation/activitypub/object/mod.rs b/packages/backend-rs/src/federation/activitypub/object/mod.rs
index b245bca98a..7fbd1eebda 100644
--- a/packages/backend-rs/src/federation/activitypub/object/mod.rs
+++ b/packages/backend-rs/src/federation/activitypub/object/mod.rs
@@ -1,4 +1,4 @@
-pub mod relay;
+pub mod follow;
pub trait ActivityPubObject {}
@@ -7,3 +7,5 @@ pub trait ActivityPubObject {}
pub enum Activity {
Follow,
}
+
+const AS_PUBLIC_URL: &str = "https://www.w3.org/ns/activitystreams#Public";
diff --git a/packages/backend-rs/src/federation/activitypub/object/relay.rs b/packages/backend-rs/src/federation/activitypub/object/relay.rs
deleted file mode 100644
index f3d7656564..0000000000
--- a/packages/backend-rs/src/federation/activitypub/object/relay.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use super::*;
-use crate::{config::CONFIG, federation::internal_actor};
-use serde::Serialize;
-
-#[derive(Serialize)]
-#[macros::export(object)]
-pub struct FollowRelay {
- pub id: String,
- pub r#type: Activity,
- pub actor: String,
- pub object: String,
-}
-
-impl ActivityPubObject for FollowRelay {}
-
-#[macros::export(js_name = "renderFollowRelay")]
-pub async fn follow(relay_id: &str) -> Result {
- Ok(FollowRelay {
- id: format!("{}/activities/follow-relay/{}", CONFIG.url, relay_id),
- r#type: Activity::Follow,
- actor: format!(
- "{}/users/{}",
- CONFIG.url,
- internal_actor::relay::get_id().await?
- ),
- object: "https://www.w3.org/ns/activitystreams#Public".to_owned(),
- })
-}
diff --git a/packages/backend-rs/src/misc/user/mod.rs b/packages/backend-rs/src/misc/user/mod.rs
index 16ee43aeca..059f3072c5 100644
--- a/packages/backend-rs/src/misc/user/mod.rs
+++ b/packages/backend-rs/src/misc/user/mod.rs
@@ -1 +1,23 @@
pub mod count;
+
+#[doc(hidden)] // hide the macro in the top doc page
+#[macro_export]
+macro_rules! is_local {
+ ($user_like:expr) => {
+ $user_like.host.is_none()
+ };
+}
+
+#[doc(inline)] // show the macro in the module doc page
+pub use is_local;
+
+#[doc(hidden)] // hide the macro in the top doc page
+#[macro_export]
+macro_rules! is_remote {
+ ($user_like:expr) => {
+ $user_like.host.is_some()
+ };
+}
+
+#[doc(inline)] // show the macro in the module doc page
+pub use is_remote;
diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts
index e9c1b5bd1b..663f9be299 100644
--- a/packages/backend/src/remote/activitypub/models/person.ts
+++ b/packages/backend/src/remote/activitypub/models/person.ts
@@ -207,7 +207,7 @@ export async function createPerson(
try {
const data = await fetch(person.followers, {
headers: { Accept: "application/json" },
- size: 1024 * 1024
+ size: 1024 * 1024,
});
const json_data = JSON.parse(await data.text());
@@ -223,7 +223,7 @@ export async function createPerson(
try {
const data = await fetch(person.following, {
headers: { Accept: "application/json" },
- size: 1024 * 1024
+ size: 1024 * 1024,
});
const json_data = JSON.parse(await data.text());
@@ -492,7 +492,7 @@ export async function updatePerson(
try {
const data = await fetch(person.followers, {
headers: { Accept: "application/json" },
- size: 1024 * 1024
+ size: 1024 * 1024,
});
const json_data = JSON.parse(await data.text());
@@ -508,7 +508,7 @@ export async function updatePerson(
try {
const data = await fetch(person.following, {
headers: { Accept: "application/json" },
- size: 1024 * 1024
+ size: 1024 * 1024,
});
const json_data = JSON.parse(await data.text());
diff --git a/packages/backend/src/remote/activitypub/renderer/follow.ts b/packages/backend/src/remote/activitypub/renderer/follow.ts
deleted file mode 100644
index 30ad799507..0000000000
--- a/packages/backend/src/remote/activitypub/renderer/follow.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { config } from "@/config.js";
-import type { User } from "@/models/entities/user.js";
-import { Users } from "@/models/index.js";
-
-export default (
- follower: { id: User["id"]; host: User["host"]; uri: User["host"] },
- followee: { id: User["id"]; host: User["host"]; uri: User["host"] },
- requestId?: string,
-) => {
- const follow = {
- id: requestId ?? `${config.url}/follows/${follower.id}/${followee.id}`,
- type: "Follow",
- actor: Users.isLocalUser(follower)
- ? `${config.url}/users/${follower.id}`
- : follower.uri,
- object: Users.isLocalUser(followee)
- ? `${config.url}/users/${followee.id}`
- : followee.uri,
- } as any;
-
- return follow;
-};
diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts
index c9d94e9fd6..48ca3e6244 100644
--- a/packages/backend/src/remote/activitypub/resolver.ts
+++ b/packages/backend/src/remote/activitypub/resolver.ts
@@ -6,6 +6,7 @@ import {
isAllowedServer,
isBlockedServer,
isSelfHost,
+ renderFollow,
} from "backend-rs";
import { apGet } from "./request.js";
import type { IObject, ICollection, IOrderedCollection } from "./type.js";
@@ -24,7 +25,6 @@ import { renderPerson } from "@/remote/activitypub/renderer/person.js";
import renderQuestion from "@/remote/activitypub/renderer/question.js";
import renderCreate from "@/remote/activitypub/renderer/create.js";
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import { apLogger } from "@/remote/activitypub/logger.js";
import { IsNull, Not } from "typeorm";
diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts
index 81513f5d89..bc0442d381 100644
--- a/packages/backend/src/server/activitypub.ts
+++ b/packages/backend/src/server/activitypub.ts
@@ -9,7 +9,12 @@ import renderKey from "@/remote/activitypub/renderer/key.js";
import { renderPerson } from "@/remote/activitypub/renderer/person.js";
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
import { inbox as processInbox } from "@/queue/index.js";
-import { fetchMeta, getInstanceActor, isSelfHost } from "backend-rs";
+import {
+ fetchMeta,
+ getInstanceActor,
+ isSelfHost,
+ renderFollow,
+} from "backend-rs";
import {
Notes,
Users,
@@ -24,7 +29,6 @@ import {
checkFetch,
getSignatureUser,
} from "@/remote/activitypub/check-fetch.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import Featured from "./activitypub/featured.js";
import Following from "./activitypub/following.js";
import Followers from "./activitypub/followers.js";
diff --git a/packages/backend/src/services/blocking/create.ts b/packages/backend/src/services/blocking/create.ts
index 1d7b80ffbf..9bc59e70e9 100644
--- a/packages/backend/src/services/blocking/create.ts
+++ b/packages/backend/src/services/blocking/create.ts
@@ -1,5 +1,4 @@
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import { renderUndo } from "@/remote/activitypub/renderer/undo.js";
import { renderBlock } from "@/remote/activitypub/renderer/block.js";
import { deliver } from "@/queue/index.js";
@@ -20,6 +19,7 @@ import {
publishToMainStream,
publishToUserStream,
UserEvent,
+ renderFollow,
} from "backend-rs";
import { getActiveWebhooks } from "@/misc/webhook-cache.js";
import { webhookDeliver } from "@/queue/index.js";
diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts
index 494027a37c..d0bcdd33a4 100644
--- a/packages/backend/src/services/fetch-instance-metadata.ts
+++ b/packages/backend/src/services/fetch-instance-metadata.ts
@@ -156,7 +156,7 @@ async function fetchFaviconUrl(
// TODO
//timeout: 10000,
agent: getAgentByUrl,
- size: 1024 * 1024
+ size: 1024 * 1024,
});
if (favicon.ok) {
diff --git a/packages/backend/src/services/following/create.ts b/packages/backend/src/services/following/create.ts
index aea5bd48a5..c3dc91ff9e 100644
--- a/packages/backend/src/services/following/create.ts
+++ b/packages/backend/src/services/following/create.ts
@@ -1,5 +1,4 @@
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import renderAccept from "@/remote/activitypub/renderer/accept.js";
import renderReject from "@/remote/activitypub/renderer/reject.js";
import { deliver } from "@/queue/index.js";
@@ -23,6 +22,7 @@ import {
publishToMainStream,
publishToUserStream,
UserEvent,
+ renderFollow,
} from "backend-rs";
import { createNotification } from "@/services/create-notification.js";
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
diff --git a/packages/backend/src/services/following/delete.ts b/packages/backend/src/services/following/delete.ts
index 9d0135b81f..e46d8422db 100644
--- a/packages/backend/src/services/following/delete.ts
+++ b/packages/backend/src/services/following/delete.ts
@@ -3,9 +3,9 @@ import {
publishToMainStream,
publishToUserStream,
UserEvent,
+ renderFollow,
} from "backend-rs";
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import { renderUndo } from "@/remote/activitypub/renderer/undo.js";
import renderReject from "@/remote/activitypub/renderer/reject.js";
import { deliver, webhookDeliver } from "@/queue/index.js";
diff --git a/packages/backend/src/services/following/reject.ts b/packages/backend/src/services/following/reject.ts
index 1523573bf9..aaed1df3a8 100644
--- a/packages/backend/src/services/following/reject.ts
+++ b/packages/backend/src/services/following/reject.ts
@@ -1,5 +1,4 @@
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import renderReject from "@/remote/activitypub/renderer/reject.js";
import { deliver, webhookDeliver } from "@/queue/index.js";
import {
@@ -7,6 +6,7 @@ import {
publishToMainStream,
publishToUserStream,
UserEvent,
+ renderFollow,
} from "backend-rs";
import type { ILocalUser, IRemoteUser } from "@/models/entities/user.js";
import { Users, FollowRequests, Followings } from "@/models/index.js";
diff --git a/packages/backend/src/services/following/requests/accept.ts b/packages/backend/src/services/following/requests/accept.ts
index bcd7d2cf4c..81484d6fba 100644
--- a/packages/backend/src/services/following/requests/accept.ts
+++ b/packages/backend/src/services/following/requests/accept.ts
@@ -1,8 +1,7 @@
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import renderAccept from "@/remote/activitypub/renderer/accept.js";
import { deliver } from "@/queue/index.js";
-import { Event, publishToMainStream } from "backend-rs";
+import { Event, publishToMainStream, renderFollow } from "backend-rs";
import { insertFollowingDoc } from "../create.js";
import type { User, CacheableUser } from "@/models/entities/user.js";
import { FollowRequests, Users } from "@/models/index.js";
diff --git a/packages/backend/src/services/following/requests/cancel.ts b/packages/backend/src/services/following/requests/cancel.ts
index eb1b2dcb49..435c86f19b 100644
--- a/packages/backend/src/services/following/requests/cancel.ts
+++ b/packages/backend/src/services/following/requests/cancel.ts
@@ -1,8 +1,7 @@
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import { renderUndo } from "@/remote/activitypub/renderer/undo.js";
import { deliver } from "@/queue/index.js";
-import { Event, publishToMainStream } from "backend-rs";
+import { Event, publishToMainStream, renderFollow } from "backend-rs";
import { IdentifiableError } from "@/misc/identifiable-error.js";
import type { User } from "@/models/entities/user.js";
import { Users, FollowRequests } from "@/models/index.js";
diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts
index 40f383cfd3..cc6b4261eb 100644
--- a/packages/backend/src/services/following/requests/create.ts
+++ b/packages/backend/src/services/following/requests/create.ts
@@ -1,9 +1,8 @@
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
-import renderFollow from "@/remote/activitypub/renderer/follow.js";
import { deliver } from "@/queue/index.js";
import type { User } from "@/models/entities/user.js";
import { Blockings, FollowRequests, Users } from "@/models/index.js";
-import { Event, genIdAt, publishToMainStream } from "backend-rs";
+import { Event, genIdAt, publishToMainStream, renderFollow } from "backend-rs";
import { createNotification } from "@/services/create-notification.js";
import { config } from "@/config.js";