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): add hono context types for middleware

- now use appenv interface
- update results and search to use ^

byarielm.fyi 7f060c4f d4eaef6e

verified
+55 -14
+31 -13
packages/api/src/routes/results.ts
··· 7 7 import { authMiddleware } from '../middleware/auth'; 8 8 import { UploadRepository } from '../repositories/UploadRepository'; 9 9 import { SourceAccountRepository } from '../repositories/SourceAccountRepository'; 10 - import { MatchRepository } from '../repositories/MatchRepository'; 10 + import { MatchRepository, UploadDetailRow } from '../repositories/MatchRepository'; 11 11 import { normalize } from '../utils/string.utils'; 12 12 import { ValidationError, NotFoundError } from '../errors'; 13 13 import { z } from 'zod'; 14 + import type { AppEnv } from '../types/hono'; 14 15 15 - const results = new Hono(); 16 + const results = new Hono<AppEnv>(); 16 17 17 18 // Zod schemas for validation 18 19 const searchResultSchema = z.object({ ··· 34 35 ), 35 36 isSearching: z.boolean().optional(), 36 37 error: z.string().optional(), 37 - selectedMatches: z.any().optional(), 38 + selectedMatches: z.record(z.string(), z.boolean()).optional(), 38 39 }); 39 40 40 41 const saveResultsSchema = z.object({ ··· 110 111 .map((result) => { 111 112 const normalized = normalize(result.sourceUser.username); 112 113 const sourceAccountId = sourceAccountIdMap.get(normalized); 114 + if (sourceAccountId === undefined) { 115 + return null; 116 + } 113 117 return { 114 - sourceAccountId: sourceAccountId!, 118 + sourceAccountId, 115 119 sourceDate: result.sourceUser.date, 116 120 }; 117 121 }) 118 - .filter((link) => link.sourceAccountId !== undefined); 122 + .filter((link): link is NonNullable<typeof link> => link !== null); 119 123 120 124 await sourceAccountRepo.linkUserToAccounts(uploadId, userDid, links); 121 125 ··· 153 157 atprotoHandle: match.handle, 154 158 atprotoDisplayName: match.displayName, 155 159 atprotoAvatar: match.avatar, 156 - atprotoDescription: (match as any).description, 160 + atprotoDescription: match.description, 157 161 matchScore: match.matchScore, 158 162 postCount: match.postCount || 0, 159 163 followerCount: match.followerCount || 0, ··· 266 270 const totalPages = Math.ceil(totalUsers / pageSize); 267 271 268 272 // Group results by source username 269 - const groupedResults = new Map<string, any>(); 273 + interface GroupedResult { 274 + sourceUser: { username: string; date: string }; 275 + atprotoMatches: Array<{ 276 + did: string; 277 + handle: string; 278 + displayName: string | null; 279 + matchScore: number; 280 + postCount: number | null; 281 + followerCount: number | null; 282 + foundAt: Date | null; 283 + dismissed: boolean; 284 + followStatus: Record<string, unknown>; 285 + }>; 286 + } 287 + const groupedResults = new Map<string, GroupedResult>(); 270 288 271 - rawResults.forEach((row: any) => { 289 + rawResults.forEach((row: UploadDetailRow) => { 272 290 const username = row.original_username; 273 291 274 292 // Get or create the entry for this username ··· 278 296 userResult = { 279 297 sourceUser: { 280 298 username: username, 281 - date: row.date_on_source || '', 299 + date: row.date_on_source?.toISOString() ?? '', 282 300 }, 283 301 atprotoMatches: [], 284 302 }; ··· 286 304 } 287 305 288 306 // Add the match (if it exists) to the array 289 - if (row.atproto_did) { 307 + if (row.atproto_did && row.atproto_handle) { 290 308 userResult.atprotoMatches.push({ 291 309 did: row.atproto_did, 292 310 handle: row.atproto_handle, 293 311 displayName: row.display_name, 294 - matchScore: row.match_score, 312 + matchScore: row.match_score ?? 0, 295 313 postCount: row.post_count, 296 314 followerCount: row.follower_count, 297 315 foundAt: row.found_at, 298 - dismissed: row.dismissed || false, 299 - followStatus: row.follow_status || {}, 316 + dismissed: row.dismissed ?? false, 317 + followStatus: row.follow_status ?? {}, 300 318 }); 301 319 } 302 320 });
+2 -1
packages/api/src/routes/search.ts
··· 10 10 import { SessionService } from '../services/SessionService'; 11 11 import { FollowService } from '../services/FollowService'; 12 12 import { normalize } from '../utils/string.utils'; 13 + import type { AppEnv } from '../types/hono'; 13 14 14 - const search = new Hono(); 15 + const search = new Hono<AppEnv>(); 15 16 16 17 // Validation schema for batch search request 17 18 const batchSearchSchema = z.object({
+22
packages/api/src/types/hono.ts
··· 1 + /** 2 + * Hono Context Types 3 + * Defines custom variables available in the request context 4 + */ 5 + 6 + /** 7 + * Custom variables set by middleware and available via c.get()/c.set() 8 + */ 9 + export interface AppVariables { 10 + /** User's decentralized identifier, set by authMiddleware */ 11 + did: string; 12 + /** Session ID from the cookie, set by authMiddleware */ 13 + sessionId: string; 14 + } 15 + 16 + /** 17 + * Environment type for the Hono app 18 + * This enables type-safe access to context variables 19 + */ 20 + export interface AppEnv { 21 + Variables: AppVariables; 22 + }