An entry for the streamplace vod showcase
1
fork

Configure Feed

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

docs: add comprehensive documentation for all components

- Add frontend README with pages, composables, and architecture
- Add runtime README with quick example (docs coming soon)
- Add CLI README with command overview (docs coming soon)
- Update VOD API README with share endpoints
- Mark AppView as work in progress
- Update DESIGN.md with recent decisions (share endpoints, OG images, runner fixes)
- Update main README with correct paths and documentation links

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+325 -28
+24
DESIGN.md
··· 112 112 ### Dokploy Deployment (Mainasara) 113 113 User's platform of choice for Docker deployments. 114 114 115 + ## Social Sharing 116 + 117 + ### Share Endpoints Pattern (Mainasara) 118 + For rich link previews in a static SPA, create server endpoints that return HTML with OG meta tags then redirect to the frontend. The share button copies a link to the server endpoint, not the SPA route. 119 + 120 + ### Simplified OG Images (Claude, with Mainasara's direction) 121 + Initially attempted satori-based OG image generation with custom fonts and layouts. Encountered WASM initialization issues in the Deno sandbox. Simplified to using original thumbnails/avatars directly as OG images, with titles formatted as "Streamhut | \<title\>". 122 + 123 + ## Runner Improvements 124 + 125 + ### Dynamic Imports for Sandbox Compatibility (Claude) 126 + Libraries that access `process.env` at import time break bundle extraction. Solution: use dynamic `import()` inside handlers so the code only runs after permissions are applied. 127 + 128 + ### Merge Env Permissions with Secrets (Claude) 129 + Runner was replacing bundle's declared env permissions with only secret keys. Fixed to merge both - bundles can declare env vars they need (e.g., `JEST_WORKER_ID` for satori) while also getting their secrets. 130 + 131 + ### Don't Cache "Latest" Version Resolution (Claude) 132 + The runner was caching `did/name/latest` -> specific AT URI. After deploying a new version, old URI was served until restart. Fixed by skipping cache when version is `"latest"`. 133 + 134 + ### Robust Version Sorting (Claude) 135 + Use `parseInt()` instead of `Number()` for parsing version strings. Handles edge cases like "1.2.3-beta" correctly. 136 + 115 137 ## Lessons Learned 116 138 117 139 1. **Start simple, add complexity when needed**: Began with synchronous endpoints, added task queue only when resource exhaustion became a problem. ··· 123 145 4. **HLS + ffmpeg + seeking is tricky**: Accurate seeking in HLS streams requires `-ss` after `-i`, not before. Seek times must be clamped to video duration. 124 146 125 147 5. **User-Agent matters**: Some APIs return 403 without a proper User-Agent header. Always set one when making HTTP requests from serverless functions. 148 + 149 + 6. **Keep OG images simple**: Generated images with custom fonts require WASM, font fetching, and complex rendering. Using existing thumbnails/avatars is more reliable and the result is often better anyway.
+39 -28
README.md
··· 34 34 35 35 ``` 36 36 ├── apps/ 37 - │ ├── appview/ # Video indexer - crawls creators, stores in Turso 38 - │ ├── vod/ # Video playback - HLS proxying, thumbnails, sprites 39 - │ └── web/ # React frontend - video player UI 37 + │ ├── backend/ 38 + │ │ ├── api/ # VOD bundle - HLS proxying, thumbnails, sprites, sharing 39 + │ │ └── appview/ # Video indexer - crawls creators, stores in Turso (WIP) 40 + │ └── frontend/ # Nuxt 4 web app - video player UI 40 41 41 42 ├── packages/at-run/ 42 - │ ├── runtime/ # Bundle authoring SDK 43 - │ ├── cli/ # Deploy bundles to PDS 44 - │ ├── runner/ # Execute bundles in Deno sandbox 45 - │ └── lexicons/ # AT Protocol record schemas 43 + │ ├── runtime/ # Bundle authoring SDK 44 + │ ├── cli/ # Deploy bundles to PDS 45 + │ ├── runner/ # Execute bundles in Deno sandbox 46 + │ └── lexicons/ # AT Protocol record schemas 46 47 47 - ├── accelerators/ # GPU compute (Modal.com) 48 - └── DESIGN.md # Architecture decisions 48 + └── DESIGN.md # Architecture decisions 49 49 ``` 50 50 51 51 ## Quick Start ··· 112 112 113 113 ## Bundles 114 114 115 - ### AppView (`streamhut-appview`) 115 + ### VOD (`atmosphereconf-vod`) 116 + 117 + Serves video playback with thumbnails, preview sprites, and social sharing. 118 + 119 + | Endpoint | Description | 120 + |----------|-------------| 121 + | `GET /listVideos` | List videos (from AppView or fallback) | 122 + | `GET /getPlaylist` | HLS master playlist | 123 + | `GET /getThumbnail` | Video thumbnail | 124 + | `GET /getSprite` | Preview sprite sheet | 125 + | `GET /getVtt` | Sprite coordinates | 126 + | `GET /shareVideo` | Share page with OG meta tags | 127 + | `GET /shareCreator` | Creator share page with OG meta tags | 128 + 129 + **Job:** `syncAndProcessVideos` - runs every 10 minutes 130 + 131 + ### AppView (`streamhut-appview`) *(Work in Progress)* 116 132 117 133 Indexes `place.stream.video` records from registered AT Protocol creators. 118 134 ··· 127 143 128 144 **Job:** `syncAllCreators` - runs every 15 minutes 129 145 130 - ### VOD (`atmosphereconf-vod`) 146 + ## Documentation 131 147 132 - Serves video playback with thumbnails and preview sprites. 148 + ### Applications 149 + - [VOD Bundle](./apps/backend/api/README.md) - Video playback API with HLS, thumbnails, and sharing 150 + - [Frontend](./apps/frontend/README.md) - Nuxt 4 web application 151 + - [AppView](./apps/backend/appview/README.md) - Video indexer *(work in progress)* 133 152 134 - | Endpoint | Description | 135 - |----------|-------------| 136 - | `GET /listVideos` | List videos (from AppView or fallback) | 137 - | `GET /getPlaylist` | HLS master playlist | 138 - | `GET /getThumbnail` | Video thumbnail | 139 - | `GET /getSprite` | Preview sprite sheet | 140 - | `GET /getVtt` | Sprite coordinates | 141 - 142 - **Job:** `syncAndProcessVideos` - runs every 10 minutes 143 - 144 - ## Documentation 153 + ### at-run Framework 154 + - [Overview](./packages/at-run/README.md) - Serverless execution on AT Protocol 155 + - [Runner](./packages/at-run/runner/README.md) - HTTP server for bundle execution 156 + - [Runtime](./packages/at-run/runtime/README.md) - Bundle authoring SDK *(docs coming soon)* 157 + - [CLI](./packages/at-run/cli/README.md) - Deployment tool *(docs coming soon)* 145 158 146 - - [AppView Bundle](./apps/appview/README.md) 147 - - [VOD Bundle](./apps/vod/README.md) 148 - - [Frontend](./apps/web/README.md) 149 - - [at-run Framework](./packages/at-run/README.md) 150 - - [Design Decisions](./DESIGN.md) 159 + ### Other 160 + - [Design Decisions](./DESIGN.md) - Architecture decisions and rationale 161 + - [Hosting Guide](./packages/at-run/runner/HOSTING.md) - Deploy your own runner 151 162 152 163 ## Requirements 153 164
+9
apps/backend/api/README.md
··· 43 43 | GET | `/getProfile` | Get creator profile from Bluesky | 44 44 | POST | `/batchProfiles` | Batch fetch multiple profiles | 45 45 46 + ### Social Sharing 47 + 48 + | Method | Endpoint | Description | 49 + |--------|----------|-------------| 50 + | GET | `/shareVideo` | Share page with OG meta tags for videos | 51 + | GET | `/shareCreator` | Share page with OG meta tags for creators | 52 + 53 + The share endpoints return HTML with Open Graph meta tags for rich link previews, then redirect to the frontend. Titles use the format "Streamhut | \<title\>". 54 + 46 55 ## Background Job 47 56 48 57 **`syncAndProcessVideos`** - Runs every 10 minutes
+2
apps/backend/appview/README.md
··· 1 1 # Streamhut AppView 2 2 3 + > **Work in Progress**: This component is under active development and not yet deployed to production. 4 + 3 5 Video indexer for AT Protocol. Crawls registered creators and maintains a searchable index of `place.stream.video` records. 4 6 5 7 ## How It Works
+151
apps/frontend/README.md
··· 1 + # Streamhut Frontend 2 + 3 + Nuxt 4 web application for browsing and watching videos on Streamhut. 4 + 5 + ## Features 6 + 7 + - **Video Playback** - HLS streaming with hls.js 8 + - **Hover Previews** - YouTube-style sprite sheet previews 9 + - **Creator Profiles** - Browse videos by creator 10 + - **Watch History** - Local storage tracking of watched videos 11 + - **Search** - Filter videos by title 12 + - **Social Sharing** - Share videos and creator profiles with rich link previews 13 + - **Responsive Design** - Works on desktop and mobile 14 + 15 + ## Pages 16 + 17 + | Route | Description | 18 + |-------|-------------| 19 + | `/` | Home page with featured video, latest, and recommended sections | 20 + | `/watch?v={uri}` | Video player with related videos sidebar | 21 + | `/profile/{did}` | Creator profile with their videos | 22 + | `/search?q={query}` | Search results | 23 + | `/docs` | Documentation | 24 + 25 + ## Development 26 + 27 + ```bash 28 + # Install dependencies 29 + bun install 30 + 31 + # Start dev server 32 + bun run dev 33 + 34 + # Build for production 35 + bun run build 36 + 37 + # Generate static site 38 + bun run generate 39 + ``` 40 + 41 + ## Configuration 42 + 43 + Create `.env` in the frontend directory: 44 + 45 + ```bash 46 + # Required: at-run runner URL 47 + NUXT_PUBLIC_RUNNER_URL=https://at-run.example.com 48 + 49 + # Required: Bundle path for VOD API 50 + NUXT_PUBLIC_BUNDLE_PATH=/bundle/did:plc:xxx/atmosphereconf-vod/latest 51 + ``` 52 + 53 + ## Architecture 54 + 55 + ``` 56 + apps/frontend/ 57 + ├── app/ 58 + │ ├── pages/ 59 + │ │ ├── index.vue # Home page 60 + │ │ ├── watch.vue # Video player 61 + │ │ ├── search.vue # Search results 62 + │ │ └── profile/ 63 + │ │ └── [did].vue # Creator profile 64 + │ ├── components/ 65 + │ │ └── VideoCard.vue # Video thumbnail with hover preview 66 + │ ├── composables/ 67 + │ │ ├── useApi.ts # VOD API client 68 + │ │ ├── useWatchHistory.ts # Local watch history 69 + │ │ └── useShare.ts # Social sharing utilities 70 + │ └── types/ 71 + │ └── index.ts # TypeScript types 72 + ├── nuxt.config.ts # Nuxt configuration 73 + └── package.json 74 + ``` 75 + 76 + ## Composables 77 + 78 + ### `useApi()` 79 + 80 + API client for the VOD backend. 81 + 82 + ```typescript 83 + const { 84 + listVideos, // Fetch video list 85 + batchCheckMetadata, // Check which videos have thumbnails 86 + batchGetProfiles, // Fetch creator profiles 87 + getPlaylistUrl, // Get HLS playlist URL 88 + formatDuration, // Format nanoseconds to "1:23:45" 89 + } = useApi() 90 + ``` 91 + 92 + ### `useWatchHistory()` 93 + 94 + Track watched videos in localStorage. 95 + 96 + ```typescript 97 + const { 98 + recordWatch, // Record a watch session 99 + getContinueWatching, // Get videos with progress < 90% 100 + sortByRecommendation, // Sort videos by watch history 101 + } = useWatchHistory() 102 + ``` 103 + 104 + ### `useShare()` 105 + 106 + Share videos and creators. 107 + 108 + ```typescript 109 + const { 110 + shareVideo, // Copy/share video link 111 + shareCreator, // Copy/share creator link 112 + } = useShare() 113 + ``` 114 + 115 + ## Video Player 116 + 117 + Uses [hls.js](https://github.com/video-dev/hls.js) for HLS playback: 118 + 119 + ```typescript 120 + import Hls from 'hls.js' 121 + 122 + const hls = new Hls() 123 + hls.loadSource(playlistUrl) 124 + hls.attachMedia(videoElement) 125 + ``` 126 + 127 + ## Hover Previews 128 + 129 + The `VideoCard` component shows sprite previews on hover: 130 + 131 + 1. Fetches sprite VTT from `/getVtt?uri=...` 132 + 2. Parses timestamp-to-coordinates mapping 133 + 3. On hover, cycles through frames using CSS `background-position` 134 + 135 + ## Static Generation 136 + 137 + The app uses `ssr: false` and generates a static SPA: 138 + 139 + ```bash 140 + bun run generate 141 + ``` 142 + 143 + Output goes to `.output/public/` (symlinked to `dist/`). 144 + 145 + ## Styling 146 + 147 + - CSS custom properties for theming (`--bg`, `--text`, `--border`, etc.) 148 + - Dark theme by default 149 + - Instrument Serif for headings 150 + - Inter for body text 151 + - Responsive breakpoints at 600px, 800px, 1000px, 1200px
+38
packages/at-run/cli/README.md
··· 1 + # @at-run/cli 2 + 3 + > **Documentation coming soon** 4 + 5 + Command-line tool for deploying and managing at-run bundles on AT Protocol. 6 + 7 + ## Quick Start 8 + 9 + ```bash 10 + # Install 11 + bun add -g @at-run/cli 12 + 13 + # Login to your PDS 14 + at-run login 15 + 16 + # Deploy a bundle 17 + at-run deploy ./dist/bundle.js --name my-bundle 18 + 19 + # Manage secrets 20 + at-run secrets set my-bundle API_KEY "secret-value" --runner did:plc:runner-did 21 + 22 + # Register jobs 23 + at-run jobs create --bundle my-bundle --job dailySync 24 + ``` 25 + 26 + ## Commands 27 + 28 + | Command | Description | 29 + |---------|-------------| 30 + | `at-run login` | Authenticate with your AT Protocol PDS | 31 + | `at-run deploy` | Deploy a bundle to your PDS | 32 + | `at-run secrets` | Manage encrypted secrets for bundles | 33 + | `at-run jobs` | Manage scheduled jobs | 34 + | `at-run ls` | List deployed bundles | 35 + 36 + ## Full Documentation 37 + 38 + *Coming soon*
+62
packages/at-run/runtime/README.md
··· 1 + # @at-run/runtime 2 + 3 + > **Documentation coming soon** 4 + 5 + SDK for authoring at-run bundles. Provides the core primitives for building serverless functions on AT Protocol. 6 + 7 + ## Quick Example 8 + 9 + ```typescript 10 + import { endpoint, manifest, task, job, v } from "@at-run/runtime" 11 + 12 + // Re-export v for sandbox validation 13 + export { v } 14 + 15 + // Declare bundle metadata and permissions 16 + export const bundle = manifest({ 17 + name: "my-bundle", 18 + description: "Example bundle", 19 + permissions: { 20 + net: ["api.example.com"], 21 + read: ["/tmp/cache/"], 22 + write: ["/tmp/cache/"], 23 + }, 24 + }) 25 + 26 + // Simple endpoint 27 + export const hello = endpoint({ 28 + input: v.object({ name: v.string() }), 29 + handler: async ({ name }) => { 30 + return { message: `Hello, ${name}!` } 31 + }, 32 + }) 33 + 34 + // Background task with concurrency limits 35 + export const processData = task({ 36 + concurrency: 2, 37 + cacheTtl: 3600, 38 + handler: async (input) => { 39 + // Heavy processing... 40 + return { processed: true } 41 + }, 42 + }) 43 + 44 + // Scheduled job 45 + export const dailySync = job({ 46 + description: "Sync data daily", 47 + schedule: { type: "cron", cron: "0 0 * * *" }, 48 + handler: async () => { 49 + // Sync logic... 50 + }, 51 + }) 52 + ``` 53 + 54 + ## Installation 55 + 56 + ```bash 57 + bun add @at-run/runtime 58 + ``` 59 + 60 + ## API Reference 61 + 62 + *Coming soon*