Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place
96
fork

Configure Feed

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

at v1.0.0 100 lines 2.8 kB view raw
1import { Elysia } from 'elysia' 2import { requireAuth } from '../lib/wisp-auth' 3import { NodeOAuthClient } from '@atproto/oauth-client-node' 4import { Agent } from '@atproto/api' 5import { getSitesByDid, getDomainByDid, getCustomDomainsByDid, getWispDomainInfo } from '../lib/db' 6import { syncSitesFromPDS } from '../lib/sync-sites' 7import { logger } from '../lib/logger' 8 9export const userRoutes = (client: NodeOAuthClient) => 10 new Elysia({ prefix: '/api/user' }) 11 .derive(async ({ cookie }) => { 12 const auth = await requireAuth(client, cookie) 13 return { auth } 14 }) 15 .get('/status', async ({ auth }) => { 16 try { 17 // Check if user has any sites 18 const sites = await getSitesByDid(auth.did) 19 20 // Check if user has claimed a domain 21 const domain = await getDomainByDid(auth.did) 22 23 return { 24 did: auth.did, 25 hasSites: sites.length > 0, 26 hasDomain: !!domain, 27 domain: domain || null, 28 sitesCount: sites.length 29 } 30 } catch (err) { 31 logger.error('[User] Status error', err) 32 throw new Error('Failed to get user status') 33 } 34 }) 35 .get('/info', async ({ auth }) => { 36 try { 37 // Get user's handle from AT Protocol 38 const agent = new Agent((url, init) => auth.session.fetchHandler(url, init)) 39 40 let handle = 'unknown' 41 try { 42 const profile = await agent.getProfile({ actor: auth.did }) 43 handle = profile.data.handle 44 } catch (err) { 45 logger.error('[User] Failed to fetch profile', err) 46 } 47 48 return { 49 did: auth.did, 50 handle 51 } 52 } catch (err) { 53 logger.error('[User] Info error', err) 54 throw new Error('Failed to get user info') 55 } 56 }) 57 .get('/sites', async ({ auth }) => { 58 try { 59 const sites = await getSitesByDid(auth.did) 60 return { sites } 61 } catch (err) { 62 logger.error('[User] Sites error', err) 63 throw new Error('Failed to get sites') 64 } 65 }) 66 .get('/domains', async ({ auth }) => { 67 try { 68 // Get wisp.place subdomain with mapping 69 const wispDomainInfo = await getWispDomainInfo(auth.did) 70 71 // Get custom domains 72 const customDomains = await getCustomDomainsByDid(auth.did) 73 74 return { 75 wispDomain: wispDomainInfo ? { 76 domain: wispDomainInfo.domain, 77 rkey: wispDomainInfo.rkey || null 78 } : null, 79 customDomains 80 } 81 } catch (err) { 82 logger.error('[User] Domains error', err) 83 throw new Error('Failed to get domains') 84 } 85 }) 86 .post('/sync', async ({ auth }) => { 87 try { 88 logger.debug('[User] Manual sync requested for', auth.did) 89 const result = await syncSitesFromPDS(auth.did, auth.session) 90 91 return { 92 success: true, 93 synced: result.synced, 94 errors: result.errors 95 } 96 } catch (err) { 97 logger.error('[User] Sync error', err) 98 throw new Error('Failed to sync sites') 99 } 100 })