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

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
Changed files
+79 -8
netlify
+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";