Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
wisp.place
1import { Elysia } from 'elysia'
2import { requireAuth } from '../lib/wisp-auth'
3import { NodeOAuthClient } from '@atproto/oauth-client-node'
4import { Agent } from '@atproto/api'
5import { deleteSite } from '../lib/db'
6import { logger } from '../lib/logger'
7
8export const siteRoutes = (client: NodeOAuthClient) =>
9 new Elysia({ prefix: '/api/site' })
10 .derive(async ({ cookie }) => {
11 const auth = await requireAuth(client, cookie)
12 return { auth }
13 })
14 .delete('/:rkey', async ({ params, auth }) => {
15 const { rkey } = params
16
17 if (!rkey) {
18 return {
19 success: false,
20 error: 'Site rkey is required'
21 }
22 }
23
24 try {
25 // Create agent with OAuth session
26 const agent = new Agent((url, init) => auth.session.fetchHandler(url, init))
27
28 // Delete the record from AT Protocol
29 try {
30 await agent.com.atproto.repo.deleteRecord({
31 repo: auth.did,
32 collection: 'place.wisp.fs',
33 rkey: rkey
34 })
35 logger.info(`[Site] Deleted site ${rkey} from PDS for ${auth.did}`)
36 } catch (err) {
37 logger.error(`[Site] Failed to delete site ${rkey} from PDS`, err)
38 throw new Error('Failed to delete site from AT Protocol')
39 }
40
41 // Delete from database
42 const result = await deleteSite(auth.did, rkey)
43 if (!result.success) {
44 throw new Error('Failed to delete site from database')
45 }
46
47 logger.info(`[Site] Successfully deleted site ${rkey} for ${auth.did}`)
48
49 return {
50 success: true,
51 message: 'Site deleted successfully'
52 }
53 } catch (err) {
54 logger.error('[Site] Delete error', err)
55 return {
56 success: false,
57 error: err instanceof Error ? err.message : 'Failed to delete site'
58 }
59 }
60 })