Monorepo for Aesthetic.Computer aesthetic.computer
at main 122 lines 4.5 kB view raw
1#!/usr/bin/env node 2 3/** 4 * Query P console.log('═══════════════════════════════════════') 5 console.log('Profile Information') 6 console.log('═══════════════════════════════════════') 7 console.log(`Handle: ${p.handle}`) 8 console.log(`DID: ${p.did}`) 9 console.log(`Display Name: ${p.displayName || '(not set)'}`) 10 console.log(`Description: ${p.description || '(not set)'}`) 11 console.log(`Followers: ${p.followersCount || 0}`) 12 console.log(`Following: ${p.followsCount || 0}`) 13 console.log(`Posts: ${p.postsCount || 0}`)* Introspective tool to query ATProto profile information. 14 * 15 * Usage: 16 * node query-profile.mjs aesthetic.computer 17 * node query-profile.mjs did:plc:z72i7hdynmk6r22z27h6tvur 18 */ 19 20import { AtpAgent } from '@atproto/api' 21import { config } from 'dotenv' 22 23config() // Load .env if it exists 24 25const BSKY_SERVICE = process.env.BSKY_SERVICE || 'https://public.api.bsky.app' 26 27async function queryProfile(actor) { 28 console.log(`\n🔍 Querying profile for: ${actor}`) 29 console.log(`📡 Using service: ${BSKY_SERVICE}\n`) 30 31 const agent = new AtpAgent({ service: BSKY_SERVICE }) 32 33 try { 34 // Use unauthenticated API endpoint 35 const response = await fetch(`${BSKY_SERVICE}/xrpc/app.bsky.actor.getProfile?actor=${actor}`) 36 37 if (!response.ok) { 38 throw new Error(`HTTP ${response.status}: ${response.statusText}`) 39 } 40 41 const profile = await response.json() 42 const p = profile 43 44 console.log('═══════════════════════════════════════') 45 console.log('Profile Information') 46 console.log('═══════════════════════════════════════') 47 console.log(`Handle: ${p.handle}`) 48 console.log(`DID: ${p.did}`) 49 console.log(`Display Name: ${p.displayName || '(not set)'}`) 50 console.log(`Description: ${p.description || '(not set)'}`) 51 console.log(`Followers: ${p.followersCount || 0}`) 52 console.log(`Following: ${p.followsCount || 0}`) 53 console.log(`Posts: ${p.postsCount || 0}`) 54 55 if (p.avatar) { 56 console.log(`Avatar: ${p.avatar}`) 57 } 58 59 if (p.banner) { 60 console.log(`Banner: ${p.banner}`) 61 } 62 63 if (p.indexedAt) { 64 console.log(`Indexed: ${new Date(p.indexedAt).toLocaleString()}`) 65 } 66 67 console.log('═══════════════════════════════════════\n') 68 69 // Get some recent posts 70 console.log('📝 Recent Posts (last 5):\n') 71 const feedResponse = await fetch(`${BSKY_SERVICE}/xrpc/app.bsky.feed.getAuthorFeed?actor=${actor}&limit=5`) 72 73 if (feedResponse.ok) { 74 const feedData = await feedResponse.json() 75 76 if (!feedData.feed || feedData.feed.length === 0) { 77 console.log(' (no posts yet)') 78 } else { 79 feedData.feed.forEach((item, i) => { 80 const post = item.post 81 const text = post.record.text || '(no text)' 82 const date = new Date(post.indexedAt).toLocaleDateString() 83 const likes = post.likeCount || 0 84 const replies = post.replyCount || 0 85 const reposts = post.repostCount || 0 86 87 console.log(`${i + 1}. [${date}] ${text.slice(0, 60)}${text.length > 60 ? '...' : ''}`) 88 console.log(` ❤️ ${likes} 💬 ${replies} 🔁 ${reposts}`) 89 console.log(` URI: ${post.uri}\n`) 90 }) 91 } 92 } else { 93 console.log(' (could not fetch posts)') 94 } 95 96 return profile 97 98 } catch (error) { 99 console.error('❌ Error querying profile:', error.message) 100 101 if (error.status === 400) { 102 console.error('\n💡 Tip: Make sure the handle or DID is valid') 103 console.error(' Examples: aesthetic.computer, did:plc:...') 104 } 105 106 process.exit(1) 107 } 108} 109 110// CLI 111const actor = process.argv[2] 112 113if (!actor) { 114 console.error('Usage: node query-profile.mjs <handle-or-did>') 115 console.error('\nExamples:') 116 console.error(' node query-profile.mjs aesthetic.computer') 117 console.error(' node query-profile.mjs bsky.app') 118 console.error(' node query-profile.mjs did:plc:z72i7hdynmk6r22z27h6tvur') 119 process.exit(1) 120} 121 122queryProfile(actor)