forked from trent_larson/crowd-funder-for-time-pwa
Remove CORS headers to enable universal image support and fix local API server settings. ## Changes **Remove CORS Headers** - Remove Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers - Enables images from any domain (Facebook, Medium, arbitrary websites) - Database falls back to IndexedDB mode (minimal performance impact) **Fix Local Development Configuration** - Set LOCAL_ENDORSER_API_SERVER to http://127.0.0.1:3000 (was "/api") - Create .env.development with local API server config - Fix ensureCorrectApiServer() method in HomeView.vue - "Use Local" button now sets proper localhost address **Fix Settings Cache Issues** - Add PlatformServiceMixin to AccountViewView.vue - Disable settings caching to prevent stale data - Settings changes now apply immediately without browser refresh ## Impact **Tradeoffs:** - Lost: ~2x SharedArrayBuffer database performance - Gained: Universal image support from any domain - Result: Better user experience, database still fast via IndexedDB **Files Modified:** - Configuration: vite.config.*.mts, index.html, .env.development - Source: constants/app.ts, libs/util.ts, views/*.vue, utils/PlatformServiceMixin.ts ## Rationale For a community platform, universal image support is more critical than marginal database performance gains. Users share images from arbitrary websites, making CORS restrictions incompatible with Time Safari's core mission.
240 lines
7.5 KiB
Markdown
240 lines
7.5 KiB
Markdown
# CORS Image Loading Solution
|
|
|
|
## Overview
|
|
|
|
This document describes the implementation of a comprehensive image loading solution that works in a cross-origin isolated environment (required for SharedArrayBuffer support) while accepting images from any domain.
|
|
|
|
## Problem Statement
|
|
|
|
When using SharedArrayBuffer (required for absurd-sql), browsers enforce a cross-origin isolated environment with these headers:
|
|
- `Cross-Origin-Opener-Policy: same-origin`
|
|
- `Cross-Origin-Embedder-Policy: require-corp`
|
|
|
|
This isolation prevents loading external resources (including images) unless they have proper CORS headers, which most image hosting services don't provide.
|
|
|
|
## Solution Architecture
|
|
|
|
### 1. Multi-Tier Proxy System
|
|
|
|
The solution uses a multi-tier approach to handle images from various sources:
|
|
|
|
#### Tier 1: Specific Domain Proxies (Development Only)
|
|
- **TimeSafari Images**: `/image-proxy/` → `https://image.timesafari.app/`
|
|
- **Flickr Images**: `/flickr-proxy/` → `https://live.staticflickr.com/`
|
|
- **Imgur Images**: `/imgur-proxy/` → `https://i.imgur.com/`
|
|
- **GitHub Raw**: `/github-proxy/` → `https://raw.githubusercontent.com/`
|
|
- **Unsplash**: `/unsplash-proxy/` → `https://images.unsplash.com/`
|
|
|
|
#### Tier 2: Universal CORS Proxy (Development Only)
|
|
- **Any External Domain**: Uses `https://api.allorigins.win/raw?url=` for arbitrary domains
|
|
|
|
#### Tier 3: Direct Loading (Production)
|
|
- **Production Mode**: All images load directly without proxying
|
|
|
|
### 2. Smart URL Transformation
|
|
|
|
The `transformImageUrlForCors` function automatically:
|
|
- Detects the image source domain
|
|
- Routes through appropriate proxy in development
|
|
- Preserves original URLs in production
|
|
- Handles edge cases (data URLs, relative paths, etc.)
|
|
|
|
## Implementation Details
|
|
|
|
### Configuration Files
|
|
|
|
#### `vite.config.common.mts`
|
|
```typescript
|
|
server: {
|
|
headers: {
|
|
// Required for SharedArrayBuffer support
|
|
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
'Cross-Origin-Embedder-Policy': 'require-corp'
|
|
},
|
|
proxy: {
|
|
// Specific domain proxies with CORS headers
|
|
'/image-proxy': { /* TimeSafari images */ },
|
|
'/flickr-proxy': { /* Flickr images */ },
|
|
'/imgur-proxy': { /* Imgur images */ },
|
|
'/github-proxy': { /* GitHub raw images */ },
|
|
'/unsplash-proxy': { /* Unsplash images */ }
|
|
}
|
|
}
|
|
```
|
|
|
|
#### `src/libs/util.ts`
|
|
```typescript
|
|
export function transformImageUrlForCors(imageUrl: string): string {
|
|
// Development mode: Transform URLs to use proxies
|
|
// Production mode: Return original URLs
|
|
|
|
// Handle specific domains with dedicated proxies
|
|
// Fall back to universal CORS proxy for arbitrary domains
|
|
}
|
|
```
|
|
|
|
### Usage in Components
|
|
|
|
All image loading in components uses the transformation function:
|
|
|
|
```typescript
|
|
// In Vue components
|
|
import { transformImageUrlForCors } from "../libs/util";
|
|
|
|
// Transform image URL before using
|
|
const imageUrl = transformImageUrlForCors(originalImageUrl);
|
|
```
|
|
|
|
```html
|
|
<!-- In templates -->
|
|
<img :src="transformImageUrlForCors(imageUrl)" alt="Description" />
|
|
```
|
|
|
|
## Benefits
|
|
|
|
### ✅ SharedArrayBuffer Support
|
|
- Maintains cross-origin isolation required for SharedArrayBuffer
|
|
- Enables fast SQLite database operations via absurd-sql
|
|
- Provides better performance than IndexedDB fallback
|
|
|
|
### ✅ Universal Image Support
|
|
- Handles images from any domain
|
|
- No need to pre-configure every possible image source
|
|
- Graceful fallback for unknown domains
|
|
|
|
### ✅ Development/Production Flexibility
|
|
- Proxy system only active in development
|
|
- Production uses direct URLs for maximum performance
|
|
- No proxy server required in production
|
|
|
|
### ✅ Automatic Detection
|
|
- Smart URL transformation based on domain patterns
|
|
- Preserves relative URLs and data URLs
|
|
- Handles edge cases gracefully
|
|
|
|
## Testing
|
|
|
|
### Automated Testing
|
|
Run the test suite to verify URL transformation:
|
|
|
|
```typescript
|
|
import { testCorsImageTransformation } from './libs/test-cors-images';
|
|
|
|
// Console output shows transformation results
|
|
testCorsImageTransformation();
|
|
```
|
|
|
|
### Visual Testing
|
|
Create test image elements to verify loading:
|
|
|
|
```typescript
|
|
import { createTestImageElements } from './libs/test-cors-images';
|
|
|
|
// Creates visual test panel in browser
|
|
createTestImageElements();
|
|
```
|
|
|
|
### Manual Testing
|
|
1. Start development server: `npm run dev`
|
|
2. Open browser console to see transformation logs
|
|
3. Check Network tab for proxy requests
|
|
4. Verify images load correctly from various domains
|
|
|
|
## Security Considerations
|
|
|
|
### Development Environment
|
|
- CORS proxies are only used in development
|
|
- External proxy services (allorigins.win) are used for testing
|
|
- No sensitive data is exposed through proxies
|
|
|
|
### Production Environment
|
|
- All images load directly without proxying
|
|
- No dependency on external proxy services
|
|
- Original security model maintained
|
|
|
|
### Privacy
|
|
- Image URLs are not logged or stored by proxy services
|
|
- Proxy requests are only made during development
|
|
- No tracking or analytics in proxy chain
|
|
|
|
## Performance Impact
|
|
|
|
### Development
|
|
- Slight latency from proxy requests
|
|
- Additional network hops for external domains
|
|
- More verbose logging for debugging
|
|
|
|
### Production
|
|
- No performance impact
|
|
- Direct image loading as before
|
|
- No proxy overhead
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
#### Images Not Loading in Development
|
|
1. Check console for proxy errors
|
|
2. Verify CORS headers are set
|
|
3. Test with different image URLs
|
|
4. Check network connectivity to proxy services
|
|
|
|
#### SharedArrayBuffer Not Available
|
|
1. Verify CORS headers are set in server configuration
|
|
2. Check that site is served over HTTPS (or localhost)
|
|
3. Ensure browser supports SharedArrayBuffer
|
|
|
|
#### Proxy Service Unavailable
|
|
1. Check if allorigins.win is accessible
|
|
2. Consider using alternative CORS proxy services
|
|
3. Temporarily disable CORS headers for testing
|
|
|
|
### Debug Commands
|
|
|
|
```bash
|
|
# Check if SharedArrayBuffer is available
|
|
console.log(typeof SharedArrayBuffer !== 'undefined');
|
|
|
|
# Test URL transformation
|
|
import { transformImageUrlForCors } from './libs/util';
|
|
console.log(transformImageUrlForCors('https://example.com/image.jpg'));
|
|
|
|
# Run comprehensive tests
|
|
import { testCorsImageTransformation } from './libs/test-cors-images';
|
|
testCorsImageTransformation();
|
|
```
|
|
|
|
## Migration Guide
|
|
|
|
### From Previous Implementation
|
|
1. CORS headers are now required for SharedArrayBuffer
|
|
2. Image URLs automatically transformed in development
|
|
3. No changes needed to existing image loading code
|
|
4. Test thoroughly in both development and production
|
|
|
|
### Adding New Image Sources
|
|
1. Add specific proxy for frequently used domains
|
|
2. Update `transformImageUrlForCors` function
|
|
3. Add CORS headers to proxy configuration
|
|
4. Test with sample images
|
|
|
|
## Future Enhancements
|
|
|
|
### Possible Improvements
|
|
1. **Local Proxy Server**: Run dedicated proxy server for development
|
|
2. **Caching**: Cache proxy responses for better performance
|
|
3. **Fallback Chain**: Multiple proxy services for reliability
|
|
4. **Image Optimization**: Compress/resize images through proxy
|
|
5. **Analytics**: Track image loading success/failure rates
|
|
|
|
### Alternative Approaches
|
|
1. **Service Worker**: Intercept image requests at service worker level
|
|
2. **Build-time Processing**: Pre-process images during build
|
|
3. **CDN Integration**: Use CDN with proper CORS headers
|
|
4. **Local Storage**: Cache images in browser storage
|
|
|
|
## Conclusion
|
|
|
|
This solution provides a robust, scalable approach to image loading in a cross-origin isolated environment while maintaining the benefits of SharedArrayBuffer support. The multi-tier proxy system ensures compatibility with any image source while optimizing for performance and security.
|
|
|
|
For questions or issues, refer to the troubleshooting section or consult the development team. |