1/** 2 * @license 3 * Copyright 2025 Google LLC 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6// service-worker.js 7 8// Define the target URL that we want to intercept and proxy. 9const TARGET_URL_PREFIX = 'https://generativelanguage.googleapis.com'; 10 11// Installation event: 12self.addEventListener('install', (event) => { 13 try { 14 console.log('Service Worker: Installing...'); 15 event.waitUntil(self.skipWaiting()); 16 } catch (error) { 17 console.error('Service Worker: Error during install event:', error); 18 // If skipWaiting fails, the new SW might get stuck in a waiting state. 19 } 20}); 21 22// Activation event: 23self.addEventListener('activate', (event) => { 24 try { 25 console.log('Service Worker: Activating...'); 26 event.waitUntil(self.clients.claim()); 27 } catch (error) { 28 console.error('Service Worker: Error during activate event:', error); 29 // If clients.claim() fails, the SW might not control existing pages until next nav. 30 } 31}); 32 33// Fetch event: 34self.addEventListener('fetch', (event) => { 35 try { 36 const requestUrl = event.request.url; 37 38 if (requestUrl.startsWith(TARGET_URL_PREFIX)) { 39 console.log(`Service Worker: Intercepting request to ${requestUrl}`); 40 41 const remainingPathAndQuery = requestUrl.substring(TARGET_URL_PREFIX.length); 42 const proxyUrl = `${self.location.origin}/api-proxy${remainingPathAndQuery}`; 43 44 console.log(`Service Worker: Proxying to ${proxyUrl}`); 45 46 // Construct headers for the request to the proxy 47 const newHeaders = new Headers(); 48 // Copy essential headers from the original request 49 // For OPTIONS (preflight) requests, Access-Control-Request-* are critical. 50 // For actual requests (POST, GET), Content-Type, Accept etc. 51 const headersToCopy = [ 52 'Content-Type', 53 'Accept', 54 'Access-Control-Request-Method', 55 'Access-Control-Request-Headers', 56 ]; 57 58 for (const headerName of headersToCopy) { 59 if (event.request.headers.has(headerName)) { 60 newHeaders.set(headerName, event.request.headers.get(headerName)); 61 } 62 } 63 64 if (event.request.method === 'POST') { 65 66 // Ensure Content-Type is set for POST requests to the proxy, defaulting to application/json 67 if (!newHeaders.has('Content-Type')) { 68 console.warn("Service Worker: POST request to proxy was missing Content-Type in newHeaders. Defaulting to application/json."); 69 newHeaders.set('Content-Type', 'application/json'); 70 } else { 71 console.log(`Service Worker: POST request to proxy has Content-Type: ${newHeaders.get('Content-Type')}`); 72 } 73 } 74 75 const createProxyRequest = async () => { 76 const body = event.request.method !== 'GET' && event.request.method !== 'HEAD' ? await event.request.arrayBuffer() : undefined; 77 78 const requestOptions = { 79 method: event.request.method, 80 headers: newHeaders, 81 body: body, 82 mode: event.request.mode, 83 credentials: event.request.credentials, 84 cache: event.request.cache, 85 redirect: event.request.redirect, 86 referrer: event.request.referrer, 87 integrity: event.request.integrity, 88 }; 89 90 // Only set duplex if there's a body and it's a relevant method 91 if (body) { 92 requestOptions.duplex = 'half'; 93 } 94 95 return new Request(proxyUrl, requestOptions); 96 }; 97 98 const promise = createProxyRequest().then(proxyRequest => fetch(proxyRequest)) 99 .then((response) => { 100 console.log(`Service Worker: Successfully proxied request to ${proxyUrl}, Status: ${response.status}`); 101 return response; 102 }) 103 .catch((error) => { 104 // Log more error details 105 console.error(`Service Worker: Error proxying request to ${proxyUrl}. Message: ${error.message}, Name: ${error.name}, Stack: ${error.stack}`); 106 return new Response( 107 JSON.stringify({ error: 'Proxying failed', details: error.message, name: error.name, proxiedUrl: proxyUrl }), 108 { 109 status: 502, // Bad Gateway is appropriate for proxy errors 110 headers: { 'Content-Type': 'application/json' } 111 } 112 ); 113 }); 114 115 event.respondWith(promise); 116 117 } else { 118 // If the request URL doesn't match our target, let it proceed as normal. 119 event.respondWith(fetch(event.request)); 120 } 121 } catch (error) { 122 // Log more error details for unhandled errors too 123 console.error('Service Worker: Unhandled error in fetch event handler. Message:', error.message, 'Name:', error.name, 'Stack:', error.stack); 124 event.respondWith( 125 new Response( 126 JSON.stringify({ error: 'Service worker fetch handler failed', details: error.message, name: error.name }), 127 { 128 status: 500, 129 headers: { 'Content-Type': 'application/json' } 130 } 131 ) 132 ); 133 } 134}); 135
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.