Skip to content

Development Guide

Temp edited this page Jan 9, 2026 · 13 revisions

Development Guide

Complete guide for local development and contributing to R2-Manager-Worker.

Local Development Setup

Prerequisites

Ensure you have installed:

Clone and Install

git clone https://github.com/neverinfamous/R2-Manager-Worker.git
cd R2-Manager-Worker
npm install

Environment Configuration

Create a .env file for local development:

cp .env.example .env

Edit .env:

VITE_WORKER_API=http://localhost:8787

Start Development Servers

You need two terminal windows running simultaneously:

Terminal 1: Vite Dev Server (Frontend)

npm run dev
  • Frontend available at: http://localhost:5173
  • Hot module replacement (HMR) enabled
  • React Fast Refresh for instant updates
  • Watches src/ directory for changes

Terminal 2: Wrangler Worker (Backend)

npx wrangler dev --config wrangler.dev.toml --local
  • Worker API available at: http://localhost:8787
  • Automatic reload on worker/ code changes
  • Uses local bindings with mock data (no remote resources)
  • wrangler.dev.toml skips the frontend build step for faster startup

Important Notes

  • Authentication is disabled on localhost during development
  • JWT validation is automatically skipped for requests from localhost
  • CORS is configured to allow http://localhost:5173 origin with credentials
  • No Cloudflare secrets required - returns mock bucket data for local testing
  • The .env file is already configured to point to http://localhost:8787
  • Mock data includes a single dev-bucket for UI testing
  • To test with real R2 buckets, deploy to production and test there

Mock Operations in Local Development

The following operations return simulated success responses for UI testing:

  • List buckets - Returns dev-bucket
  • Create bucket - Simulates success
  • Rename bucket - Simulates success
  • List files - Returns empty array
  • Upload files - Simulates success (files not stored)
  • Create folders - Simulates success

Note: Files and folders are not actually stored. Local development is for UI/UX testing only. For full functionality, deploy to Cloudflare Workers.

Troubleshooting Development Servers

Port already in use:

# Windows PowerShell: Kill processes on specific ports
$port5173 = Get-NetTCPConnection -LocalPort 5173 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique
$port8787 = Get-NetTCPConnection -LocalPort 8787 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique
foreach ($p in $port5173) { taskkill /F /PID $p }
foreach ($p in $port8787) { taskkill /F /PID $p }

Check if servers are running:

# Windows PowerShell
Get-NetTCPConnection -LocalPort 5173,8787 -ErrorAction SilentlyContinue | Select-Object LocalPort, State

Wrangler won't start:

  • Make sure you're using wrangler.dev.toml config
  • Check for TypeScript errors in worker/index.ts
  • Try deleting .wrangler/ directory and restarting

Vite won't start:

  • Check for port conflicts
  • Delete node_modules/.vite/ cache
  • Restart with npm run dev

Development Server Architecture

The local development setup uses two separate servers:

  1. Vite (Port 5173): Serves the React frontend with HMR

    • Watches: src/**/*
    • Config: vite.config.ts and .env
    • No backend logic
  2. Wrangler (Port 8787): Runs the Worker with local bindings

    • Watches: worker/**/*
    • Config: wrangler.dev.toml
    • Handles API requests from frontend

CORS and Authentication Flow:

  • Frontend sends requests to http://localhost:8787/api/*
  • Worker detects localhost origin and skips JWT validation
  • Worker sets CORS headers to allow http://localhost:5173 with credentials
  • No Cloudflare Access involved in local development

Project Structure

R2-Manager-Worker/
├── src/                      # Frontend source code
│   ├── app.tsx              # Main application component
│   ├── filegrid.tsx         # File browser with grid/list views
│   ├── main.tsx             # React entry point
│   ├── app.css              # Global styles with CSS variables
│   ├── components/
│   │   └── ThemeToggle.tsx  # Theme toggle button component
│   ├── contexts/
│   │   └── ThemeContext.tsx # Theme state management
│   ├── hooks/
│   │   └── useTheme.ts      # Theme hook for components
│   ├── services/
│   │   ├── api.ts           # HTTP client & API calls
│   │   └── auth.ts          # Authentication utilities
│   └── styles/
│       ├── themes.css       # CSS variable definitions
│       └── ThemeToggle.css  # Theme toggle button styles
│
├── worker/                   # Backend Worker code
│   ├── index.ts             # Worker runtime & API endpoints
│   ├── routes/              # API route handlers
│   └── utils/               # Helper utilities
│
├── public/                   # Static assets
│   ├── favicon.ico
│   ├── logo.png
│   └── manifest files
│
├── dist/                     # Production build output
│
├── wrangler.toml.example    # Wrangler config template
├── .env.example             # Environment variables template
├── package.json             # Project dependencies
├── vite.config.ts           # Vite configuration
├── tsconfig.json            # TypeScript configuration
└── eslint.config.js         # ESLint configuration

Technology Stack

Frontend

  • React - UI framework with latest features
  • TypeScript - Type-safe JavaScript
  • Vite - Fast build tool and dev server
  • CSS - No framework, vanilla CSS for simplicity

Backend

  • Cloudflare Workers - Serverless edge runtime
  • TypeScript - Worker code is also type-safe
  • R2 - Object storage (S3-compatible)
  • JSZip - ZIP file creation for bulk downloads

Build Tools

  • Wrangler - Cloudflare Workers CLI
  • ESLint - Code linting
  • Vite - Frontend bundling

Available Scripts

Frontend Development

Start dev server:

npm run dev

Build for production:

npm run build

Preview production build:

npm run preview

Run linter:

npm run lint

Backend Development

Start local Worker:

npx wrangler dev

Start with remote bindings:

npx wrangler dev --remote

View Worker logs:

npx wrangler tail

Deployment

Deploy to Cloudflare:

npm run build && npx wrangler deploy

ES Modules Configuration

The project uses ES modules throughout:

{
  "type": "module"
}

Important:

  • All files use ES6 import/export syntax
  • No CommonJS require() statements
  • Ensures compatibility with Vite 7+
  • Prevents subtle syntax issues

Development Workflow

Making Changes

  1. Create a feature branch:

    git checkout -b feature/your-feature-name
  2. Make your changes in src/ or worker/

  3. Test locally with both dev servers running

  4. Run linter:

    npm run lint
  5. Build for production:

    npm run build
  6. Test production build:

    npm run preview
    npx wrangler dev --remote
  7. Commit changes:

    git add .
    git commit -m "Description of changes"
  8. Push to GitHub:

    git push origin feature/your-feature-name
  9. Create Pull Request on GitHub

Code Style

Follow these conventions:

TypeScript:

  • Use TypeScript strict mode
  • Define interfaces for all API responses
  • Use explicit return types for functions
  • Prefer const over let

React:

  • Functional components only (no class components)
  • Use hooks for state and side effects
  • Keep components small and focused
  • Extract reusable logic into custom hooks

CSS:

  • Use BEM naming convention
  • Mobile-first responsive design
  • Avoid inline styles when possible

Comments:

  • Use JSDoc comments for functions
  • Explain complex logic
  • Don't comment obvious code

Testing Authentication Locally

To test with Cloudflare Access:

Option 1: Deploy and Test

  1. Deploy to production: npx wrangler deploy
  2. Test on your deployed domain
  3. JWT validation works in production

Option 2: Use Remote Worker

  1. Set .env to point to deployed Worker:
    VITE_WORKER_API=https://your-worker.workers.dev
    
  2. Run frontend locally: npm run dev
  3. API calls go to production Worker with JWT validation

Debugging

Frontend Debugging

Browser DevTools:

  • Open DevTools (F12)
  • Console tab - View logs and errors
  • Network tab - Inspect API requests
  • Application tab - Check cookies and storage
  • React DevTools - Install browser extension

Enable verbose logging:

// In src/services/api.ts
console.log('API Request:', {
  method,
  url,
  body
});

Worker Debugging

View real-time logs:

npx wrangler tail

Add debug logging:

// In worker/index.ts
console.log('[Debug]', {
  path: url.pathname,
  method: request.method,
  headers: Object.fromEntries(request.headers)
});

View logs in dashboard:

  1. Go to Workers & Pages → Select your Worker
  2. Click Logs tab
  3. See real-time console output

Common Issues

Port already in use:

# Find and kill process using port 5173 or 8787
npx kill-port 5173
npx kill-port 8787

Module not found:

# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install

Wrangler authentication:

# Re-authenticate with Cloudflare
npx wrangler login

Database Development

View Database

Note: R2 Manager no longer uses a database. All bucket operations use Cloudflare's R2 REST API directly.

Adding New Features

Adding a New API Endpoint

  1. Add route handler in worker/index.ts:
if (url.pathname.startsWith('/api/your-endpoint')) {
  // Handle request
  return new Response(JSON.stringify({ success: true }), {
    headers: {
      'Content-Type': 'application/json',
      ...corsHeaders
    }
  });
}
  1. Add API client method in src/services/api.ts:
export async function yourNewEndpoint(param: string): Promise<Response> {
  return apiRequest(`/your-endpoint/${param}`, {
    method: 'GET'
  });
}
  1. Use in component:
import { yourNewEndpoint } from './services/api';

const data = await yourNewEndpoint('value');

Adding a New UI Component

  1. Create component file:
// src/components/YourComponent.tsx
import React from 'react';

export function YourComponent() {
  return (
    <div className="your-component">
      {/* Component content */}
    </div>
  );
}
  1. Import and use:
import { YourComponent } from './components/YourComponent';

function App() {
  return <YourComponent />;
}

Performance Optimization

Frontend

  • Code splitting - Vite automatically splits chunks
  • Lazy loading - Use React.lazy() for large components
  • Memoization - Use React.memo() to prevent re-renders
  • Debouncing - Debounce search and filter inputs

Worker

  • Streaming responses - Use ReadableStream for large files
  • Caching - Implement cache headers for static content
  • Pagination - Limit result sets and use cursors
  • Rate limiting - Built-in delays prevent API throttling

Contributing Guidelines

Before Submitting

  1. ✅ Code follows project style
  2. ✅ All tests pass (when tests exist)
  3. ✅ Linter passes: npm run lint
  4. ✅ Production build succeeds: npm run build
  5. ✅ Changes are documented
  6. ✅ Commit messages are clear

Pull Request Process

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Push to your fork
  5. Open a Pull Request with:
    • Clear description of changes
    • Screenshots (if UI changes)
    • Related issue numbers

Code Review

PRs will be reviewed for:

  • Code quality and style
  • TypeScript type safety
  • Security implications
  • Performance impact
  • Documentation updates

Theme System Architecture

R2 Bucket Manager includes a comprehensive theme system with light/dark mode support:

Architecture Overview

Components:

  • ThemeContext.tsx - React Context for theme state management
  • useTheme.ts - Custom hook for accessing theme context
  • ThemeToggle.tsx - UI component for theme switching
  • themes.css - CSS custom properties for all colors
  • app.css - Styles using CSS variables

Theme Implementation

How It Works:

  1. ThemeProvider wraps the entire application in main.tsx
  2. Theme preference is stored in localStorage (key: r2-manager-theme)
  3. System preference is detected via prefers-color-scheme media query
  4. Theme is applied via data-theme attribute on <html> element
  5. All colors reference CSS custom properties (var(--color-name))

Theme Modes:

  • system - Follows OS/browser preference (default)
  • light - Force light mode
  • dark - Force dark mode

Color Variables:

/* Light Theme */
--bg-primary: #ffffff
--text-primary: #111827
--accent-blue: #2563eb

/* Dark Theme */
--bg-primary: #111827
--text-primary: rgba(255, 255, 255, 0.87)
--accent-blue: #2563eb

Adding New Colors

  1. Define in themes.css:
:root[data-theme="light"] {
  --my-color: #hexcode;
}

:root[data-theme="dark"] {
  --my-color: #hexcode;
}
  1. Use in app.css:
.my-element {
  background: var(--my-color);
}

Theme Toggle Usage

In Components:

import { useTheme } from '../hooks/useTheme'

function MyComponent() {
  const { theme, resolvedTheme, setTheme } = useTheme()
  
  // theme: 'light' | 'dark' | 'system'
  // resolvedTheme: 'light' | 'dark'
  // setTheme: (theme: ThemeMode) => void
}

Cycle Through Themes:

const cycleTheme = () => {
  if (theme === 'system') setTheme('light')
  else if (theme === 'light') setTheme('dark')
  else setTheme('system')
}

Testing Themes

Manual Testing:

  1. Click theme toggle button in header
  2. Verify smooth transition between themes
  3. Check localStorage persistence (reload page)
  4. Test system theme detection (change OS theme)

Browser DevTools:

  1. Open DevTools → Application → Local Storage
  2. Check for r2-manager-theme key
  3. Change OS theme: DevTools → Rendering → Emulate CSS prefers-color-scheme

Color Contrast Guidelines

All colors meet WCAG 2.1 AA standards:

  • Normal text: 4.5:1 contrast ratio minimum
  • Large text: 3:1 contrast ratio minimum
  • Interactive elements: 3:1 contrast ratio minimum

Use online tools to verify:

Release Process

  1. Update version in package.json
  2. Update README.md if needed
  3. Create git tag: git tag v1.x.x
  4. Push tag: git push origin v1.x.x
  5. Deploy to production: npx wrangler deploy

Adding File Type Support

To add support for new file extensions in uploads, you need to modify three files:

1. Update src/services/api.ts - File Type Configuration

Define the file type category and MIME types:

// Add new category to FILE_TYPES object
myCategory: {
  maxSize: 50 * 1024 * 1024, // 50MB limit
  description: 'My Category Files',
  accept: [
    'application/my-type',
    'text/plain' // fallback for files without MIME type
  ]
}

Then add extension mappings in getConfigByExtension():

'ext1': 'myCategory',
'ext2': 'myCategory',
'ext3': 'myCategory'

2. Update src/filegrid.tsx - File Icons

Add a custom icon function to display the file type visually:

// Add before the generic document icon at the end
if (ext === 'ext1' || ext === 'ext2' || ext === 'ext3') {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" className="file-type-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
      {/* Your SVG icon here */}
    </svg>
  )
}

Icon Guidelines:

  • Use 24x24 viewBox
  • Stroke-based design with strokeWidth="1.5"
  • No fill on main elements (let CSS handle color)
  • Keep design simple and recognizable at small sizes

3. Update src/app.tsx - Upload Instructions

Add your new category to the upload instructions list:

<li>My Category (EXT1, EXT2, EXT3) - up to 50MB</li>

Keep entries:

  • Alphabetical by category name
  • Uppercase extension names
  • Specific size limits per category

File Type Categories

Complete list of supported file types and size limits:

  • Archives (7Z, GZ, RAR, TAR, ZIP) - up to 500MB
  • Audio (AAC, FLAC, M4A, MP3, OGG, OPUS, WAV) - up to 100MB
  • Code (CSS, GO, HTML, Java, JS, Rust, TS, Python, etc.) - up to 10MB
  • Config & Metadata (CONF, ENV, INI, JSON, JSONC, LOCK, TOML, etc.) - up to 10MB
  • Data Formats (AVRO, FEATHER, NDJSON) - up to 50MB
  • Databases (DB, PARQUET, SQL) - up to 50MB
  • Dev Environment (Dockerfile, editorconfig, .gitignore, nvmrc, etc.) - up to 1MB
  • Documents (CSV, Excel, Markdown, PDF, PowerPoint, TXT, Word, etc.) - up to 50MB
  • Documentation (NFO) - up to 10MB
  • Fonts (EOT, OTF, TTF, WOFF, WOFF2) - up to 10MB
  • Images (AVIF, BMP, GIF, HEIC, JPG, PNG, PSD, SVG, WebP) - up to 15MB
  • Jupyter Notebooks (.ipynb) - up to 10MB
  • Videos (3GP, AVI, FLV, M4V, MKV, MOV, MP4, MPEG, OGG, WebM, WMV) - up to 500MB

Category Mapping:

Category Size Limit Purpose Extensions
archive 500MB Compressed files 7z, gz, rar, tar, zip
audio 100MB Audio files aac, flac, m4a, mp3, oga, ogg, opus, wav
code 10MB Source code css, go, html, java, js, py, rb, rs, swift, ts, etc.
config 10MB Config files conf, env, ini, json, jsonc, lock, toml
dataformat 50MB Data formats avro, feather, ndjson
devenv 1MB Dev environment dockerfile, editorconfig, gitignore, nvmrc, browserslistrc
document 50MB Docs & spreadsheets csv, db, doc, docx, md, parquet, pdf, ppt, pptx, rtf, sqlite, txt, xls, xlsx
docs 10MB Documentation nfo
font 10MB Font files eot, otf, ttf, woff, woff2
image 15MB Images avif, bmp, gif, heic, jpg, jpeg, png, psd, svg, webp
video 500MB Videos 3gp, 3g2, avi, flv, m4v, mkv, mov, mp4, mpeg, mpg, mpeg4, ogg, ogv, webm, wmv

Security Considerations

Never add these unsafe file types:

  • .exe, .dll, .bat, .cmd - Windows executables
  • .sh, .bash, .zsh - Shell scripts
  • .ps1 - PowerShell scripts
  • .jar, .class - Java executables
  • .wasm - WebAssembly
  • .msi - Windows installers

These can bypass Cloudflare Access or pose security risks.

Testing New Extensions

  1. Make changes to all three files
  2. Run linter: npm run lint
  3. Build: npm run build
  4. Test locally: npm run dev (both servers)
  5. Upload a test file with the new extension
  6. Verify icon displays correctly
  7. Deploy: npx wrangler deploy

Additional Resources


Questions? Check the Troubleshooting page or open an issue on GitHub.

R2 Bucket Manager Wiki

Getting Started

Core Features

Development

Security & Authentication

Support & Resources

  • Changelog - Release history and updates ⭐ NEW
  • Troubleshooting - Common issues and solutions
  • FAQ - Frequently asked questions
  • Roadmap - Planned features and enhancements

External Links

Clone this wiki locally