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

fix readme, fix script, add cache observability to dashboard

Changed files
+45 -10
scripts
src
routes
+2 -2
README.md
··· 43 43 44 44 # Hosting service 45 45 cd hosting-service 46 - cargo run 46 + npm run start 47 47 48 48 # CLI 49 49 cd cli ··· 60 60 61 61 - Backend: Bun + Elysia + PostgreSQL 62 62 - Frontend: React 19 + Tailwind 4 + Radix UI 63 - - Hosting: Rust microservice 63 + - Hosting: Node microservice using Hono 64 64 - CLI: Rust + Jacquard (AT Protocol library) 65 65 - Protocol: AT Protocol OAuth + custom lexicons 66 66
+2 -2
scripts/change-admin-password.ts
··· 1 1 // Change admin password 2 - import { adminAuth } from './src/lib/admin-auth' 3 - import { db } from './src/lib/db' 2 + import { adminAuth } from '../src/lib/admin-auth' 3 + import { db } from '../src/lib/db' 4 4 import { randomBytes, createHash } from 'crypto' 5 5 6 6 // Get username and new password from command line
+41 -6
src/routes/admin.ts
··· 106 106 // Get logs from hosting service 107 107 let hostingLogs: any[] = [] 108 108 try { 109 - const hostingPort = process.env.HOSTING_PORT || '3001' 109 + const hostingServiceUrl = process.env.HOSTING_SERVICE_URL || `http://localhost:${process.env.HOSTING_PORT || '3001'}` 110 110 const params = new URLSearchParams() 111 111 if (query.level) params.append('level', query.level as string) 112 112 if (query.service) params.append('service', query.service as string) ··· 114 114 if (query.eventType) params.append('eventType', query.eventType as string) 115 115 params.append('limit', String(filter.limit || 100)) 116 116 117 - const response = await fetch(`http://localhost:${hostingPort}/__internal__/observability/logs?${params}`) 117 + const response = await fetch(`${hostingServiceUrl}/__internal__/observability/logs?${params}`) 118 118 if (response.ok) { 119 119 const data = await response.json() 120 120 hostingLogs = data.logs ··· 154 154 // Get errors from hosting service 155 155 let hostingErrors: any[] = [] 156 156 try { 157 - const hostingPort = process.env.HOSTING_PORT || '3001' 157 + const hostingServiceUrl = process.env.HOSTING_SERVICE_URL || `http://localhost:${process.env.HOSTING_PORT || '3001'}` 158 158 const params = new URLSearchParams() 159 159 if (query.service) params.append('service', query.service as string) 160 160 params.append('limit', String(filter.limit || 100)) 161 161 162 - const response = await fetch(`http://localhost:${hostingPort}/__internal__/observability/errors?${params}`) 162 + const response = await fetch(`${hostingServiceUrl}/__internal__/observability/errors?${params}`) 163 163 if (response.ok) { 164 164 const data = await response.json() 165 165 hostingErrors = data.errors ··· 207 207 } 208 208 209 209 try { 210 - const hostingPort = process.env.HOSTING_PORT || '3001' 211 - const response = await fetch(`http://localhost:${hostingPort}/__internal__/observability/metrics?timeWindow=${timeWindow}`) 210 + const hostingServiceUrl = process.env.HOSTING_SERVICE_URL || `http://localhost:${process.env.HOSTING_PORT || '3001'}` 211 + const response = await fetch(`${hostingServiceUrl}/__internal__/observability/metrics?timeWindow=${timeWindow}`) 212 212 if (response.ok) { 213 213 const data = await response.json() 214 214 hostingServiceStats = data.stats ··· 273 273 set.status = 500 274 274 return { 275 275 error: 'Failed to fetch database stats', 276 + message: error instanceof Error ? error.message : String(error) 277 + } 278 + } 279 + }, { 280 + cookie: t.Cookie({ 281 + admin_session: t.Optional(t.String()) 282 + }, { 283 + secrets: cookieSecret, 284 + sign: ['admin_session'] 285 + }) 286 + }) 287 + 288 + // Get cache stats (protected) 289 + .get('/cache', async ({ cookie, set }) => { 290 + const check = requireAdmin({ cookie, set }) 291 + if (check) return check 292 + 293 + try { 294 + const hostingServiceUrl = process.env.HOSTING_SERVICE_URL || `http://localhost:${process.env.HOSTING_PORT || '3001'}` 295 + const response = await fetch(`${hostingServiceUrl}/__internal__/observability/cache`) 296 + 297 + if (response.ok) { 298 + const data = await response.json() 299 + return data 300 + } else { 301 + set.status = 503 302 + return { 303 + error: 'Failed to fetch cache stats from hosting service', 304 + message: 'Hosting service unavailable' 305 + } 306 + } 307 + } catch (error) { 308 + set.status = 500 309 + return { 310 + error: 'Failed to fetch cache stats', 276 311 message: error instanceof Error ? error.message : String(error) 277 312 } 278 313 }