@dirathea/busical
v0.3.0
Published
Sync calendar events to your work calendar - with privacy
Downloads
680
Maintainers
Readme
BusiCal 📅
A privacy-first Progressive Web App (PWA) that helps you sync personal calendar events to your work calendar — with privacy.
Features
- Privacy-First: Events sync as "Synced Event" marked as busy to protect your privacy
- No Authentication Required: Uses calendar deeplinks - no OAuth, no backend
- CORS Proxy Built-in: Cloudflare Worker handles ICS fetching to bypass browser CORS restrictions
- Edit Calendar URL: Easily change your source calendar with one click
- Multiple Platforms: Sync to Google Calendar, Outlook Calendar, or download .ics files
- Week View Toggle: View events for this week or next week
- Offline-Capable: PWA with localStorage caching
- Mobile-Friendly: Fully responsive design that works on iOS and Android
Quick Start
Run with npx/bunx
The easiest way to run BusiCal locally:
# Using npm (Node.js)
npx @dirathea/busical
# Using bun
bunx @dirathea/busical
# With custom port
npx @dirathea/busical --port 8080
# With environment variables
PORT=8080 npx @dirathea/busicalThe app will be available at http://localhost:3000 (or your specified port).
Development
# Install dependencies
npm install
# Run development server
npm run dev
# Build for production
npm run build
# Preview production build
npm run previewThe app will be available at http://localhost:5173
How It Works
- Add Your Calendar: Enter your source calendar's ICS URL (from Google Calendar, Outlook, iCloud, etc.)
- View Events: Browse events for this week or next week
- Sync: Click any event to sync it to your work calendar
- Choose Platform: Select Google Calendar, Outlook, or download .ics file
- Privacy Protected: Event syncs with minimal details ("Synced Event", marked as busy)
Perfect for those who had a busy day ✨
Getting Your ICS URL
Google Calendar
- Open Google Calendar on the web
- Click Settings (gear icon) → Settings
- Select your calendar from the left sidebar
- Scroll to "Integrate calendar" section
- Copy the "Secret address in iCalendar format" URL
Outlook.com
- Open Outlook Calendar on the web
- Click Settings → View all Outlook settings
- Go to Calendar → Shared calendars
- Under "Publish a calendar", select your calendar
- Click "Publish" and copy the ICS link
Apple Calendar (iCloud)
- Open iCloud.com and go to Calendar
- Click the share icon next to your calendar
- Enable "Public Calendar"
- Copy the URL
- Replace "webcal://" with "https://" in the URL
CORS Proxy Architecture
BusiCal uses a Cloudflare Worker as a CORS proxy to fetch ICS calendar files. This is necessary because browsers block direct requests to calendar URLs due to CORS (Cross-Origin Resource Sharing) restrictions.
How It Works
- User enters ICS URL → Frontend sends request to
/proxy?url=... - Cloudflare Worker → Fetches the ICS file from the calendar provider
- Worker validates → Ensures it's a valid ICS file (contains
BEGIN:VCALENDAR) - Returns JSON → Worker wraps ICS content in JSON response with CORS headers
- Frontend parses → Extracts ICS data and parses calendar events locally
Privacy & Data Handling
⚠️ IMPORTANT: No data is stored, logged, or retained on the proxy server.
- Stateless Operation: The proxy fetches your calendar and immediately returns it to your browser. Nothing is saved.
- No Logging: The proxy does not log calendar URLs, ICS content, IP addresses, or any request data.
- Pass-Through Only: Think of it as a transparent tunnel - data flows through but nothing sticks.
- Client-Side Processing: All calendar parsing, caching, and storage happens in your browser's localStorage.
See our Privacy Policy for complete details.
Security Measures
- URL Validation: Prevents SSRF (Server-Side Request Forgery) attacks
- Protocol Restriction: Only http/https allowed (blocks file://, ftp://, etc.)
- Content Validation: Verifies response contains valid ICS data
- Size Limits: Maximum 5MB calendar file size
- Security Headers: X-Frame-Options, CSP, X-Content-Type-Options, etc.
- Origin Restriction: CORS limited to configured domains (not wildcard
*) - Rate Limiting: Configured via Cloudflare dashboard to prevent abuse
Benefits
- No Third-Party Services: Your own Cloudflare Worker (not a public proxy)
- Privacy: ICS URLs processed by infrastructure you control
- Reliability: Cloudflare's edge network for fast, global access
- Transparency: Open source - inspect the code yourself
Self-Hosting
Want complete control? You have multiple deployment options:
Option 1: Docker
# Run with Docker (replace VERSION with desired version)
docker run -p 3000:3000 ghcr.io/dirathea/getbusicalapp:latest
# Or with custom port and CORS origin
docker run -p 8080:3000 -e PORT=3000 -e CORS_ORIGIN=https://yourdomain.com ghcr.io/dirathea/getbusicalapp:0.1.3Option 2: Cloudflare Workers
# 1. Clone the repo
git clone https://github.com/dirathea/getbusicalapp
cd getbusicalapp
# 2. Configure your domain
# Edit wrangler.jsonc and set ALLOWED_ORIGIN
# 3. Deploy to Cloudflare
npm run deploySee DEPLOYMENT.md for detailed instructions.
Worker Endpoints
GET /proxy?url=<ics-url>- Fetch ICS file (primary method)POST /proxywith{ url: "..." }- Alternative methodGET /health- Health check endpoint
FAQ
Have questions about the proxy? Check our FAQ page or Privacy Policy.
Technology Stack
- Frontend: React 19 + TypeScript
- Backend: Cloudflare Worker (CORS proxy)
- Build Tool: Vite 7
- Framework: Hono (Cloudflare Worker)
- UI Components: shadcn/ui (Tailwind CSS + Radix UI)
- Calendar Parsing: ical.js (Mozilla)
- Date Handling: date-fns
- Storage: localStorage (client-side only)
- PWA: Web App Manifest
- Deployment: Cloudflare Pages + Workers
Project Structure
src/
├── components/ # React components
│ ├── ui/ # shadcn/ui components (DO NOT MODIFY)
│ ├── Header.tsx
│ ├── IcsInput.tsx
│ ├── EventList.tsx
│ ├── EventCard.tsx
│ ├── EventDetailsDialog.tsx
│ ├── SyncDialog.tsx
│ └── WeekToggle.tsx
├── lib/ # Core utilities
│ ├── icsParser.ts # ICS fetching and parsing
│ ├── calendarLinks.ts # Deeplink generation
│ ├── icsGenerator.ts # .ics file generation
│ ├── storage.ts # localStorage management
│ ├── dateUtils.ts # Date formatting and filtering
│ └── utils.ts # General utilities
├── hooks/ # React hooks
│ ├── useIcsData.ts # Main data management hook
│ └── useLocalStorage.ts
├── types/ # TypeScript types
│ └── index.ts
├── App.tsx # Main app component
└── main.tsx # Entry pointPWA Setup
Manifest
The app includes a manifest.json for PWA installation. Update the theme colors in:
public/manifest.jsonindex.html(theme-color meta tag)
Icons
You need to generate PNG icons for PWA installation:
Required:
public/icons/icon-192.png(192x192px)public/icons/icon-512.png(512x512px)
Generate from SVG:
# Using ImageMagick
convert public/icons/icon.svg -resize 192x192 public/icons/icon-192.png
convert public/icons/icon.svg -resize 512x512 public/icons/icon-512.png
# Or use https://realfavicongenerator.net/Privacy & Security
- No Server: All data stays on your device
- No Tracking: No analytics or external tracking
- No OAuth: No authentication tokens stored
- HTTPS Required: For PWA functionality
- Event Privacy: Synced events show minimal information
Limitations
- No OAuth: Users must be logged into Google/Outlook in their browser
- No Private Flag: Can't set Google Calendar events as "private" via deeplink
- No Sync Confirmation: Can't verify if user actually saved the event
- Week Range Only: Shows only this week and next week events
- Client-Side Only: All processing happens in browser
Browser Support
- Desktop: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
- Mobile: iOS Safari 14+, Android Chrome 90+
- PWA: Requires HTTPS (works on localhost for development)
Development Notes
UI Components
The src/components/ui/ directory is managed by shadcn CLI. DO NOT MODIFY these files manually. To add or update components:
npx shadcn@latest add [component-name]Environment
- Development runs on
http://localhost:5173 - PWA features require HTTPS in production
- localStorage is used for all data persistence
Future Enhancements
- [ ] Custom date range selection
- [ ] Bulk sync (multiple events at once)
- [ ] Sync history tracking
- [ ] Customizable event titles
- [ ] Support for recurring events
- [ ] Dark mode toggle
- [ ] Multiple calendar sources
- [ ] Service worker for offline support
- [ ] Background sync
Contributing
Contributions are welcome! Please follow these guidelines:
- Keep the existing code style
- Don't modify
src/components/ui/manually (use shadcn CLI) - Test on both desktop and mobile
- Update this README if adding features
License
MIT License - feel free to use this project for personal or commercial purposes.
Support
If you encounter issues:
- Check browser console for errors
- Verify ICS URL is valid and accessible
- Ensure you're using a modern browser
- Try clearing localStorage and refreshing
☕ Support This Project
If BusiCal helps you manage your busy days, consider buying me a coffee!
Acknowledgments
- ical.js by Mozilla
- shadcn/ui for beautiful UI components
- date-fns for date manipulation
- Lucide Icons for icons
