refactor: Migrate from ActivityPub federation to native Swarm network

- Remove ActivityPub infrastructure (webfinger, nodeinfo, inbox, activities, signatures)
- Implement native peer-to-peer Swarm network with gossip protocol
- Replace federated timeline with Swarm timeline aggregating posts from all nodes
- Migrate direct messaging to end-to-end encrypted Swarm Chat system
- Update user interactions (follow, like, repost) to use Swarm protocol
- Add cryptographic key management for DID-based identity system
- Remove server-bound identity model in favor of portable DID identities
- Update documentation to reflect Swarm architecture and capabilities
- Add debug utilities and chat testing tools for Swarm network
- Refactor database schema to support distributed user directory
- Update bot framework to work with Swarm network interactions
- Simplify API routes to use Swarm protocol instead of ActivityPub
- This transition enables true peer-to-peer communication, instant interactions, and encrypted messaging while maintaining sovereign identity through DIDs
This commit is contained in:
Christomatt
2026-01-27 01:27:15 +01:00
parent 6b8eeb6814
commit eb63194c56
49 changed files with 1173 additions and 3559 deletions
+3 -3
View File
@@ -2,7 +2,7 @@
* Bot Manager Service
*
* Core orchestrator for bot lifecycle, configuration, and operations.
* Handles bot CRUD operations, user linking, and ActivityPub key generation.
* Handles bot CRUD operations, user linking, and cryptographic key generation.
*
* Bots are first-class users with their own profiles, handles, and posts.
* Each bot has an owner (human user) who manages it.
@@ -12,7 +12,7 @@
import { db, bots, users, botContentSources, botContentItems, botMentions, botActivityLogs, botRateLimits, follows } from '@/db';
import { eq, and, count } from 'drizzle-orm';
import { generateKeyPair } from '@/lib/activitypub/signatures';
import { generateKeyPair } from '@/lib/crypto/keys';
import {
encryptApiKey,
decryptApiKey,
@@ -333,7 +333,7 @@ export async function createBot(ownerId: string, config: BotCreateInput): Promis
throw new BotHandleTakenError(config.handle);
}
// Generate ActivityPub keys for the bot's user account
// Generate cryptographic keys for the bot's user account
const { publicKey, privateKey } = await generateKeyPair();
// Encrypt the API key and private key
+1 -1
View File
@@ -549,7 +549,7 @@ export async function processAllMentions(botId: string): Promise<MentionResponse
/**
* Store a detected mention in the database.
* Used when mentions are detected from external sources (e.g., ActivityPub).
* Used when mentions are detected from external sources (e.g., swarm nodes).
*
* @param data - Mention data to store
* @returns Created mention
+20 -42
View File
@@ -828,7 +828,7 @@ async function createPostInDatabase(
/**
* Federate a post to remote followers.
* Uses the bot's own user account for federation.
* Uses swarm protocol for delivery to other Synapsis nodes.
* This is a non-blocking operation that runs in the background.
*
* @param post - The post to federate
@@ -861,46 +861,25 @@ async function federatePost(
return;
}
// Import federation modules
const { createCreateActivity } = await import('@/lib/activitypub/activities');
const { getFollowerInboxes, deliverToFollowers } = await import('@/lib/activitypub/outbox');
const nodeDomain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
// Get follower inboxes for the bot's user account
const followerInboxes = await getFollowerInboxes(bot.userId);
if (followerInboxes.length === 0) {
console.log('[Bot Federation] No remote followers to notify');
return;
}
// Use swarm delivery for bot posts
const { deliverPostToSwarmFollowers } = await import('@/lib/swarm/interactions');
// Create ActivityPub Create activity using bot's user account
const createActivity = createCreateActivity(post, botUser, nodeDomain);
const swarmResult = await deliverPostToSwarmFollowers(
bot.userId,
post,
{
handle: botUser.handle,
displayName: botUser.displayName,
avatarUrl: botUser.avatarUrl,
isNsfw: botUser.isNsfw,
},
[], // No media for now
nodeDomain
);
// Get private key for signing from bot's user account
const privateKey = botUser.privateKeyEncrypted;
if (!privateKey) {
console.error('[Bot Federation] Bot user has no private key for signing');
await logActivity(
botId,
'error',
{
type: 'federation',
postId: post.id,
error: 'No private key for signing',
},
false,
'No private key for signing'
);
return;
}
const keyId = `https://${nodeDomain}/users/${botUser.handle}#main-key`;
// Deliver to followers
const result = await deliverToFollowers(createActivity, followerInboxes, privateKey, keyId);
console.log(`[Bot Federation] Post ${post.id} delivered to ${result.delivered}/${followerInboxes.length} inboxes (${result.failed} failed)`);
console.log(`[Bot Swarm] Post ${post.id} delivered to ${swarmResult.delivered} swarm nodes (${swarmResult.failed} failed)`);
// Log federation activity
await logActivity(
@@ -908,16 +887,15 @@ async function federatePost(
'post_created',
{
postId: post.id,
federation: {
delivered: result.delivered,
failed: result.failed,
total: followerInboxes.length,
swarm: {
delivered: swarmResult.delivered,
failed: swarmResult.failed,
},
},
true
);
} catch (error) {
console.error('[Bot Federation] Error federating post:', error);
console.error('[Bot Swarm] Error delivering post:', error);
await logActivity(
botId,