File size: 4,802 Bytes
27215dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
// service-worker.js

// Define the target URL that we want to intercept and proxy.
const TARGET_URL_PREFIX = 'https://generativelanguage.googleapis.com';

// Installation event:
self.addEventListener('install', (event) => {
  try {
    console.log('Service Worker: Installing...');
    event.waitUntil(self.skipWaiting());
  } catch (error) {
    console.error('Service Worker: Error during install event:', error);
    // If skipWaiting fails, the new SW might get stuck in a waiting state.
  }
});

// Activation event:
self.addEventListener('activate', (event) => {
  try {
    console.log('Service Worker: Activating...');
    event.waitUntil(self.clients.claim());
  } catch (error) {
    console.error('Service Worker: Error during activate event:', error);
    // If clients.claim() fails, the SW might not control existing pages until next nav.
  }
});

// Fetch event:
self.addEventListener('fetch', (event) => {
  try {
    const requestUrl = event.request.url;

    if (requestUrl.startsWith(TARGET_URL_PREFIX)) {
      console.log(`Service Worker: Intercepting request to ${requestUrl}`);

      const remainingPathAndQuery = requestUrl.substring(TARGET_URL_PREFIX.length);
      const proxyUrl = `${self.location.origin}/api-proxy${remainingPathAndQuery}`;

      console.log(`Service Worker: Proxying to ${proxyUrl}`);

      // Construct headers for the request to the proxy
      const newHeaders = new Headers();
      // Copy essential headers from the original request
      // For OPTIONS (preflight) requests, Access-Control-Request-*  are critical.
      // For actual requests (POST, GET), Content-Type, Accept etc.
      const headersToCopy = [
        'Content-Type',
        'Accept',
        'Access-Control-Request-Method',
        'Access-Control-Request-Headers',
      ];

      for (const headerName of headersToCopy) {
        if (event.request.headers.has(headerName)) {
          newHeaders.set(headerName, event.request.headers.get(headerName));
        }
      }

      if (event.request.method === 'POST') {

        // Ensure Content-Type is set for POST requests to the proxy, defaulting to application/json
        if (!newHeaders.has('Content-Type')) {
          console.warn("Service Worker: POST request to proxy was missing Content-Type in newHeaders. Defaulting to application/json.");
          newHeaders.set('Content-Type', 'application/json');
        } else {
          console.log(`Service Worker: POST request to proxy has Content-Type: ${newHeaders.get('Content-Type')}`);
        }
      }

      const requestOptions = {
        method: event.request.method,
        headers: newHeaders, // Use simplified headers
        body: event.request.body, // Still use the original body stream
        mode: event.request.mode,
        credentials: event.request.credentials,
        cache: event.request.cache,
        redirect: event.request.redirect,
        referrer: event.request.referrer,
        integrity: event.request.integrity,
      };

      // Only set duplex if there's a body and it's a relevant method
      if (event.request.method !== 'GET' && event.request.method !== 'HEAD' && event.request.body ) {
        requestOptions.duplex = 'half';
      }

      const promise = fetch(new Request(proxyUrl, requestOptions))
        .then((response) => {
          console.log(`Service Worker: Successfully proxied request to ${proxyUrl}, Status: ${response.status}`);
          return response;
        })
        .catch((error) => {
          // Log more error details
          console.error(`Service Worker: Error proxying request to ${proxyUrl}. Message: ${error.message}, Name: ${error.name}, Stack: ${error.stack}`);
          return new Response(
            JSON.stringify({ error: 'Proxying failed', details: error.message, name: error.name, proxiedUrl: proxyUrl }),
            {
              status: 502, // Bad Gateway is appropriate for proxy errors
              headers: { 'Content-Type': 'application/json' }
            }
          );
        });

      event.respondWith(promise);

    } else {
      // If the request URL doesn't match our target, let it proceed as normal.
      event.respondWith(fetch(event.request));
    }
  } catch (error) {
    // Log more error details for unhandled errors too
    console.error('Service Worker: Unhandled error in fetch event handler. Message:', error.message, 'Name:', error.name, 'Stack:', error.stack);
    event.respondWith(
      new Response(
        JSON.stringify({ error: 'Service worker fetch handler failed', details: error.message, name: error.name }),
        {
          status: 500,
          headers: { 'Content-Type': 'application/json' }
        }
      )
    );
  }
});