docs: complete repository documentation update for v1.0.0-RC5 features

This commit is contained in:
Timo
2026-04-22 11:54:54 +02:00
parent 830f8c44b1
commit 1d2237aab6
5 changed files with 117 additions and 148 deletions
+32 -60
View File
@@ -3,85 +3,57 @@
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. 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.
> [!IMPORTANT] > [!IMPORTANT]
> **Privacy & Data Sovereignty**: KoalaSync follows a strict **Zero-External-Requests Policy**: The extension and website must not make requests to any third-party domains (Google Fonts, CDNs, etc.). All assets (fonts, icons, scripts) must be self-hosted or use system defaults. > **Privacy & Data Sovereignty**: KoalaSync follows a strict **Zero-External-Requests Policy**: The extension and website must not make requests to any third-party domains. All assets must be self-hosted.
> - **Font Stack**: Use a modern system font stack (e.g., -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif) to maintain a premium look without external dependencies. Prohibit the use of `@import` or `<link>` for external font services. > - **Font Stack**: Use a modern system font stack to maintain a premium look without external dependencies.
--- ---
## 1. Project Overview ## 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. KoalaSync is a specialized tool for **synchronized video playback** across multiple remote peers.
- **Users**: Friends or groups wanting to watch synchronized content together. - **Workflow**: A user creates a room, shares an invitation link, and all peers are synchronized via a Node.js relay server.
- **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. - **Identity**: Users are identified by a unique hex `peerId` combined with a customizable `username`.
## 2. Repository Structure ## 2. Repository Structure
- `extension/`: Chrome Extension (Manifest V3). Contains background service worker, content scripts, and popup UI. - `extension/`: Chrome Extension (Manifest V3).
- `server/`: Node.js Relay Server using Socket.IO (WebSocket-only). - `server/`: Node.js Relay Server using Socket.IO (WebSocket-only).
- `website/`: **Landing Page** (Marketing, Tutorials, and Downloads). - `website/`: Landing Page & Invitation Bridge.
- `shared/`: **Single Source of Truth** for protocol constants and event names. - `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 ## 3. Mandatory Reading
Before touching any code, you MUST read the following documents in order: 1. [ARCHITECTURE.md](ARCHITECTURE.md) Communication flows and Dual Heartbeat protocol.
1. [ARCHITECTURE.md](ARCHITECTURE.md) Detailed communication flows and two-phase sync protocol. 2. [extension/README.md](extension/README.md) UI structure and component overview.
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 ## 4. Design Guidelines
The popup UI follows a strict design system. Do not modify these variables or the layout structure without explicit approval.
- **Font**: System font stack (e.g., `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`). **MANDATORY**: No external CDNs or Google Fonts to ensure 100% privacy.
- **Popup Width**: Fixed at `320px`. - **Popup Width**: Fixed at `320px`.
- **Tab Structure**: Must maintain the **Room**, **Sync**, and **Dev** tabs. - **Tab Structure**: **Room**, **Sync**, **Settings**, and **Dev**.
- **CSS Variables**: - **CSS Variables**: Uses the CSS variables defined in `popup.html` for a consistent Dark Mode / Glassmorphic look.
| 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) ## 5. Non-Negotiables (Core Logic)
The following features are critical and must not be removed or fundamentally altered: - **Two-Phase Force Sync**: `Prepare``ACK``Execute` flow for frame-perfect sync.
- **Two-Phase Force Sync**: The `Prepare``ACK``Execute` flow ensures all peers are buffered before playback resumes. - **Dual Heartbeat**:
- **Platform Specifics**: Specialized click-logic for YouTube (`.ytp-play-button`) and Twitch play/pause buttons in `content.js`. - **Background Heartbeat (30s)**: Keeps the session alive even without a video.
- **pollSeekReady()**: The polling mechanism that checks `video.readyState` and `currentTime` offset before acknowledging a sync command. - **Content Heartbeat (15s)**: Transmits current video metadata (title, time).
- **SW Keep-alive**: Use of `chrome.alarms` to prevent the Manifest V3 Service Worker from suspending. - **Dead Peer Pruning**: Server automatically disconnects peers after 5 minutes of total silence.
- **Exponential Backoff**: Reconnection logic in `background.js` (1s → 30s max). - **Deduplication**: Server kills old sockets if a user re-joins with the same `peerId`.
- **Rate Limiting**: IP-based connection limits (10/min) and socket-based event limits (30/10s) on the server. - **Diagnostics**: The "Dev" tab provides real-time access to the underlying `<video>` state for troubleshooting.
- **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 ## 6. Technical Constraints
- **No Bundler**: The extension uses plain ES Modules. Do not introduce build steps or npm packages into the `extension/` folder. - **No Bundler**: Plain ES Modules only.
- **Manual Protocol**: `background.js` implements a subset of the Socket.IO wire protocol (e.g., `42[...]` framing) to work with native WebSockets. - **Socket.IO Protocol**: Manual implementation of the wire protocol in `background.js`.
- **Server Transport**: Restricted to `websocket` only. Polling is disabled. - **Docker Context**: Must build from the **Repo Root**.
- **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 ## 7. Security & Deployment
- **Tokens**: `OFFICIAL_SERVER_TOKEN` and `OFFICIAL_SERVER_URL` are intentionally hardcoded in `constants.js` by design. - **Invitation Links**: Correctly propagate server URLs and room credentials via the URL hash.
- **Environment**: `.env` is excluded via `.gitignore`. Only `.env.example` should be committed. - **Rate Limiting**: IP and socket-based limits are enforced server-side.
- **Revocation**: `MIN_VERSION` in the server configuration is the only way to deprecate old extension versions. - **Persistence**: `peerId` and `username` must persist across browser sessions.
- **Token Rotation**: Requires updating `shared/constants.js`, running the sync script, incrementing the extension version, and re-deploying the server.
## 8. Common Workflows ## 8. Common Workflows
### Adding a Protocol Event ### Modifying the Protocol
1. Add the event name to `shared/constants.js`. 1. Edit `shared/constants.js`.
2. Run `./scripts/sync-constants.sh`. 2. Run `scripts/sync-constants.bat` (Windows) or `scripts/sync-constants.sh` (POSIX).
3. Implement the handler in `server/index.js` and `background.js`. 3. Restart the server and reload the extension.
### Testing Locally ### Testing
1. Load `extension/` as an "Unpacked Extension" in Chrome. - Use **different browser profiles** or vendors to test multi-peer logic locally.
2. Start the server from the root: `docker-compose up --build`. - Use the **Dev tab** to verify that the extension is correctly detecting the video state.
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.
+29 -43
View File
@@ -3,54 +3,40 @@
This document describes the communication flows and internal logic of the KoalaSync system. This document describes the communication flows and internal logic of the KoalaSync system.
## 1. Extension Startup & Connection ## 1. Extension Startup & Connection
- **Initialization**: On startup, `background.js` reads settings (Server URL, Last Room) from `chrome.storage.sync`. - **Initialization**: On startup, `background.js` reads settings (Server URL, Username, Last Room) from `chrome.storage.sync`.
- **WebSocket Handshake**: - **WebSocket Handshake**:
1. Background creates a `new WebSocket` to `/socket.io/?EIO=4&transport=websocket&version=1.0.0&token=...`. 1. Background creates a `new WebSocket` to `/socket.io/?EIO=4&transport=websocket&version=1.0.0`.
2. Server performs security checks: 2. Server performs security checks:
- **IP Rate Limit**: Checks if the IP has exceeded 10 connections/min. - **IP Rate Limit**: Checks if the IP has exceeded connection limits.
- **Auth Token**: If a server token is required, it must match. - **Protocol Version**: Client must match the server's protocol (currently `1.0.0`).
- **Version Check**: Client version must be `>= MIN_VERSION`. 3. Server responds with Engine.IO handshake (`0`) and the client joins the namespace (`40`).
3. Server responds with an Engine.IO handshake (packet type `0`). - **Room Join**: Background emits `JOIN_ROOM` containing `roomId`, `password`, `peerId`, and `username`.
4. Background sends `40` to join the default Socket.IO namespace. - **Deduplication**: If a user joins with a `peerId` that already has an active socket, the server kills the old socket to prevent "Ghost Peers".
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 ## 2. Media Event Synchronization
When a user presses Play/Pause in a synchronized tab: When a user interacts with a video:
1. **Detection**: `content.js` listens to native `play`/`pause` events on the `<video>` element. 1. **Detection**: `content.js` listens to native events (`play`, `pause`, `seeked`) on the `<video>` element.
2. **Reporting**: `content.js` sends a `CONTENT_EVENT` message to `background.js`. 2. **Prevention of Loops**: Uses `lastTargetState` to distinguish between user actions and programmatic actions triggered by the extension.
3. **Emission**: `background.js` emits `42["play"|"pause", {...}]` to the server. 3. **Reporting**: `content.js` sends a `CONTENT_EVENT` to `background.js`.
4. **Relay**: The Server forwards the event to all other sockets in the same room. 4. **Relay**: The Server forwards the event to all other peers in the room.
5. **Reception**: Other Extensions receive the event via WebSocket. 5. **Execution**: Remote peers receive the command and call `video.play()`, `video.pause()`, or `video.currentTime = targetTime`.
6. **Execution**: `background.js` sends a `SERVER_COMMAND` to its `content.js`.
7. **Control**: `content.js` calls `video.play()` or `video.pause()`.
- *Note*: It uses `isProcessingCommand` to prevent feedback loops.
## 3. Two-Phase Force Sync ## 3. Two-Phase Force Sync
This protocol ensures all peers are paused and buffered at the exact same timestamp before resuming playback. Ensures all peers are frame-perfect and buffered before resuming:
1. **Initiation**: User clicks "Force Sync" in the popup. 1. **Prepare**: Initiator sends `FORCE_SYNC_PREPARE` with the target timestamp.
2. **Preparation**: 2. **Buffer**: Peers seek and pause. Once buffered (`readyState >= 3`), they send a `FORCE_SYNC_ACK`.
- Popup asks Content Script for the current time. 3. **Execute**: Once the Initiator collects ACKs (or after a 5s timeout), they send `FORCE_SYNC_EXECUTE`.
- Background emits `FORCE_SYNC_PREPARE` with `targetTime`. 4. **Resume**: All peers call `play()` simultaneously.
3. **Coordination**:
- Peers receive `PREPARE`, `content.js` pauses and seeks.
- Once `video.readyState >= 3` (buffered), `content.js` sends `FORCE_SYNC_ACK`.
- Background forwards ACK to the Initiator via Server.
4. **Execution**:
- Initiator collects ACKs. Once all peers have responded (or 5s timeout), Initiator emits `FORCE_SYNC_EXECUTE`.
- All peers receive `EXECUTE` and call `video.play()`.
## 4. Peer Lifecycle ## 4. Peer Lifecycle & Dual Heartbeat
- **Join**: Server sends `ROOM_DATA` to the joiner and `PEER_STATUS (joined)` to others. To maintain a clean room state and eliminate "Ghost Peers":
- **Leave**: - **Session Heartbeat (Background)**: Every 30 seconds, `background.js` sends an "I'm alive" signal to the server. This keeps you in the room even if no video is playing.
- **Manual**: User clicks "Leave". Popup sends `LEAVE_ROOM` to Background -> Server. - **Video Heartbeat (Content)**: Every 15 seconds, `content.js` sends current playback metadata (time, title, state) if a video is found.
- **Pruning**: If a socket disconnects, the Server automatically broadcasts `PEER_STATUS (left)` and deletes the room if empty. - **Server Pruning**: The server runs a "Reaper" every 2 minutes. If a peer has sent **zero** activity (no events and no heartbeats) for 5 minutes, they are forcefully disconnected.
- **Heartbeat**: `content.js` sends a status heartbeat every 15s to keep the peer list updated with current playback states. - **Immediate Cleanup**: Rooms are deleted instantly when the last peer leaves or disconnects.
## 5. Service Worker Keep-alive ## 5. Security & Stability
Manifest V3 Service Workers are ephemeral. To keep the connection alive: - **Service Worker Lifecycle**: Uses `chrome.alarms` to prevent the Manifest V3 service worker from suspending while in an active room.
1. `chrome.alarms` triggers every 15 seconds. - **Rate Limiting**: Server-side per-socket and per-IP rate limits to prevent sync-spamming or DoS.
2. The alarm listener checks the WebSocket `readyState`. - **Noise Filtering**: Uses a curated blacklist of domains (Search Engines, Social Media) to declutter the "Target Tab" selector in the popup.
3. If not `OPEN`, it triggers a `connect()` attempt. - **Diagnostics**: A "Dev" tab provides real-time access to the underlying `<video>` state (`readyState`, `paused`, `currentTime`) for easier troubleshooting.
4. This keeps the background process "awake" enough to handle incoming WebSocket messages.
+25 -29
View File
@@ -1,20 +1,28 @@
# KoalaSync # KoalaSync
KoalaSync is a Chrome Extension and Relay Server for synchronized video playback (YouTube, Twitch, HTML5). KoalaSync is a premium, lightweight Chrome Extension and Relay Server for synchronized video playback across any website (YouTube, Twitch, Netflix, and custom HTML5 players).
> [!TIP] > [!TIP]
> **New Developers & AI Agents**: Please read [AI_INIT.md](AI_INIT.md) before starting work. > **New Developers & AI Agents**: Please read [AI_INIT.md](AI_INIT.md) before starting work.
## Repository Structure ## Repository Structure
- `extension/`: Chrome Extension (Manifest V3). - `extension/`: Chrome Extension (Manifest V3, Vanilla JS).
- `server/`: Node.js + Socket.IO Relay Server. - `server/`: Node.js + Socket.IO Relay Server (Containerized).
- `website/`: Static marketing landing page & tutorials. - `website/`: Static marketing landing page & tutorials.
- `shared/`: Shared protocol constants. - `shared/`: Shared protocol constants.
## Key Features
- **Global Synchronization**: Synchronize Play, Pause, and Seeking on any website with a `<video>` tag.
- **Smart Identity**: Customizable usernames combined with unique hexadecimal peer IDs.
- **Dual Heartbeat Architecture**: Robust session tracking that prevents ghost rooms and stale connections.
- **Zero-Latency Relay**: Custom Socket.IO wire protocol implementation for maximum performance.
- **Integrated Diagnostics**: A dedicated "Dev" tab for real-time video state debugging.
- **Seamless Invitations**: Smart invitation links that automatically configure the server and room credentials for your friends.
## Setup Instructions ## Setup Instructions
### 1. Relay Server (Docker) ### 1. Relay Server (Docker)
The server runs on Node.js using Socket.IO but is restricted to WebSocket transport for compatibility with native clients. The server runs on Node.js using Socket.IO, containerized for easy deployment.
```bash ```bash
# From the root directory # From the root directory
@@ -29,35 +37,23 @@ The server will be available at `ws://localhost:3000`.
4. Select the `extension/` folder. 4. Select the `extension/` folder.
## Usage ## Usage
1. Open the extension popup. 1. Open the extension and go to the **Settings** tab to set your **Username**.
2. Enter the Server URL (default: `ws://localhost:3000`). 2. Go to the **Room** tab, enter your Server URL (default: `ws://localhost:3000`), and click **Join / Create Room**.
3. Click **Join / Create Room**. 3. In the **Sync** tab, select the tab containing the video you want to sync.
4. In the **Sync** tab, select the tab containing the video you want to sync. 4. Share the **Invite Link** from the Room tab. When your friends click it, they will automatically join your room and server.
5. Share the **Invite Link** (RoomID#Password) with your friends. 5. Use **Force Sync** to perfectly align everyone to your current timestamp.
6. When they join, your play/pause/seek actions will be synchronized.
7. Use **Force Sync** to align everyone to your current timestamp.
## Technical Details ## Technical Details
- **Manifest V3**: Uses a Service Worker for background tasks. - **Manifest V3**: Uses a persistent Service Worker with Alarm-based keep-alive.
- **Native WebSockets**: The extension uses the native `WebSocket` API. - **Manual Socket.IO Protocol**: The extension implements the Socket.IO v4 wire protocol natively for extreme performance and zero dependencies.
- > [!IMPORTANT] - **Dead Peer Pruning**: The server automatically prunes peers after 5 minutes of total inactivity (detected via dual heartbeats).
- > **Socket.IO Compatibility**: The server must use **Socket.IO v4**. The extension implements a subset of the Engine.IO/Socket.IO wire protocol. - **Two-Phase Sync**: Ensures all peers are buffered (`readyState >= 3`) before resuming playback.
- **Keep-Alive**: A `chrome.alarms` mechanism keeps the Service Worker active.
- **Two-Phase Force Sync**: Uses `pollSeekReady` to ensure all peers are synchronized before resuming.
## Security & Privacy ## Security & Privacy
> [!IMPORTANT] > [!IMPORTANT]
> **Privacy by Design**: KoalaSync is built with extreme data parsimony in mind. > **Privacy First**: KoalaSync stores no data on disk. All room states exist only in RAM and are purged immediately when empty. There is zero telemetry, tracking, or analytics.
> - **No Databases**: The server stores absolutely nothing on disk. All room states and peer mappings exist only in RAM and are destroyed as soon as a room is empty or inactive.
> - **No Tracking**: There is zero telemetry, analytics, or user tracking in both the extension and the server.
> - **Minimal Logging**: The server logs only technical events (connections, errors, rate-limiting) with no personally identifiable information (PII).
> - **Extension Permissions**: The `<all_urls>` permission is required solely to detect and synchronize HTML5 video elements on any website you visit. No browsing history is ever transmitted or stored.
- > [!WARNING]
> **Invite Links**: Passwords in invite links (e.g., `RoomID#Password`) are shared in plaintext. This is a trade-off for convenience. For higher security, share the password via a secure channel.
## Troubleshooting ## Troubleshooting
- **Logs**: Check the **Dev** tab in the extension popup for detailed connection logs. - **Logs**: Check the **Dev** tab in the extension popup for live connection logs and video state diagnostics.
- **Handshake**: Look for `Socket.IO Handshake: 0{...}` in the logs to verify successful connection. - **Handshake**: Verify you see `Joined Namespace /` in the logs.
- **Permissions**: Ensure you have granted the extension permission to access the video site's tab. - **Permissions**: Ensure the target site hasn't blocked script injection (rare for most video sites).
+9 -3
View File
@@ -1,9 +1,9 @@
# KoalaSync Protocol Synchronization Guide (SYNC_GUIDE.md) # KoalaSync Protocol Synchronization Guide
## Why do we need to sync? ## Why do we need to sync?
KoalaSync uses a "Single Source of Truth" for its communication protocol constants located in the `shared/` directory. However, Chrome Extensions (Manifest V3) are strictly sandboxed and **cannot load or import files from outside their root directory**. KoalaSync uses a "Single Source of Truth" for its communication protocol constants located in the root `shared/` directory. However, Chrome Extensions (Manifest V3) are strictly sandboxed and **cannot load or import files from outside their root directory**.
To ensure that the extension and the relay server are always using the exact same event names and protocol versions, we must maintain a mirrored copy of the shared files within the extension folder. To ensure that the extension and the relay server are always using the exact same event names and protocol versions, we maintain a mirrored copy of the shared files within the `extension/shared/` folder.
## When should you run the sync script? ## When should you run the sync script?
You MUST run the synchronization script in any of the following scenarios: You MUST run the synchronization script in any of the following scenarios:
@@ -32,5 +32,11 @@ The script performs the following actions:
2. Copies `shared/constants.js` to `extension/shared/constants.js`. 2. Copies `shared/constants.js` to `extension/shared/constants.js`.
3. Copies `shared/blacklist.js` to `extension/shared/blacklist.js`. 3. Copies `shared/blacklist.js` to `extension/shared/blacklist.js`.
## Protocol Versioning
As of v1.0.0-RC5, the system enforces a strict `protocolVersion` check during the `JOIN_ROOM` handshake.
- The version is defined in `shared/constants.js`.
- If the extension and server versions mismatch, the server will reject the connection with an `Incompatible protocol version` error.
- **Always run the sync script** after bumping the version number to ensure both components are updated.
> [!CAUTION] > [!CAUTION]
> **NEVER** edit the files inside `extension/shared/` directly. They will be overwritten the next time the sync script is run. Always edit the files in the root `shared/` directory and then run the sync script. > **NEVER** edit the files inside `extension/shared/` directly. They will be overwritten the next time the sync script is run. Always edit the files in the root `shared/` directory and then run the sync script.
+22 -13
View File
@@ -1,23 +1,32 @@
# KoalaSync Chrome Extension # KoalaSync Chrome Extension
A Manifest V3 Chrome Extension for synchronized video playback. A Manifest V3 Chrome Extension for synchronized video playback across any website.
## Key Features ## Key Features
- **Manifest V3**: Using a modern Service Worker architecture. - **Manifest V3**: Optimized Service Worker architecture with session persistence.
- **Native WebSockets**: No heavy libraries, uses the browser's native API. - **Pure Vanilla JS**: No external dependencies or heavy libraries.
- **Smart Peer IDs**: Hexadecimal IDs combined with customizable Usernames for easy identification.
- **Dual Heartbeat**: Advanced session tracking (Background) and video synchronization (Content) to prevent ghost sessions.
- **Live Diagnostics**: Built-in "Dev" tab for real-time video state debugging (ReadyState, CurrentTime, etc.).
## Tab Overview
1. **Room**: Manage connections, view active peers, and share invitation links.
2. **Sync**: Control video playback (Play/Pause/Force Sync) and view recent activity.
3. **Settings**: Customize your Username and toggle domain-based Noise Filtering.
4. **Dev**: Monitor connection status and view real-time video element metadata for debugging.
## Privacy & Permissions ## Privacy & Permissions
KoalaSync requires `<all_urls>` permission to detect and interact with video elements (`<video>`) on any website. KoalaSync requires `<all_urls>` permission to detect and interact with video elements (`<video>`) on websites.
- **No Browsing History**: We do not track which sites you visit. - **No Browsing History**: We do not track or store your browsing history.
- **No Telemetry**: There are no analytics or tracking scripts included. - **State Management**: Sensitive data (Room Passwords) is stored locally using `chrome.storage`.
- **Local State**: Settings (Server URL, Room ID, Password) are stored only locally in your browser using `chrome.storage`. - **Zero Telemetry**: No analytics or external tracking scripts.
## Installation ## Installation
1. Go to `chrome://extensions/`. 1. Open Chrome and go to `chrome://extensions/`.
2. Enable **Developer mode**. 2. Enable **Developer mode** (top right).
3. Click **Load unpacked** and select this folder. 3. Click **Load unpacked** and select the `extension` folder from this repository.
## Development ## Development
If you change `shared/constants.js`, remember to run the synchronization script: If you modify `shared/constants.js`, you must synchronize the changes across the extension and server:
- Windows: `..\scripts\sync-constants.bat` - **Windows**: Run `scripts\sync-constants.bat`
- Linux/macOS: `../scripts/sync-constants.sh` - **Linux/macOS**: Run `scripts/sync-constants.sh`