ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
16
fork

Configure Feed

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

replace any types with AT Protocol interfaces

Optimization #9:
- created atproto.types.ts with proper AT Protocol interfaces
- replaced 7 any types in batch-search-actors.ts
- added ATProtoActor, ATProtoProfile, RankedActor, EnrichedActor types
- improves type safety, compile-time error catching, IDE support

byarielm.fyi 43710263 65ac8561

verified
+79 -8
+14 -8
netlify/functions/batch-search-actors.ts
··· 1 - import { AuthenticatedHandler } from "./core/types"; 1 + import { 2 + AuthenticatedHandler, 3 + ATProtoActor, 4 + ATProtoProfile, 5 + RankedActor, 6 + EnrichedActor, 7 + } from "./core/types"; 2 8 import { SessionService } from "./services/SessionService"; 3 9 import { successResponse, validateArrayInput, ValidationSchemas } from "./utils"; 4 10 import { withAuthErrorHandling } from "./core/middleware"; ··· 28 34 const normalizedUsername = normalize(username); 29 35 30 36 const rankedActors = response.data.actors 31 - .map((actor: any) => { 37 + .map((actor: ATProtoActor): RankedActor => { 32 38 const handlePart = actor.handle.split(".")[0]; 33 39 const normalizedHandle = normalize(handlePart); 34 40 const normalizedFullHandle = normalize(actor.handle); ··· 51 57 did: actor.did, 52 58 }; 53 59 }) 54 - .filter((actor: any) => actor.matchScore > 0) 55 - .sort((a: any, b: any) => b.matchScore - a.matchScore) 60 + .filter((actor: RankedActor) => actor.matchScore > 0) 61 + .sort((a: RankedActor, b: RankedActor) => b.matchScore - a.matchScore) 56 62 .slice(0, 5); 57 63 58 64 return { ··· 72 78 const results = await Promise.all(searchPromises); 73 79 74 80 const allDids = results 75 - .flatMap((r) => r.actors.map((a: any) => a.did)) 81 + .flatMap((r) => r.actors.map((a: RankedActor) => a.did)) 76 82 .filter((did): did is string => !!did); 77 83 78 84 if (allDids.length > 0) { ··· 89 95 actors: batch, 90 96 }); 91 97 92 - profilesResponse.data.profiles.forEach((profile: any) => { 98 + profilesResponse.data.profiles.forEach((profile: ATProtoProfile) => { 93 99 profileDataMap.set(profile.did, { 94 100 postCount: profile.postsCount || 0, 95 101 followerCount: profile.followersCount || 0, ··· 101 107 } 102 108 103 109 results.forEach((result) => { 104 - result.actors = result.actors.map((actor: any) => { 110 + result.actors = result.actors.map((actor: RankedActor): EnrichedActor => { 105 111 const enrichedData = profileDataMap.get(actor.did); 106 112 return { 107 113 ...actor, ··· 124 130 ); 125 131 126 132 results.forEach((result) => { 127 - result.actors = result.actors.map((actor: any) => ({ 133 + result.actors = result.actors.map((actor: EnrichedActor): EnrichedActor => ({ 128 134 ...actor, 129 135 followStatus: { 130 136 [followLexicon]: followStatus[actor.did] || false,
+64
netlify/functions/core/types/atproto.types.ts
··· 1 + /** 2 + * AT Protocol type definitions 3 + * Based on @atproto/api response schemas 4 + */ 5 + 6 + /** 7 + * Actor profile from app.bsky.actor.searchActors 8 + */ 9 + export interface ATProtoActor { 10 + did: string; 11 + handle: string; 12 + displayName?: string; 13 + avatar?: string; 14 + description?: string; 15 + indexedAt?: string; 16 + labels?: any[]; // Moderation labels 17 + } 18 + 19 + /** 20 + * Detailed profile from app.bsky.actor.getProfiles 21 + */ 22 + export interface ATProtoProfile { 23 + did: string; 24 + handle: string; 25 + displayName?: string; 26 + avatar?: string; 27 + description?: string; 28 + followersCount?: number; 29 + followsCount?: number; 30 + postsCount?: number; 31 + indexedAt?: string; 32 + labels?: any[]; 33 + } 34 + 35 + /** 36 + * Actor with match score (search result) 37 + */ 38 + export interface RankedActor extends ATProtoActor { 39 + matchScore: number; 40 + } 41 + 42 + /** 43 + * Enriched actor with profile data and follow status 44 + */ 45 + export interface EnrichedActor extends RankedActor { 46 + postCount: number; 47 + followerCount: number; 48 + followStatus?: Record<string, boolean>; 49 + } 50 + 51 + /** 52 + * Search actors response 53 + */ 54 + export interface SearchActorsResponse { 55 + actors: ATProtoActor[]; 56 + cursor?: string; 57 + } 58 + 59 + /** 60 + * Get profiles response 61 + */ 62 + export interface GetProfilesResponse { 63 + profiles: ATProtoProfile[]; 64 + }
+1
netlify/functions/core/types/index.ts
··· 1 1 export * from "./database.types"; 2 2 export * from "./api.types"; 3 + export * from "./atproto.types";