# Foxsky A Bluesky/AT Protocol web client built with React, TypeScript, and Vite. ## Features - **OAuth 2.0 authentication** — Uses `@atproto/oauth-client-browser` for secure, password-less login via your PDS (DPoP-bound tokens, PKCE) - **Custom PDS support** — Works with any AT Protocol PDS, not just `bsky.social` - **Timeline with predictive prefetch** — IntersectionObserver-based infinite scroll with velocity-aware preloading - **Post interactions** — Like, repost, quote, reply, and edit your own posts - **Threaded conversations** — Reddit-style nesting or flat chronological layout - **Image gallery & lightbox** — Multi-image grids with full-screen viewer, keyboard navigation - **Video playback** — HLS streaming via hls.js with custom controls and volume normalization - **Profile views** — Full profile pages, side panel, and hover cards with follow/following state - **Notifications** — Grouped notification display with post previews and avatar stacks - **Search** — Actor autocomplete and post search - **Settings** — Post view mode (page/modal/side panel), reply style, theme, video autoplay - **Dark mode** — System-preference-aware with manual override - **CDN bypass** — Blob URLs rewritten to serve directly from the author's PDS - **Multi-account** — Switch between accounts without re-authenticating ## Prerequisites - Node.js 18+ - npm 9+ ## Getting Started ### Install dependencies ```bash npm install ``` ### Development The dev server binds to `127.0.0.1` (required for AT Protocol loopback OAuth — `localhost` will not work). ```bash npm run dev ``` Open [http://127.0.0.1:5173](http://127.0.0.1:5173) in your browser. ### Production Build #### For local development (loopback OAuth) ```bash npm run build ``` This produces a `dist/` folder configured for loopback OAuth on `127.0.0.1`. #### For deployment (HTTPS with a real domain) Set the `OAUTH_DOMAIN` environment variable to your domain before building: **PowerShell (Windows):** ```powershell $env:OAUTH_DOMAIN="foxsky.example.com"; npm run build ``` **bash / zsh (Linux/macOS):** ```bash OAUTH_DOMAIN=foxsky.example.com npm run build ``` **cmd (Windows):** ```cmd set OAUTH_DOMAIN=foxsky.example.com && npm run build ``` This does two things: 1. Replaces all `__DOMAIN__` placeholders in `dist/client-metadata.json` with your domain (so the AT Protocol OAuth flow can discover your app) 2. Injects the domain into the JS bundle so the OAuth client uses HTTPS mode instead of loopback mode Your server must serve the app over **HTTPS** at the domain you specified, and `client-metadata.json` must be accessible at `https:///client-metadata.json`. #### Deployment example (nginx) Since Foxsky is a single-page app with client-side routing, your web server must redirect all requests to `index.html` so React Router can handle them. Here's a minimal nginx config: ```nginx server { listen 443 ssl; server_name foxsky.example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; root /var/www/foxsky; index index.html; # SPA fallback — serve static files first, then index.html for all routes location / { try_files $uri $uri/ /index.html; } # Cache static assets (Vite hashes filenames, so they're immutable) location /assets/ { expires 1y; add_header Cache-Control "public, immutable"; } } ``` 1. Build with `OAUTH_DOMAIN=foxsky.example.com npm run build` 2. Copy the contents of `dist/` to `/var/www/foxsky/` 3. Make sure `client-metadata.json` is at `/var/www/foxsky/client-metadata.json` (it's already in `dist/` after build) ### Preview the production build ```bash npm run preview ``` ### Lint ```bash npm run lint ``` ## Project Structure ``` src/ ├── api/ # AT Protocol client, blob rewriting, PDS resolution ├── auth/ # OAuth session management, multi-account support ├── components/ # React UI components ├── hooks/ # Reusable hooks (feed, scroll velocity, saved feeds) ├── labels/ # Label resolution and caching ├── plugins/ # Vite build plugins (domain replacement) ├── prefetch/ # Predictive data prefetching engine ├── settings/ # Settings persistence and context providers ├── utils/ # Post URL routing utilities ├── App.tsx # Root component with providers and routes ├── icons.ts # Font Awesome icon registration ├── index.css # Global styles and theme variables └── main.tsx # Entry point ``` ## Tech Stack - **React 19** + **TypeScript 6** - **Vite 8** with `@vitejs/plugin-react` - **React Router 7** for client-side routing - **@atproto/oauth-client-browser** for AT Protocol OAuth 2.0 - **@atproto/api** as a secondary SDK dependency - **hls.js** for HLS video playback - **Font Awesome** for icons ## License This project is licensed under **Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)**. - ✅ You may view, use, and modify this software for personal/non-commercial purposes - ✅ You must give appropriate credit and indicate if changes were made - ❌ You may **not** use this software for commercial purposes without written permission - ❌ You may **not** claim this work as your own See [LICENSE](./LICENSE) for the full license text or visit [creativecommons.org/licenses/by-nc/4.0](https://creativecommons.org/licenses/by-nc/4.0/). To inquire about commercial licensing, please contact the author.