feat(api): Filter remote placeholder users from swarm timeline

- Add sql import from drizzle-orm for advanced query filtering
- Exclude federated/swarm posts by checking for null apId in timeline query
- Filter out remote placeholder users by validating handle doesn't contain @ symbol
- Add clarifying comments explaining local-only post filtering logic
- Improve timeline query to return only posts from local users, preventing remote placeholder user content from appearing in feeds
This commit is contained in:
Christomatt
2026-01-26 19:43:18 +01:00
parent 20055e5d2b
commit c5a5985aa6
+6 -3
View File
@@ -6,7 +6,7 @@
import { NextRequest, NextResponse } from 'next/server'; import { NextRequest, NextResponse } from 'next/server';
import { db, posts, users, media, nodes } from '@/db'; import { db, posts, users, media, nodes } from '@/db';
import { eq, desc, and, isNull, lt } from 'drizzle-orm'; import { eq, desc, and, isNull, lt, sql } from 'drizzle-orm';
export interface SwarmPost { export interface SwarmPost {
id: string; id: string;
@@ -59,9 +59,11 @@ export async function GET(request: NextRequest) {
const nodeIsNsfw = node?.isNsfw ?? false; const nodeIsNsfw = node?.isNsfw ?? false;
// Use query builder for better conditional logic // Use query builder for better conditional logic
// Only return posts from local users (not remote placeholder users)
let whereCondition = and( let whereCondition = and(
isNull(posts.replyToId), // Not a reply isNull(posts.replyToId), // Not a reply
eq(posts.isRemoved, false) // Not removed eq(posts.isRemoved, false), // Not removed
isNull(posts.apId) // Not a federated/swarm post (local posts only)
); );
if (cursor) { if (cursor) {
@@ -75,6 +77,7 @@ export async function GET(request: NextRequest) {
} }
// Get recent public posts (not replies, local users only, not removed) // Get recent public posts (not replies, local users only, not removed)
// Filter out remote placeholder users by checking handle doesn't contain @
const recentPosts = await db const recentPosts = await db
.select({ .select({
id: posts.id, id: posts.id,
@@ -97,7 +100,7 @@ export async function GET(request: NextRequest) {
}) })
.from(posts) .from(posts)
.innerJoin(users, eq(posts.userId, users.id)) .innerJoin(users, eq(posts.userId, users.id))
.where(whereCondition) .where(and(whereCondition, sql`${users.handle} NOT LIKE '%@%'`))
.orderBy(desc(posts.createdAt)) .orderBy(desc(posts.createdAt))
.limit(limit); .limit(limit);