Add proxy endpoints to Cloudflare Worker for AI services, keeping
API credentials server-side for better security architecture.
Changes:
- Add fal.ai proxy endpoints (/api/fal/*) for image generation
- Add RunPod proxy endpoints (/api/runpod/*) for image, video, text, whisper
- Update client code to use proxy pattern:
- useLiveImage.tsx (fal.ai live image generation)
- VideoGenShapeUtil.tsx (video generation)
- ImageGenShapeUtil.tsx (image generation)
- runpodApi.ts (whisper transcription)
- llmUtils.ts (LLM text generation)
- Add Environment types for AI service configuration
- Improve Automerge migration: compare shape counts between formats
to prevent data loss during format conversion
To deploy, set secrets:
wrangler secret put FAL_API_KEY
wrangler secret put RUNPOD_API_KEY
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MycroZine Generator:
- Implement actual Gemini image generation (replaces placeholders)
- Use Nano Banana Pro (gemini-2.0-flash-exp-image-generation) as primary
- Fallback to Gemini 2.0 Flash experimental
- Graceful degradation to placeholder if no API key
Client Config:
- Add geminiApiKey to ClientConfig interface
- Add isGeminiConfigured() and getGeminiConfig() functions
- Support user-specific API keys from localStorage
Local Development:
- Fix CORS to allow Tailscale IPs (100.x) and all private ranges
- Update cryptidEmailService to use same host for worker URL on local IPs
- Supports localhost, LAN (192.168.x, 10.x, 172.16-31.x), and Tailscale
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of backing up every board daily (wasteful), we now:
1. Compute SHA-256 content hash for each board
2. Compare against last backed-up hash stored in R2
3. Only backup if content actually changed
Benefits:
- Reduces backup storage by 80-90%
- Enables extending retention beyond 90 days (less storage pressure)
- Each backup represents a real change, not duplicate snapshots
- Hash stored in `hashes/{room.key}.hash` for fast comparison
The cron still runs daily at midnight UTC, but now only boards
with actual changes get new backup entries.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NEW PERMISSION MODEL:
- All users (including anonymous) can now EDIT by default
- Boards can be marked as "protected" by admin - only listed editors can edit
- Global admins (jeffemmett@gmail.com) have admin on ALL boards
- Added BoardSettingsDropdown with view-only toggle for admins
Backend changes:
- Added is_protected column to boards table
- Added global_admins table
- New getEffectivePermission logic prioritizes: token > global admin > owner > protection status
- New API endpoints: /auth/global-admin-status, /admin/request, /boards/:id/info, /boards/:id/editors
- Admin request sends email via Resend API
Frontend changes:
- BoardSettingsDropdown component with protection toggle and editor management
- Updated AuthContext and Board.tsx to default to 'edit' permission
- isReadOnly now only true for protected boards where user is not an editor
Task: task-052
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dropdown menu when clicking user nodes in network graph with options:
- Connect with <username>
- Navigate to <username> (pan to cursor)
- Screenfollow <username> (follow camera)
- Open <username>'s profile
- Fix tool visibility for logged-in users (timing issue with read-only mode)
- Fix 401 errors by correcting localStorage key from 'cryptid_session' to 'canvas_auth_session'
- Remove "(anonymous)" suffix from usernames in tooltips
- Simplify node colors to use user's profile/presence color
- Clear permission cache on logout to prevent stale state
- Various UI improvements to auth components and network graph
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add permission fetching and state management in Board.tsx
- Fetch user's permission level when board loads
- Set tldraw to read-only mode when user has 'view' permission
- Show AnonymousViewerBanner for unauthenticated users
- Banner prompts CryptID sign-up with your specified messaging
- Update permission state when user authenticates
- Wire up permission API routes in worker/worker.ts
- GET /boards/:boardId/permission
- GET /boards/:boardId/permissions (admin)
- POST /boards/:boardId/permissions (admin)
- DELETE /boards/:boardId/permissions/:userId (admin)
- PATCH /boards/:boardId (admin)
- Add X-CryptID-PublicKey to CORS allowed headers
- Add PUT, PATCH, DELETE to CORS allowed methods
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add document ID coordination via server to ensure all clients sync to same document
- Add new endpoints GET/POST /room/:roomId/documentId for document ID management
- Store automergeDocumentId in Durable Object storage
- Add enhanced logging to CloudflareAdapter send() method for debugging
- Add sharePolicy to Automerge Repo to enable document sharing
- Fix TypeScript errors in useAutomergeSyncRepo
This fixes the issue where each client was creating its own Automerge document
with a unique ID, preventing real-time sync. Now all clients in a room use the
same document ID, enabling proper real-time collaboration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>