Fix CORS restrictions and development server configuration

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.
This commit is contained in:
Matthew Raymer
2025-07-04 06:25:25 +00:00
parent 1059aa01a1
commit d823d1ad37
13 changed files with 589 additions and 223 deletions

View File

@@ -32,100 +32,9 @@ export async function createBuildConfig(mode: string): Promise<UserConfig> {
server: {
port: parseInt(process.env.VITE_PORT || "8080"),
fs: { strict: false },
headers: {
// Enable SharedArrayBuffer for absurd-sql
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
},
proxy: {
// Proxy API requests to avoid CORS issues with restrictive headers
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
secure: false,
configure: (proxy) => {
proxy.on('error', (err, req, res) => {
console.log('[Proxy Error]', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('[Proxy Request]', req.method, req.url, '->', proxyReq.path);
});
}
},
// Proxy partner API requests (redirect to main API)
'/partner-api': {
target: 'http://localhost:3000',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/partner-api/, '/api'),
configure: (proxy) => {
proxy.on('error', (err, req, res) => {
console.log('[Partner API Proxy Error]', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('[Partner API Proxy Request]', req.method, req.url, '->', proxyReq.path);
});
}
},
// Proxy image API requests
'/image-api': {
target: 'https://test-image-api.timesafari.app',
changeOrigin: true,
secure: true,
rewrite: (path) => path.replace(/^\/image-api/, ''),
configure: (proxy) => {
proxy.on('error', (err, req, res) => {
console.log('[Image API Proxy Error]', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('[Image API Proxy Request]', req.method, req.url, '->', proxyReq.path);
});
}
},
// Proxy direct image requests from image.timesafari.app to avoid CORS issues
'/image-proxy': {
target: 'https://image.timesafari.app',
changeOrigin: true,
secure: true,
followRedirects: true,
rewrite: (path) => path.replace(/^\/image-proxy/, ''),
configure: (proxy) => {
proxy.on('error', (err, req, res) => {
console.log('[Image Proxy Error]', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('[Image Proxy Request]', req.method, req.url, '->', proxyReq.path);
});
proxy.on('proxyRes', (proxyRes, req, res) => {
// Log the response to debug redirects
console.log('[Image Proxy Response]', req.url, '->', proxyRes.statusCode, proxyRes.headers.location || 'no redirect');
});
}
},
// Proxy Flickr images to avoid CORS issues
'/flickr-proxy': {
target: 'https://live.staticflickr.com',
changeOrigin: true,
secure: true,
followRedirects: true,
rewrite: (path) => path.replace(/^\/flickr-proxy/, ''),
configure: (proxy) => {
proxy.on('error', (err, req, res) => {
console.log('[Flickr Proxy Error]', err);
});
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('[Flickr Proxy Request]', req.method, req.url, '->', proxyReq.path);
});
proxy.on('proxyRes', (proxyRes, req, res) => {
// Add CORS headers to the response
proxyRes.headers['Access-Control-Allow-Origin'] = '*';
proxyRes.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS';
proxyRes.headers['Access-Control-Allow-Headers'] = 'Content-Type';
console.log('[Flickr Proxy Response]', req.url, '->', proxyRes.statusCode);
});
}
}
}
// CORS headers disabled to allow images from any domain
// This means SharedArrayBuffer is unavailable, but absurd-sql
// will automatically fall back to IndexedDB mode which still works
},
build: {
outDir: "dist",