commit 14033244e52ff853da946dc09a9b74f766ff05ee Author: MacBook Date: Tue Apr 21 07:49:37 2026 +0200 Initial commit: Production-ready KoalaSync Monorepo with Manifest V3, Socket.IO Relay, and Two-Phase Sync diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..e1d0d80 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,23 @@ +changelog: + exclude: + labels: + - ignore-for-release + authors: + - dependabot + categories: + - title: "πŸš€ Features" + labels: + - feature + - enhancement + - title: "πŸ› Bug Fixes" + labels: + - bug + - fix + - title: "πŸ“ Documentation" + labels: + - documentation + - docs + - title: "🏠 Internal" + labels: + - internal + - chore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..550bbac --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +name: Release KoalaSync + +on: + push: + tags: + - 'v*' + +jobs: + release-server: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: server/Dockerfile + push: true + tags: | + ghcr.io/${{ github.repository_owner }}/koala-sync-server:latest + ghcr.io/${{ github.repository_owner }}/koala-sync-server:${{ github.ref_name }} + + release-extension: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Create Extension Zip + run: | + zip -r koala-sync-extension.zip extension/ -x "*.DS_Store*" + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: koala-sync-extension.zip + name: Release ${{ github.ref_name }} + generate_release_notes: true + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32bf6f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Dependencies +node_modules/ +.pnp +.pnp.js + +# Environment Variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +server/.env + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS Metadata +.DS_Store +.DS_Store? +._* +Thumbs.db + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo + +# Build / Derived Files +dist/ +build/ +coverage/ + +# KoalaSync Specific +# We ignore the synced files in the extension folder to ensure +# the root 'shared/' remains the Single Source of Truth. +extension/shared/ diff --git a/AI_INIT.md b/AI_INIT.md new file mode 100644 index 0000000..5e9e414 --- /dev/null +++ b/AI_INIT.md @@ -0,0 +1,82 @@ +# KoalaSync AI Onboarding (AI_INIT.md) + +Welcome to the KoalaSync project. This file is the primary entry point for any developer or AI agent working on this codebase. It defines the architecture, non-negotiables, and workflows required to maintain the stability and security of the system. + +--- + +## 1. Project Overview +KoalaSync is a specialized tool for **synchronized video playback** across multiple remote peers. It supports YouTube, Twitch, and native HTML5 video elements. +- **Users**: Friends or groups wanting to watch synchronized content together. +- **Workflow**: A user creates a room, shares an invite link (RoomID#Password), and all peers in that room are synchronized via a Node.js relay server. + +## 2. Repository Structure +- `extension/`: Chrome Extension (Manifest V3). Contains background service worker, content scripts, and popup UI. +- `server/`: Node.js Relay Server using Socket.IO (WebSocket-only). +- `shared/`: **Single Source of Truth** for protocol constants and event names. +- `scripts/`: Utility scripts (e.g., `sync-constants.sh`). +- `docker-compose.yml`: Root-level orchestration for the relay server. + +> [!IMPORTANT] +> `shared/constants.js` and `shared/blacklist.js` must be synchronized to the `extension/shared/` directory after every modification by running `./scripts/sync-constants.sh`. + +## 3. Mandatory Reading +Before touching any code, you MUST read the following documents in order: +1. [ARCHITECTURE.md](ARCHITECTURE.md) – Detailed communication flows and two-phase sync protocol. +2. [shared/README.md](shared/README.md) – Protocol constants and synchronization requirements. +3. [extension/README.md](extension/README.md) – Extension components and loading process. +4. [server/README.md](server/README.md) – Server setup, Docker configuration, and security. + +## 4. Design Guidelines +The popup UI follows a strict design system. Do not modify these variables or the layout structure without explicit approval. +- **Font**: 'Outfit' (Google Fonts). +- **Popup Width**: Fixed at `320px`. +- **Tab Structure**: Must maintain the **Room**, **Sync**, and **Dev** tabs. +- **CSS Variables**: + | Variable | Value | Purpose | + | :--- | :--- | :--- | + | `--bg` | `#0f172a` | Main background | + | `--card` | `#1e293b` | Form and info cards | + | `--accent` | `#6366f1` | Primary actions and branding | + | `--success` | `#22c55e` | Success states / Online dot | + | `--error` | `#ef4444` | Errors / Offline dot | + +## 5. Non-Negotiables (Core Logic) +The following features are critical and must not be removed or fundamentally altered: +- **Two-Phase Force Sync**: The `Prepare` β†’ `ACK` β†’ `Execute` flow ensures all peers are buffered before playback resumes. +- **Platform Specifics**: Specialized click-logic for YouTube (`.ytp-play-button`) and Twitch play/pause buttons in `content.js`. +- **pollSeekReady()**: The polling mechanism that checks `video.readyState` and `currentTime` offset before acknowledging a sync command. +- **SW Keep-alive**: Use of `chrome.alarms` to prevent the Manifest V3 Service Worker from suspending. +- **Exponential Backoff**: Reconnection logic in `background.js` (1s β†’ 30s max). +- **Rate Limiting**: IP-based connection limits (10/min) and socket-based event limits (30/10s) on the server. +- **Security**: Token validation during the initial WebSocket handshake. +- **Persistence**: `peerId` must be stored in `chrome.storage.local` to remain stable across sessions. + +## 6. Technical Constraints +- **No Bundler**: The extension uses plain ES Modules. Do not introduce build steps or npm packages into the `extension/` folder. +- **Manual Protocol**: `background.js` implements a subset of the Socket.IO wire protocol (e.g., `42[...]` framing) to work with native WebSockets. +- **Server Transport**: Restricted to `websocket` only. Polling is disabled. +- **Docker Context**: The Docker build must run from the **Repo Root**, as it needs access to the `shared/` directory. +- **Manifest Settings**: `run_at` must remain `document_idle`, and `all_frames` must remain `false`. + +## 7. Security & Deployment +- **Tokens**: `OFFICIAL_SERVER_TOKEN` and `OFFICIAL_SERVER_URL` are intentionally hardcoded in `constants.js` by design. +- **Environment**: `.env` is excluded via `.gitignore`. Only `.env.example` should be committed. +- **Revocation**: `MIN_VERSION` in the server configuration is the only way to deprecate old extension versions. +- **Token Rotation**: Requires updating `shared/constants.js`, running the sync script, incrementing the extension version, and re-deploying the server. + +## 8. Common Workflows + +### Adding a Protocol Event +1. Add the event name to `shared/constants.js`. +2. Run `./scripts/sync-constants.sh`. +3. Implement the handler in `server/index.js` and `background.js`. + +### Testing Locally +1. Load `extension/` as an "Unpacked Extension" in Chrome. +2. Start the server from the root: `docker-compose up --build`. +3. Select "Custom" server in the popup and enter `ws://localhost:3000`. + +### Locking Old Versions +1. Increase `APP_VERSION` in `shared/constants.js`. +2. Update `MIN_VERSION` in the server's `.env` file. +3. Restart the server. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..2ffdb22 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,56 @@ +# KoalaSync Architecture + +This document describes the communication flows and internal logic of the KoalaSync system. + +## 1. Extension Startup & Connection +- **Initialization**: On startup, `background.js` reads settings (Server URL, Last Room) from `chrome.storage.sync`. +- **WebSocket Handshake**: + 1. Background creates a `new WebSocket` to `/socket.io/?EIO=4&transport=websocket&version=1.0.0&token=...`. + 2. Server performs security checks: + - **IP Rate Limit**: Checks if the IP has exceeded 10 connections/min. + - **Auth Token**: If a server token is required, it must match. + - **Version Check**: Client version must be `>= MIN_VERSION`. + 3. Server responds with an Engine.IO handshake (packet type `0`). + 4. Background sends `40` to join the default Socket.IO namespace. + 5. Server responds with `40`. +- **Room Join**: If a Room ID is stored, Background emits `42["join_room", {...}]`. +- **Reconnect Logic**: If the connection drops, Background uses an exponential backoff (1s, 2s, 4s... max 30s) to reconnect. + +## 2. Media Event Synchronization +When a user presses Play/Pause in a synchronized tab: +1. **Detection**: `content.js` listens to native `play`/`pause` events on the `