- Node.js 18+
- npm 9+
- Google Chrome 102+ / Microsoft Edge 102+ / Mozilla Firefox 128+
# Clone the repository
git clone https://github.com/mhdnazrul/CodeforcesSync.git
cd CodeforcesSync
# Install dependencies
npm install
# Build the extension
npm run buildLoad dist/ as an unpacked extension:
- Chrome:
chrome://extensions→ Developer mode → Load unpacked - Edge:
edge://extensions→ Developer mode → Load unpacked - Firefox: Build with
npm run build:firefox, then openabout:debugging#/runtime/this-firefox→ Load Temporary Add-on → selectdist/manifest.json
npm run devThis runs vite build --watch, which rebuilds on file changes. After each rebuild, reload the extension in your browser's extension manager.
npm run build # Chrome / Edge
npm run build:firefox # FirefoxThese run tsc -b (TypeScript type checking) followed by vite build (production bundle) with the appropriate manifest.
npm run lintThe project uses ESLint with TypeScript rules. The lint configuration is in eslint.config.js (flat config).
| Script | Command | Description |
|---|---|---|
dev |
vite build --emptyOutDir --watch |
Development build with watch mode |
build |
tsc -b && vite build --emptyOutDir |
Chrome/Edge production build |
build:firefox |
tsc -b && vite build --emptyOutDir --config vite.config.firefox.ts |
Firefox production build |
lint |
eslint . |
Run ESLint on all files |
preview |
vite preview |
Preview the production build |
src/
├── background/ # Service worker (alarms, sync, message routing)
├── browser/ # Browser API abstraction (Chrome adapter)
├── cfstats/ # Codeforces statistics fetching
├── codeforces/ # Codeforces API client
├── content/ # Content scripts injected into CF pages
├── github/ # GitHub REST API client
├── shared/ # Shared utilities, types, formatters
├── statistics/ # Streak and calendar computation
├── storage/ # Settings persistence
├── sync/ # Sync engine
└── ui/ # React popup application
├── components/ # Reusable UI components
├── contexts/ # React contexts
├── screens/ # Screen components
└── utils/ # UI utilities
| File | Purpose |
|---|---|
vite.config.ts |
Vite build configuration, CRXJS plugin, Tailwind plugin |
tsconfig.json |
TypeScript configuration (references app and node configs) |
tsconfig.app.json |
TypeScript config for the React app source |
tsconfig.node.json |
TypeScript config for Node.js code (Vite config, API functions) |
vercel.json |
Vercel serverless function configuration |
package.json |
Dependencies, scripts, metadata |
| File | Purpose |
|---|---|
manifest.json |
Chrome Extension manifest |
src/background/background.ts |
Service worker entry point |
src/main.tsx |
React entry point |
src/App.tsx |
Root React component |
src/index.css |
Tailwind CSS styles |
Create a .env file in the project root:
VITE_OAUTH_BROKER_URL=https://<your-vercel-deployment>.vercel.appThis variable is embedded at build time by Vite. It tells the extension where to find the OAuth broker for GitHub authentication.
When developing, follow these rules:
- Domain modules (
github/,codeforces/,sync/,statistics/) must never import frombrowser/or React. - Browser abstraction (
src/browser/) is the only module that directly callschrome.*APIs. - No cross-domain imports between
github/andcodeforces/. - Pure functions — side effects should be pushed to the edges of the system.
- Error handling — Never swallow errors in empty
catchblocks. Log errors with theCodeforcesSync:prefix.
There is no test suite currently. Manual testing steps:
- Load the extension in Chrome.
- Verify the onboarding flow works (GitHub auth → CF handle → repo link).
- Open the dashboard and verify streaks and CF stats load.
- Submit a solution on Codeforces and verify it syncs to GitHub.
- Test the settings screen (change repo, set subdirectory, reset all).
- Open
chrome://extensions. - Find CodeforcesSync.
- Click Service Worker (blue link under "Inspect views").
- The DevTools console shows all service worker logs.
Right-click the extension icon → Inspect popup → The DevTools console shows popup logs.
Open chrome://identity-internals to see cached OAuth tokens.