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

CLI v0.4.1 release

nekomimi.pet 0172a31f 0bbe78d5

verified
Changed files
+53 -28
apps
hosting-service
src
main-app
public
editor
tabs
src
binaries
docs
src
content
docs
+4 -3
README.md
···
## Architecture
-
- **`/src`** - Main backend (OAuth, site management, custom domains)
-
- **`/hosting-service`** - Microservice that serves cached sites from disk
+
- **`/apps/main-app`** - Main backend (OAuth, site management, custom domains)
+
- **`/apps/hosting-service`** - Microservice that serves cached sites from disk
- **`/cli`** - Rust CLI for direct PDS uploads
-
- **`/public`** - React frontend
+
- **`/apps/main-app/public`** - React frontend
+
- **`/packages`** - Shared packages
### How it works
+22
apps/hosting-service/src/lib/firehose.ts
···
private idResolver: IdResolver
private isShuttingDown = false
private lastEventTime = Date.now()
+
private cacheCleanupInterval: NodeJS.Timeout | null = null
constructor(
private logger?: (msg: string, data?: Record<string, unknown>) => void
) {
this.idResolver = new IdResolver()
+
this.startCacheCleanup()
}
private log(msg: string, data?: Record<string, unknown>) {
···
log(`[FirehoseWorker] ${msg}`, data || {})
}
+
private startCacheCleanup() {
+
// Clear IdResolver cache every hour to prevent unbounded memory growth
+
// The IdResolver has an internal cache that never expires and can cause heap exhaustion
+
this.cacheCleanupInterval = setInterval(() => {
+
if (this.isShuttingDown) return
+
+
this.log('Clearing IdResolver cache to prevent memory leak')
+
+
// Recreate the IdResolver to clear its internal cache
+
this.idResolver = new IdResolver()
+
+
this.log('IdResolver cache cleared')
+
}, 60 * 60 * 1000) // Every hour
+
}
+
start() {
this.log('Starting firehose worker')
this.connect()
···
stop() {
this.log('Stopping firehose worker')
this.isShuttingDown = true
+
+
if (this.cacheCleanupInterval) {
+
clearInterval(this.cacheCleanupInterval)
+
this.cacheCleanupInterval = null
+
}
if (this.firehose) {
this.firehose.destroy()
+6 -6
apps/main-app/public/editor/tabs/CLITab.tsx
···
<div className="flex items-center gap-2 mb-2">
<CardTitle>Wisp CLI Tool</CardTitle>
<Badge variant="secondary" className="text-xs">
-
v0.4.0
+
v0.4.1
</Badge>
<Badge variant="outline" className="text-xs">
Alpha
···
</div>
<div className="space-y-3">
-
<h3 className="text-sm font-semibold">Download v0.4.0</h3>
+
<h3 className="text-sm font-semibold">Download v0.4.1</h3>
<div className="grid gap-2">
<div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border">
<a
···
</a>
<div className="text-xs text-muted-foreground">
<span className="font-mono">
-
SHA-1: 2b5c1d6d0e21f9d764dd66ef869bfcd348e8a111
+
SHA-1: 69de880e160a2f26e3c26b7c28030457913754dc
</span>
</div>
</div>
···
</a>
<div className="text-xs text-muted-foreground">
<span className="font-mono">
-
SHA-1: 68d4a3831c07d2f32fdde8d3e809af1ab79e804e
+
SHA-1: 026189f2c10077a2be4705102e169e66cb207f84
</span>
</div>
</div>
···
</a>
<div className="text-xs text-muted-foreground">
<span className="font-mono">
-
SHA-1: 86e89f592b0ec53239c082f502cbe7a47ed8bbec
+
SHA-1: 4777cff07558906717402484a3313359880eae96
</span>
</div>
</div>
···
</a>
<div className="text-xs text-muted-foreground">
<span className="font-mono">
-
SHA-1: 227b735911ad260cff5af3ca3beefa4e1e3956a8
+
SHA-1: d6bc789d7fd7c787e5520eb476cee70c97ccb3ce
</span>
</div>
</div>
+9 -7
apps/main-app/src/index.ts
···
}
})
.get('/api/screenshots', async () => {
-
const { Glob } = await import('bun')
-
const glob = new Glob('*.png')
-
-
// Convert async iterator to array using Array.fromAsync
-
const files = glob.scan('./apps/main-app/public/screenshots')
-
const screenshots = await Array.fromAsync(files)
+
const fs = await import('fs/promises')
-
return { screenshots }
+
try {
+
const screenshotsDir = './apps/main-app/public/screenshots'
+
const files = await fs.readdir(screenshotsDir)
+
const screenshots = files.filter(file => file.endsWith('.png'))
+
return { screenshots }
+
} catch (error) {
+
return { screenshots: [] }
+
}
})
.get('/api/admin/test', () => {
return { message: 'Admin routes test works!' }
+6 -6
binaries/index.html
···
</head>
<body>
<div class="container">
-
<h1>Wisp CLI <span style="font-size: 1.5rem; color: var(--demo-text-secondary);">v0.4.0</span></h1>
+
<h1>Wisp CLI <span style="font-size: 1.5rem; color: var(--demo-text-secondary);">v0.4.1</span></h1>
<p class="subtitle">Deploy static sites to the AT Protocol</p>
<div class="description">
···
</div>
<div class="downloads">
-
<h2>Download v0.4.0</h2>
+
<h2>Download v0.4.1</h2>
<a href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwin" class="download-link" download>
<span class="platform">macOS (Apple Silicon):</span> wisp-cli-aarch64-darwin
</a>
···
</a>
<h3 style="margin-top: 1.5rem; margin-bottom: 0.5rem;">SHA-1 Checksums</h3>
-
<pre style="font-size: 0.75rem; padding: 1rem;"><code class="language-bash">2b5c1d6d0e21f9d764dd66ef869bfcd348e8a111 wisp-cli-aarch64-darwin
-
68d4a3831c07d2f32fdde8d3e809af1ab79e804e wisp-cli-aarch64-linux
-
86e89f592b0ec53239c082f502cbe7a47ed8bbec wisp-cli-x86_64-linux
-
227b735911ad260cff5af3ca3beefa4e1e3956a8 wisp-cli-x86_64-windows.exe</code></pre>
+
<pre style="font-size: 0.75rem; padding: 1rem;"><code class="language-bash">69de880e160a2f26e3c26b7c28030457913754dc wisp-cli-aarch64-darwin
+
026189f2c10077a2be4705102e169e66cb207f84 wisp-cli-aarch64-linux
+
4777cff07558906717402484a3313359880eae96 wisp-cli-x86_64-linux
+
d6bc789d7fd7c787e5520eb476cee70c97ccb3ce wisp-cli-x86_64-windows.exe</code></pre>
</div>
<div class="cicd-section">
binaries/wisp-cli-aarch64-darwin

This is a binary file and will not be displayed.

binaries/wisp-cli-aarch64-linux

This is a binary file and will not be displayed.

binaries/wisp-cli-x86_64-linux

This is a binary file and will not be displayed.

binaries/wisp-cli-x86_64-windows.exe

This is a binary file and will not be displayed.

+6 -6
docs/src/content/docs/cli.md
···
---
-
title: Wisp CLI 0.4.0 (alpha)
+
title: Wisp CLI 0.4.1 (alpha)
description: Command-line tool for deploying static sites to the AT Protocol
---
···
<div class="downloads">
-
<h2>Download v0.4.0</h2>
+
<h2>Download v0.4.1</h2>
<a href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwin" class="download-link" download="">
···
<h3 style="margin-top: 1.5rem; margin-bottom: 0.5rem;">SHA-1 Checksums</h3>
<pre style="font-size: 0.75rem; padding: 1rem;" class="language-bash" tabindex="0"><code class="language-bash">
-
2b5c1d6d0e21f9d764dd66ef869bfcd348e8a111 wisp-cli-aarch64-darwin
+
69de880e160a2f26e3c26b7c28030457913754dc wisp-cli-aarch64-darwin
-
68d4a3831c07d2f32fdde8d3e809af1ab79e804e wisp-cli-aarch64-linux
+
026189f2c10077a2be4705102e169e66cb207f84 wisp-cli-aarch64-linux
-
86e89f592b0ec53239c082f502cbe7a47ed8bbec wisp-cli-x86_64-linux
+
4777cff07558906717402484a3313359880eae96 wisp-cli-x86_64-linux
-
227b735911ad260cff5af3ca3beefa4e1e3956a8 wisp-cli-x86_64-windows.exe
+
d6bc789d7fd7c787e5520eb476cee70c97ccb3ce wisp-cli-x86_64-windows.exe
</code></pre>
</div>