feat(swarm): Add direct swarm interaction delivery for likes, reposts, and unreosts

- Add swarm post handling to like endpoint with direct delivery to origin node
- Add swarm post handling to repost endpoint with direct delivery to origin node
- Add new unrepost endpoint for removing reposts from swarm posts
- Implement deliverSwarmUnrepost function in interactions library
- Extract swarm domain and post ID validation for all interaction types
- Return appropriate error responses for invalid swarm post IDs
- Log successful swarm interaction deliveries for debugging
- Improve separation between local post and swarm post handling logic
- Enable federated users to interact with remote swarm posts directly without local caching
This commit is contained in:
Christomatt
2026-01-26 13:04:05 +01:00
parent 12f515b7fb
commit f361e13e53
4 changed files with 222 additions and 6 deletions
@@ -0,0 +1,67 @@
/**
* Swarm Unrepost Endpoint
*
* POST: Receive an unrepost from another swarm node
*/
import { NextRequest, NextResponse } from 'next/server';
import { db, posts } from '@/db';
import { eq } from 'drizzle-orm';
import { z } from 'zod';
const swarmUnrepostSchema = z.object({
postId: z.string().uuid(),
unrepost: z.object({
actorHandle: z.string(),
actorNodeDomain: z.string(),
interactionId: z.string(),
timestamp: z.string(),
}),
});
/**
* POST /api/swarm/interactions/unrepost
*
* Receives an unrepost from another swarm node.
*/
export async function POST(request: NextRequest) {
try {
if (!db) {
return NextResponse.json({ error: 'Database not available' }, { status: 503 });
}
const body = await request.json();
const data = swarmUnrepostSchema.parse(body);
// Find the target post
const post = await db.query.posts.findFirst({
where: eq(posts.id, data.postId),
});
if (!post) {
return NextResponse.json({ error: 'Post not found' }, { status: 404 });
}
if (post.isRemoved) {
return NextResponse.json({ error: 'Post not found' }, { status: 404 });
}
// Decrement repost count
await db.update(posts)
.set({ repostsCount: Math.max(0, post.repostsCount - 1) })
.where(eq(posts.id, data.postId));
console.log(`[Swarm] Received unrepost from ${data.unrepost.actorHandle}@${data.unrepost.actorNodeDomain} on post ${data.postId}`);
return NextResponse.json({
success: true,
message: 'Unrepost received',
});
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json({ error: 'Invalid request', details: error.issues }, { status: 400 });
}
console.error('[Swarm] Unrepost error:', error);
return NextResponse.json({ error: 'Failed to process unrepost' }, { status: 500 });
}
}