Spaces:
Runtime error
Runtime error
| // Updated Cloudflare Worker for Backblaze B2 with NestJS Backend Resizing | |
| export default { | |
| async fetch(request, env, ctx) { | |
| try { | |
| const url = new URL(request.url); | |
| // 1. Restrict to CDN domain only | |
| if (url.hostname !== 'cdn.aksharbhesaniya.dev') { | |
| return new Response('Forbidden', { status: 403 }); | |
| } | |
| // 2. Serve from cache if available | |
| const cache = caches.default; | |
| const cacheKey = new Request(url.toString(), request); | |
| const cached = await cache.match(cacheKey); | |
| if (cached) { | |
| console.log('Cache HIT:', url.toString()); | |
| return cached; | |
| } | |
| console.log('Cache MISS:', url.toString()); | |
| // 3. Read resize parameters | |
| const width = url.searchParams.get('w'); | |
| const height = url.searchParams.get('h'); | |
| const quality = url.searchParams.get('q'); | |
| // 4. Check if resizing is requested | |
| const needsResize = width || height || quality; | |
| if (needsResize) { | |
| // ===== RESIZE PATH: Proxy to NestJS Backend ===== | |
| const backendUrl = env.BACKEND_URL || 'https://api.streamflix.com'; | |
| const filePath = url.pathname.substring(1); // Remove leading slash | |
| // Build backend resize URL | |
| const resizeUrl = new URL(`${backendUrl}/backblaze/resize`); | |
| resizeUrl.searchParams.set('path', filePath); | |
| if (width) resizeUrl.searchParams.set('w', width); | |
| if (height) resizeUrl.searchParams.set('h', height); | |
| if (quality) resizeUrl.searchParams.set('q', quality); | |
| console.log('Fetching resized image from backend:', resizeUrl.toString()); | |
| // Fetch resized image from NestJS backend | |
| const backendResponse = await fetch(resizeUrl.toString()); | |
| if (!backendResponse.ok) { | |
| return new Response('Resize failed', { status: backendResponse.status }); | |
| } | |
| // Cache and return resized image | |
| const response = new Response(backendResponse.body, { | |
| headers: { | |
| 'Content-Type': backendResponse.headers.get('Content-Type') || 'image/jpeg', | |
| 'Cache-Control': 'public, max-age=31536000', // Cache for 1 year | |
| 'X-Resize-Backend': 'NestJS', | |
| }, | |
| }); | |
| ctx.waitUntil(cache.put(cacheKey, response.clone())); | |
| return response; | |
| } else { | |
| // ===== ORIGINAL PATH: Serve from B2 directly ===== | |
| // 5. Load B2 secrets | |
| const KEY_ID = env.B2_KEY_ID; | |
| const APP_KEY = env.B2_APP_KEY; | |
| const BUCKET = env.B2_BUCKET; | |
| if (!KEY_ID || !APP_KEY || !BUCKET) { | |
| return new Response('Missing B2 config', { status: 500 }); | |
| } | |
| // 6. Authorize Backblaze B2 | |
| const authRes = await fetch( | |
| 'https://api.backblazeb2.com/b2api/v2/b2_authorize_account', | |
| { | |
| headers: { Authorization: 'Basic ' + btoa(`${KEY_ID}:${APP_KEY}`) }, | |
| }, | |
| ); | |
| if (!authRes.ok) { | |
| return new Response('B2 auth failed', { status: 502 }); | |
| } | |
| const auth = await authRes.json(); | |
| // 7. Build file URL | |
| const cleanPath = url.pathname; | |
| const fileUrl = `${auth.downloadUrl}/file/${BUCKET}${cleanPath}`; | |
| console.log('Fetching original from B2:', fileUrl); | |
| // 8. Fetch file from B2 | |
| const origin = await fetch(fileUrl, { | |
| headers: { Authorization: auth.authorizationToken }, | |
| }); | |
| if (!origin.ok) { | |
| return new Response('File not found', { status: origin.status }); | |
| } | |
| // 9. Cache and return original | |
| const response = new Response(origin.body, { | |
| headers: { | |
| 'Content-Type': origin.headers.get('Content-Type') || 'image/jpeg', | |
| 'Cache-Control': 'public, max-age=31536000', // Cache for 1 year | |
| 'X-Source': 'B2-Direct', | |
| }, | |
| }); | |
| ctx.waitUntil(cache.put(cacheKey, response.clone())); | |
| return response; | |
| } | |
| } catch (err) { | |
| console.error('Worker error:', err); | |
| return new Response('Internal Error: ' + err.message, { status: 500 }); | |
| } | |
| }, | |
| }; | |