feat: migrate k-ap 0.1.10→0.3.1, fix AP gaps

- split FederationRepository into FollowRepository, ActorRepository, BlocklistRepository, ActivityRepository
- RemoteActor: 5 new fields (bio, banner_url, followers_url, following_url, also_known_as)
- ApObjectHandler split: get_local_objects_page/count_local_posts → ApContentReader trait
- builder API: positional args → named setters
- broadcast_create_note/update_note: add ApVisibility + mentioned_inboxes params
- backfill_outbox → import_remote_outbox
- ApUser: also_known_as Option<String> → Vec<String>, new fields

AP gaps fixed:
- add GET /users/{id}/followers + /following with content negotiation
- wire EventPublisher into builder via FederationEventBridge adapter
- add display_name field full stack (domain→DB→API→AP)
- DB-side outbox pagination (get_local_reviews_page)
- set featured_url on ApUser
This commit is contained in:
2026-05-29 10:42:53 +02:00
parent bace54c552
commit 624cfe5799
32 changed files with 1016 additions and 957 deletions

View File

@@ -1,5 +1,6 @@
pub mod composite_handler;
pub mod event_handler;
pub mod federation_event_bridge;
pub mod objects;
pub mod port;
pub mod remote_review_repository;
@@ -10,8 +11,9 @@ pub mod watchlist_handler;
// Re-export the generic base types that callers need
pub use k_ap::{
ActivityPubService, ApFederationConfig, ApObjectHandler, ApUser, ApUserRepository,
FederationData, FederationRepository, Follower, FollowerStatus, FollowingStatus, RemoteActor,
ActivityPubService, ActivityRepository, ActorRepository, ApContentReader, ApFederationConfig,
ApObjectHandler, ApUser, ApUserRepository, BlocklistRepository, FederationData,
FollowRepository, Follower, FollowerStatus, FollowingStatus, RemoteActor,
};
pub use event_handler::ActivityPubEventHandler;
@@ -27,14 +29,17 @@ pub struct ActivityPubWire {
}
pub async fn wire(
federation_repo: std::sync::Arc<dyn FederationRepository>,
activity_repo: std::sync::Arc<dyn ActivityRepository>,
follow_repo: std::sync::Arc<dyn FollowRepository>,
actor_repo: std::sync::Arc<dyn ActorRepository>,
blocklist_repo: std::sync::Arc<dyn BlocklistRepository>,
review_store: std::sync::Arc<dyn RemoteReviewRepository>,
remote_watchlist_repo: std::sync::Arc<dyn domain::ports::RemoteWatchlistRepository>,
local_ap_content: std::sync::Arc<dyn domain::ports::LocalApContentQuery>,
user_repo: std::sync::Arc<dyn domain::ports::UserRepository>,
base_url: String,
allow_registration: bool,
_event_publisher: std::sync::Arc<dyn domain::ports::EventPublisher>,
event_publisher: std::sync::Arc<dyn domain::ports::EventPublisher>,
) -> anyhow::Result<ActivityPubWire> {
let review_handler = std::sync::Arc::new(ReviewObjectHandler {
content_query: std::sync::Arc::clone(&local_ap_content),
@@ -62,18 +67,28 @@ pub async fn wire(
);
}
let fed_event_bridge = std::sync::Arc::new(
federation_event_bridge::FederationEventBridge::new(event_publisher),
);
let concrete = std::sync::Arc::new(
ActivityPubService::builder(
federation_repo,
std::sync::Arc::new(DomainUserRepoAdapter::new(user_repo, base_url.clone())),
composite,
base_url.clone(),
)
.allow_registration(allow_registration)
.software_name("movies-diary")
.debug(federation_debug)
.build()
.await?,
ActivityPubService::builder(base_url.clone())
.activity_repo(activity_repo)
.follow_repo(follow_repo)
.actor_repo(actor_repo)
.blocklist_repo(blocklist_repo)
.user_repo(std::sync::Arc::new(DomainUserRepoAdapter::new(
user_repo,
base_url.clone(),
)))
.content_reader(composite.clone() as std::sync::Arc<dyn ApContentReader>)
.object_handler(composite as std::sync::Arc<dyn ApObjectHandler>)
.event_publisher(fed_event_bridge)
.allow_registration(allow_registration)
.software_name("movies-diary")
.debug(federation_debug)
.build()
.await?,
);
let router = concrete.router();