This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

filter out known bots from feeds by default

+86 -1
+2
src/modules/feeds/application/useCases/queries/GetFollowingFeedUseCase.ts
··· 37 37 urlType?: string; // Filter by URL type 38 38 source?: ActivitySource; // Filter by activity source 39 39 activityTypes?: string[]; // Filter by activity types 40 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 40 41 } 41 42 42 43 // Use the shared API type directly ··· 110 111 urlType, 111 112 source: query.source, 112 113 activityTypes, 114 + includeKnownBots: query.includeKnownBots, 113 115 }, 114 116 ); 115 117
+2
src/modules/feeds/application/useCases/queries/GetGemActivityFeedUseCase.ts
··· 36 36 urlType?: string; // Filter by URL type 37 37 source?: ActivitySource; // Filter by activity source 38 38 activityTypes?: string[]; // Filter by activity types 39 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 39 40 } 40 41 41 42 // Use the shared API type directly ··· 160 161 urlType, 161 162 source: query.source, 162 163 activityTypes, 164 + includeKnownBots: query.includeKnownBots, 163 165 }); 164 166 165 167 if (feedResult.isErr()) {
+2
src/modules/feeds/application/useCases/queries/GetGlobalFeedUseCase.ts
··· 39 39 urlType?: string; // Filter by URL type 40 40 source?: ActivitySource; // Filter by activity source 41 41 activityTypes?: string[]; // Filter by activity types 42 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 42 43 } 43 44 44 45 // Use the shared API type directly ··· 111 112 urlType, 112 113 source: query.source, 113 114 activityTypes, 115 + includeKnownBots: query.includeKnownBots, 114 116 }); 115 117 116 118 if (feedResult.isErr()) {
+1
src/modules/feeds/domain/IFeedRepository.ts
··· 13 13 urlType?: UrlType; // Filter by URL type 14 14 source?: ActivitySource; // Filter by activity source 15 15 activityTypes?: ActivityTypeEnum[]; // Filter by activity types 16 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 16 17 } 17 18 18 19 export interface PaginatedFeedResult {
+9
src/modules/feeds/infrastructure/http/controllers/GetFollowingFeedController.ts
··· 19 19 if (!val) return undefined; 20 20 return Array.isArray(val) ? val : [val]; 21 21 }), 22 + includeKnownBots: z 23 + .union([z.boolean(), z.string()]) 24 + .optional() 25 + .transform((val) => { 26 + if (val === undefined) return false; // Default to false 27 + if (typeof val === 'boolean') return val; 28 + return val === 'true'; // Convert string to boolean 29 + }), 22 30 }); 23 31 24 32 export class GetFollowingFeedController extends Controller { ··· 50 58 urlType: params.urlType, 51 59 source: params.source, 52 60 activityTypes: params.activityTypes, 61 + includeKnownBots: params.includeKnownBots, 53 62 }); 54 63 55 64 if (result.isErr()) {
+9
src/modules/feeds/infrastructure/http/controllers/GetGemActivityFeedController.ts
··· 19 19 if (!val) return undefined; 20 20 return Array.isArray(val) ? val : [val]; 21 21 }), 22 + includeKnownBots: z 23 + .union([z.boolean(), z.string()]) 24 + .optional() 25 + .transform((val) => { 26 + if (val === undefined) return false; // Default to false 27 + if (typeof val === 'boolean') return val; 28 + return val === 'true'; // Convert string to boolean 29 + }), 22 30 }); 23 31 24 32 export class GetGemActivityFeedController extends Controller { ··· 45 53 urlType: params.urlType, 46 54 source: params.source, 47 55 activityTypes: params.activityTypes, 56 + includeKnownBots: params.includeKnownBots, 48 57 }); 49 58 50 59 if (result.isErr()) {
+9
src/modules/feeds/infrastructure/http/controllers/GetGlobalFeedController.ts
··· 19 19 if (!val) return undefined; 20 20 return Array.isArray(val) ? val : [val]; 21 21 }), 22 + includeKnownBots: z 23 + .union([z.boolean(), z.string()]) 24 + .optional() 25 + .transform((val) => { 26 + if (val === undefined) return false; // Default to false 27 + if (typeof val === 'boolean') return val; 28 + return val === 'true'; // Convert string to boolean 29 + }), 22 30 }); 23 31 24 32 export class GetGlobalFeedController extends Controller { ··· 45 53 urlType: params.urlType, 46 54 source: params.source, 47 55 activityTypes: params.activityTypes, 56 + includeKnownBots: params.includeKnownBots, 48 57 }); 49 58 50 59 if (result.isErr()) {
+31 -1
src/modules/feeds/infrastructure/repositories/DrizzleFeedRepository.ts
··· 1 - import { eq, desc, lt, count, sql, and, gte, inArray } from 'drizzle-orm'; 1 + import { 2 + eq, 3 + desc, 4 + lt, 5 + count, 6 + sql, 7 + and, 8 + gte, 9 + inArray, 10 + notInArray, 11 + } from 'drizzle-orm'; 2 12 import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; 3 13 import { 4 14 IFeedRepository, ··· 19 29 import { CardId } from '../../../cards/domain/value-objects/CardId'; 20 30 import { ActivityTypeEnum } from '../../domain/value-objects/ActivityType'; 21 31 import { ActivitySource } from '@semble/types'; 32 + import { KNOWN_BOT_DIDS } from '../../../../shared/constants/knownBots'; 22 33 23 34 export class DrizzleFeedRepository implements IFeedRepository { 24 35 constructor(private db: PostgresJsDatabase) {} ··· 90 101 whereConditions.push(eq(feedActivities.source, options.source)); 91 102 } 92 103 } 104 + // Filter out known bots by default (unless explicitly included) 105 + if (!options.includeKnownBots && KNOWN_BOT_DIDS.length > 0) { 106 + whereConditions.push( 107 + notInArray(feedActivities.actorId, KNOWN_BOT_DIDS), 108 + ); 109 + } 93 110 94 111 if (beforeActivityId) { 95 112 // Get the timestamp of the beforeActivityId ··· 251 268 // Direct match for other sources (e.g., ActivitySource.MARGIN) 252 269 whereConditions.push(eq(feedActivities.source, options.source)); 253 270 } 271 + } 272 + // Filter out known bots by default (unless explicitly included) 273 + if (!options.includeKnownBots && KNOWN_BOT_DIDS.length > 0) { 274 + whereConditions.push( 275 + notInArray(feedActivities.actorId, KNOWN_BOT_DIDS), 276 + ); 254 277 } 255 278 256 279 // Create the JSON array condition using jsonb_array_elements_text ··· 513 536 } else { 514 537 whereConditions.push(eq(feedActivities.source, options.source)); 515 538 } 539 + } 540 + 541 + // Filter out known bots by default (unless explicitly included) 542 + if (!options.includeKnownBots && KNOWN_BOT_DIDS.length > 0) { 543 + whereConditions.push( 544 + notInArray(feedActivities.actorId, KNOWN_BOT_DIDS), 545 + ); 516 546 } 517 547 518 548 // Cursor-based pagination
+12
src/shared/constants/knownBots.ts
··· 1 + /** 2 + * List of known bot DIDs that should be filtered from feeds by default 3 + * 4 + * To add a new bot DID, append it to this array. 5 + * To remove a bot from the filter list, remove its DID from this array. 6 + */ 7 + export const KNOWN_BOT_DIDS: string[] = [ 8 + 'did:plc:4j7exarb62djxycrgdfhuulr', // sensemaker.computer 9 + 'did:plc:65sucjiel52gefhcdcypynsr', // phi.zzstoatzz.io 10 + 'did:plc:mxzuau6m53jtdsbqe6f4laov', // void.comind.network 11 + 'did:plc:lchy7sgr7rl42qqzquljpdbq', // dot.atdot.fyi 12 + ];
+3
src/types/src/api/requests.ts
··· 129 129 urlType?: UrlType; // Filter by URL type 130 130 source?: ActivitySource; // Filter by activity source 131 131 activityTypes?: string[]; // Filter by activity types 132 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 132 133 } 133 134 134 135 export interface GetFollowingFeedParams extends PaginationParams { ··· 136 137 urlType?: UrlType; // Filter by URL type 137 138 source?: ActivitySource; // Filter by activity source 138 139 activityTypes?: string[]; // Filter by activity types 140 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 139 141 } 140 142 141 143 export interface LoginWithAppPasswordRequest { ··· 235 237 urlType?: UrlType; // Filter by URL type 236 238 source?: ActivitySource; // Filter by activity source 237 239 activityTypes?: string[]; // Filter by activity types 240 + includeKnownBots?: boolean; // Include known bots in feed (default: false) 238 241 } 239 242 240 243 export interface SearchCollectionsParams extends PaginatedSortedParams {
+6
src/webapp/api-client/clients/FeedClient.ts
··· 22 22 searchParams.append('activityTypes', type), 23 23 ); 24 24 } 25 + if (params?.includeKnownBots !== undefined) 26 + searchParams.set('includeKnownBots', params.includeKnownBots.toString()); 25 27 26 28 const queryString = searchParams.toString(); 27 29 const endpoint = queryString ··· 44 46 searchParams.append('activityTypes', type), 45 47 ); 46 48 } 49 + if (params?.includeKnownBots !== undefined) 50 + searchParams.set('includeKnownBots', params.includeKnownBots.toString()); 47 51 48 52 const queryString = searchParams.toString(); 49 53 const endpoint = queryString ··· 68 72 searchParams.append('activityTypes', type), 69 73 ); 70 74 } 75 + if (params?.includeKnownBots !== undefined) 76 + searchParams.set('includeKnownBots', params.includeKnownBots.toString()); 71 77 72 78 const queryString = searchParams.toString(); 73 79 const endpoint = queryString