postherousgenerate-keys.ts1 match
24console.log('π Generating RSA key pair for ActivityPub HTTP signatures...');
25
26// Generate RSA key pair using Web Crypto API
27const keyPair = await crypto.subtle.generateKey(
28{
postherousACTIVITYPUB.md1 match
286- [WebFinger Specification](https://tools.ietf.org/html/rfc7033)
287- [ActivityStreams Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)
288- [Mastodon API Documentation](https://docs.joinmastodon.org/spec/activitypub/)
289290---
cognitoCallbackREADME.md1 match
9495### Copy Function Not Working
96- Modern browsers require HTTPS for clipboard API
97- Val Town URLs use HTTPS by default, so this should work automatically
26<title>Floating Vertical Stream</title>
27
28<link rel="preconnect" href="https://fonts.googleapis.com">
29<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
30<link href="https://fonts.googleapis.com/css2?family=Black+Ops+One&family=Bungee+Spice&family=Creepster&family=Metal+Mania&family=Nosifier&family=Press+Start+2P&family=Lobster&display=swap" rel="stylesheet">
3132<style>
postherousupload.html4 matches
178
179<div class="mt-4 pt-4 border-t border-gray-300">
180<h4 class="text-sm font-medium text-gray-800 mb-2">API Endpoints</h4>
181<div class="grid md:grid-cols-2 gap-4 text-xs text-gray-600">
182<div>
184</div>
185<div>
186<code class="bg-white p-1 rounded">GET /api/posts/slug/images</code> - Get post images
187</div>
188</div>
383384try {
385const response = await fetch(`/api/images?password=${encodeURIComponent(password)}&limit=${allImagesLimit}&offset=${allImagesOffset}`);
386const data = await response.json();
387586if (altText) formData.append('altText', altText);
587588const response = await fetch('/api/images/upload', {
589method: 'POST',
590body: formData
postheroustest-activitypub-inbox.ts3 matches
96
97// Check activity counts for the post
98const activityResponse = await fetch(`${BASE_URL}/api/posts/test/activities`);
99if (activityResponse.ok) {
100const activityData = await activityResponse.json();
139
140// Check activity counts for the post
141const activityResponse = await fetch(`${BASE_URL}/api/posts/test/activities`);
142if (activityResponse.ok) {
143const activityData = await activityResponse.json();
212// Get final activity counts for test post
213try {
214const activityResponse = await fetch(`${BASE_URL}/api/posts/test/activities`);
215if (activityResponse.ok) {
216const activityData = await activityResponse.json();
postherousSETUP.md5 matches
25- **Individual Posts**: `/post/[slug]` (auto-generated from title)
26- **RSS Feed**: `/rss`
27- **API**: `/api/posts` for JSON data
2829### 3. Current Features
41β **Technical Features**
42- Static HTML generation (no client-side JavaScript)
43- Hono backend API
44- TailwindCSS styling
45- Error handling and logging
118- Check Val Town logs for email processing
119- Use `/health` endpoint for status checks
120- Monitor `/api/posts` for data integrity
121122## Architecture Overview
127Database (SQLite)
128β
129backend/index.ts (HTTP API + HTML Generation)
130β
131Static HTML (TailwindCSS)
144- Check Val Town logs for debugging
145- Use the `/health` endpoint to verify system status
146- Test individual components using the API endpoints
147148Your email blog platform is ready to use! Send your first email to start publishing.
postherousSECURITY.md2 matches
137- Document your allowed email addresses
138139## API Endpoints
140141### Verification Endpoint
151### Security Headers
152All verification pages include:
153- Proper HTML escaping to prevent XSS
154- Responsive design for mobile verification
155- Clear success/error messaging
postherousREADME.md16 matches
2728### Backend (`/backend/`)
29- `index.ts` - Main Hono server with HTML generation and API routes β
30- `database/` - SQLite schema and query functions β
31- `services/` - External service integrations β
125Without BASE_URL set, the system will use the default Val Town URL for ActivityPub federation.
126127## π API Endpoints
128129- `GET /` - Main blog interface (with ActivityPub Link header)
132- `GET /images/:filename` - Serve uploaded images β
133- `GET /rss` - RSS 2.0 feed
134- `GET /api/posts` - JSON API for posts
135- `GET /api/posts/:slug` - JSON API for single post
136- `POST /api/images/upload` - Upload image endpoint β
137- `GET /api/posts/:slug/images` - Get images for a specific post β
138- `GET /api/images/user/:email` - Get images uploaded by a user β
139- `GET /api/images` - Get all images (admin endpoint) β
140- `DELETE /api/images/:filename` - Delete an image β
141- `GET /websub` - WebSub subscription endpoint
142- `GET /.well-known/webfinger` - WebFinger discovery for ActivityPub β
146- `GET /followers` - ActivityPub followers collection (with pagination support) β
147- `GET /followers-list` - Human-readable followers page β
148- `GET /api/followers` - JSON API for followers list β
149- `GET /following` - ActivityPub following collection β
150- `POST /inbox` - ActivityPub inbox (processes Follow, Like, Announce, Undo) β
151- `GET /api/posts/:slug/activities` - Get activity counts (likes, shares, replies) β
152- `GET /verify-email` - Email verification endpoint β
153- `GET /health` - Health check
205- **URL Generation**: Clean `/images/filename` URLs for serving images
206207### Image API Usage
208209```javascript
216formData.append('postSlug', 'my-blog-post'); // optional
217218const response = await fetch('/api/images/upload', {
219method: 'POST',
220body: formData
222223// Get images for a post (no password required)
224const images = await fetch('/api/posts/my-post-slug/images').then(r => r.json());
225226// Get images by user (requires password)
227const userImages = await fetch('/api/images/user/user@example.com?password=your-upload-password').then(r => r.json());
228229// Get all images (requires password)
230const allImages = await fetch('/api/images?password=your-upload-password&limit=50').then(r => r.json());
231```
232
postherousindex.ts16 matches
660});
661662// API: Get all posts
663app.get("/api/posts", async c => {
664try {
665await ensureDbInitialized();
675});
676677// API: Get single post
678app.get("/api/posts/:slug", async c => {
679try {
680await ensureDbInitialized();
696});
697698// // API: Delete posts by author name (for cleanup)
699// app.delete("/api/posts/author/:authorName", async c => {
700// try {
701// await ensureDbInitialized();
831</a>
832<div class="text-sm text-gray-500">
833<a href="/api/followers" class="hover:text-gray-700">JSON API</a>
834<span class="mx-2">β’</span>
835<a href="/followers" class="hover:text-gray-700">ActivityPub</a>
849});
850851// API: Get followers list (human-readable)
852app.get("/api/followers", async c => {
853try {
854await ensureDbInitialized();
875});
876877// API: Get activity counts for a post
878app.get("/api/posts/:slug/activities", async c => {
879try {
880await ensureDbInitialized();
16441645// Upload image endpoint
1646app.post("/api/images/upload", async c => {
1647try {
1648await ensureDbInitialized();
17061707// Get images for a specific post
1708app.get("/api/posts/:slug/images", async c => {
1709try {
1710await ensureDbInitialized();
17331734// Get images uploaded by a user
1735app.get("/api/images/user/:email", async c => {
1736try {
1737await ensureDbInitialized();
17671768// Delete an image
1769app.delete("/api/images/:filename", async c => {
1770try {
1771await ensureDbInitialized();
17911792// Get all images (admin endpoint)
1793app.get("/api/images", async c => {
1794try {
1795await ensureDbInitialized();