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.

fix(api): type safety

byarielm.fyi f11dbf27 abfef83d

verified
+36 -9
+10 -6
packages/api/src/repositories/BaseRepository.ts
··· 23 23 * const [col1, col2] = buildArraysByColumn(['col1', 'col2'], rows); 24 24 * // col1 = ['val1', 'val3'], col2 = ['val2', 'val4'] 25 25 */ 26 - protected buildArraysByColumn<T extends any[]>( 26 + protected buildArraysByColumn<T extends unknown[]>( 27 27 columns: string[], 28 28 rows: T[], 29 - ): any[][] { 29 + ): unknown[][] { 30 30 return columns.map((_, colIndex) => rows.map((row) => row[colIndex])); 31 31 } 32 32 ··· 39 39 * const map = buildIdMap(results, 'username', 'id'); 40 40 * // map.get('alice') === 1 41 41 */ 42 - protected buildIdMap<T extends Record<string, any>>( 42 + protected buildIdMap<T extends Record<string, string | number>>( 43 43 results: T[], 44 - keyField: string, 45 - valueField: string = 'id', 44 + keyField: keyof T, 45 + valueField: keyof T = 'id' as keyof T, 46 46 ): Map<string, number> { 47 47 const map = new Map<string, number>(); 48 48 for (const row of results) { 49 - map.set(row[keyField], row[valueField]); 49 + const key = row[keyField]; 50 + const value = row[valueField]; 51 + if (typeof key === 'string' && typeof value === 'number') { 52 + map.set(key, value); 53 + } 50 54 } 51 55 return map; 52 56 }
+22 -2
packages/api/src/repositories/MatchRepository.ts
··· 6 6 import { BaseRepository } from './BaseRepository'; 7 7 import { sql } from 'kysely'; 8 8 9 + /** Row shape returned by getUploadDetails query */ 10 + export interface UploadDetailRow { 11 + original_username: string; 12 + normalized_username: string; 13 + date_on_source: Date | null; 14 + atproto_did: string | null; 15 + atproto_handle: string | null; 16 + display_name: string | null; 17 + match_score: number | null; 18 + post_count: number | null; 19 + follower_count: number | null; 20 + found_at: Date | null; 21 + follow_status: Record<string, unknown> | null; 22 + dismissed: boolean | null; 23 + is_new_match: number; 24 + } 25 + 9 26 export class MatchRepository extends BaseRepository { 10 27 /** 11 28 * Store a single match (actor found on Bluesky) ··· 46 63 .returning('id') 47 64 .executeTakeFirst(); 48 65 49 - return result!.id; 66 + if (!result) { 67 + throw new Error('Failed to store match: no result returned from insert'); 68 + } 69 + return result.id; 50 70 } 51 71 52 72 /** ··· 130 150 page: number = 1, 131 151 pageSize: number = 50, 132 152 ): Promise<{ 133 - results: any[]; 153 + results: UploadDetailRow[]; 134 154 totalUsers: number; 135 155 }> { 136 156 // First, verify upload belongs to user
+4 -1
packages/api/src/repositories/SourceAccountRepository.ts
··· 35 35 .returning('id') 36 36 .executeTakeFirst(); 37 37 38 - return result!.id; 38 + if (!result) { 39 + throw new Error('Failed to get or create source account: no result returned'); 40 + } 41 + return result.id; 39 42 } 40 43 41 44 /**