Import your Last.fm and Spotify listening history to the AT Protocol network using the fm.teal.alpha.feed.play lexicon.
0
fork

Configure Feed

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

refactor: enhance auth UI with spinners and formatted output

Replace console.log statements with ui utility functions for better UX.

Changes:
- Import ui utilities for consistent formatting
- Use ui.startSpinner/succeedSpinner/failSpinner for async operations
- Use ui.header for section headers
- Use ui.keyValue for credential display
- Add try/catch for better error handling in resolveIdentifier
- Improve error messaging with ui.failSpinner

+33 -23
+33 -23
src/lib/auth.ts
··· 1 1 import { AtpAgent } from '@atproto/api'; 2 2 import { prompt } from '../utils/input.js'; 3 + import * as ui from '../utils/ui.js'; 3 4 4 5 interface ResolvedIdentity { 5 6 did: string; ··· 12 13 * Resolves an AT Protocol identifier (handle or DID) to get PDS information 13 14 */ 14 15 async function resolveIdentifier(identifier: string): Promise<ResolvedIdentity> { 15 - console.log(`Resolving identifier: ${identifier}`); 16 - 17 - const response = await fetch( 18 - `https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(identifier)}` 19 - ); 20 - 21 - if (!response.ok) { 22 - throw new Error(`Failed to resolve identifier: ${response.status} ${response.statusText}`); 23 - } 16 + ui.startSpinner(`Resolving identifier: ${identifier}`); 24 17 25 - const data = await response.json() as ResolvedIdentity; 26 - 27 - if (!data.did || !data.pds) { 28 - throw new Error('Invalid response from identity resolver'); 18 + try { 19 + const response = await fetch( 20 + `https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${encodeURIComponent(identifier)}` 21 + ); 22 + 23 + if (!response.ok) { 24 + throw new Error(`Failed to resolve identifier: ${response.status} ${response.statusText}`); 25 + } 26 + 27 + const data = await response.json() as ResolvedIdentity; 28 + 29 + if (!data.did || !data.pds) { 30 + throw new Error('Invalid response from identity resolver'); 31 + } 32 + 33 + ui.succeedSpinner(`Resolved to PDS: ${data.pds}`); 34 + return data; 35 + } catch (error) { 36 + ui.failSpinner('Failed to resolve identifier'); 37 + throw error; 29 38 } 30 - 31 - console.log(`✓ Resolved to PDS: ${data.pds}`); 32 - return data; 33 39 } 34 40 35 41 /** ··· 40 46 password: string | undefined, 41 47 _resolverUrl?: string // Keep parameter for backwards compatibility but don't use it 42 48 ): Promise<AtpAgent> { 43 - console.log('\n=== ATProto Login ==='); 49 + ui.header('ATProto Login'); 44 50 45 51 // Prompt for missing credentials 46 52 if (!identifier) { 47 53 identifier = await prompt('Handle or DID: '); 48 54 } else { 49 - console.log(`Handle or DID: ${identifier}`); 55 + ui.keyValue('Handle or DID', identifier); 50 56 } 51 57 52 58 if (!password) { 53 59 password = await prompt('App password: ', true); 54 60 } else { 55 - console.log('App password: [hidden]'); 61 + ui.keyValue('App password', '[hidden]'); 56 62 } 63 + 64 + console.log(''); 57 65 58 66 try { 59 67 // Resolve the identifier to get PDS and other info 60 68 const resolved = await resolveIdentifier(identifier); 61 69 62 70 // Initialize the agent with the resolved PDS URL 71 + ui.startSpinner('Logging in...'); 63 72 const agent = new AtpAgent({ 64 73 service: resolved.pds, 65 74 }); ··· 70 79 password: password, 71 80 }); 72 81 73 - console.log('✓ Logged in successfully!'); 74 - console.log(` DID: ${agent.session?.did}`); 75 - console.log(` Handle: ${agent.session?.handle}\n`); 82 + ui.succeedSpinner('Logged in successfully!'); 83 + ui.keyValue('DID', agent.session?.did || 'unknown'); 84 + ui.keyValue('Handle', agent.session?.handle || 'unknown'); 85 + console.log(''); 76 86 77 87 return agent; 78 88 } catch (error) { 79 89 const err = error as Error; 80 - console.error('✗ Login failed:', err.message); 90 + ui.failSpinner('Login failed'); 81 91 82 92 // Provide more specific error messages 83 93 if (err.message.includes('Failed to resolve identifier')) {