Make this work as a proxy service in cloudflare worker to bypass CORS restrictions and policy. -- // Default Configuration
const DEFAULT_CONFIG = {
  ALLOWED_DOMAINS: new Set([
    'https://api.abhibhai.com',
    'https://lnee.netlify.app',
    'https://proxe.netlify.app',
    'http://localhost:8080',
  ]),
  BLOCKED_TARGET_HOSTS: new Set(['blocked.example.com']),
  FORWARD_HEADERS: new Set([
    'accept',
    'accept-language',
    'user-agent',
    'content-type',
    'authorization',
    'cache-control',
    'pragma',
    'expires',
    'last-modified',
    'if-modified-since',
    'if-none-match',
    'range',
    'content-range',
    'accept-encoding',
    'accept-datetime',
    'cookie',
  ]),
  REMOVE_HEADERS: new Set([
    'cf-connecting-ip',
    'x-forwarded-for',
    'x-real-ip',
    'forwarded',
    'via',
    'proxy-authorization',
    'proxy-authenticate',
    'client-ip',
    'true-client-ip',
    'x-forwarded-host',
    'x-forwarded-port',
    'x-forwarded-proto',
    'x-forwarded-protocol',
    'x-forwarded-ssl',
    'x-url-scheme',
    'x-original-forwarded-for',
    'x-http-forwarded-for',
    'x-original-host',
    'x-forwarded-by',
    'x-proxy-user-ip',
    'x-cluster-client-ip',
    'x-forwarded',
    'x-real-ip',
    'forwarded-for',
    'forwarded-proto',
  ]),
  TIMEOUT: 29000, // in milliseconds
  LOGGING_LEVEL: 'warn', // Options: 'error', 'warn', 'info', 'debug'
  AUTH_KEY: 'your-secure-auth-key', // Replace with a secure key
  SECURITY_HEADERS: {
    'X-Content-Type-Options': 'nosniff',
    'Referrer-Policy': 'no-referrer',
    'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
    'X-Frame-Options': 'DENY',
  },
  CUSTOM_ERROR_RESPONSES: {},
  CACHE_CONTROL: {
    DEFAULT_MAX_AGE: 300, // 5 minutes
    CUSTOM_RULES: {},
  },
  STREAM_THRESHOLD: 1024 * 1024, // 1MB
};

// Clone the default configuration
let CONFIG = { ...DEFAULT_CONFIG };

// Custom Error Class
class ProxyError extends Error {
  constructor(message, status) {
    super(message);
    this.name = 'ProxyError';
    this.status = status;
  }
}

// Event Listener for Fetch Events
addEventListener('fetch', (event) => {
  event.respondWith(
    handleRequest(event).catch((error) => handleError(error, event.request))
  );
});

// Main Request Handler
async function handleRequest(event) {
  const request = event.request;
  const url = new URL(request.url);

  // Handle Preflight CORS Requests
  if (request.method === 'OPTIONS') {
    return handlePreflightRequest(request);
  }

  // Handle Configuration Updates
  if (request.method === 'POST' && url.pathname === '/config') {
    return handleConfigUpdate(request);
  }

  // Check for Allowed Origin
  const origin = request.headers.get('Origin');
  if (!isAllowedOrigin(origin)) {
    throw new ProxyError('Forbidden: Origin not allowed', 403);
  }

  // Forward the Request
  return forwardRequest(request, origin);
}

// Check if the Origin is Allowed
function isAllowedOrigin(origin) {
  return origin && (CONFIG.ALLOWED_DOMAINS.has(origin) || CONFIG.ALLOWED_DOMAINS.has('*'));
}

// Forward the Incoming Request to the Target URL
async function forwardRequest(request, origin) {
  const url = new URL(request.url);
  const targetUrl =
    request.headers.get('x-target-url') || url.searchParams.get('target');

  if (!targetUrl) {
    throw new ProxyError('Bad Request: Missing target URL', 400);
  }

  let parsedTargetUrl;
  try {
    parsedTargetUrl = new URL(targetUrl);
  } catch (err) {
    throw new ProxyError('Invalid URL format', 400);
  }

  if (CONFIG.BLOCKED_TARGET_HOSTS.has(parsedTargetUrl.host)) {
    throw new ProxyError('Forbidden: Target host is not allowed', 403);
  }

  // Prepare Headers for the Forwarded Request
  const init = {
    method: request.method,
    headers: filterRequestHeaders(request.headers),
    redirect: 'follow',
    // Cloudflare Workers supports signal with AbortController for timeout
    signal: AbortSignal.timeout(CONFIG.TIMEOUT),
  };

  // Attach the Request Body if Applicable
  if (!['GET', 'HEAD'].includes(request.method)) {
    const body = await getRequestBody(request);
    if (body !== null) {
      init.body = body;
    }
  }

  // Perform the Fetch to the Target URL
  let response;
  try {
    response = await fetch(parsedTargetUrl.toString(), init);
  } catch (err) {
    if (err.name === 'AbortError') {
      throw new ProxyError('Request Timed Out', 504);
    } else {
      throw new ProxyError('Error Fetching Target URL', 502);
    }
  }

  // Process and Return the Response with CORS and Security Headers
  return createCorsResponse(response, origin);
}

// Filter and Forward Only Allowed Headers
function filterRequestHeaders(headers) {
  const forwardedHeaders = new Headers();
  for (const [key, value] of headers.entries()) {
    const lowerKey = key.toLowerCase();
    if (CONFIG.FORWARD_HEADERS.has(lowerKey) && !CONFIG.REMOVE_HEADERS.has(lowerKey)) {
      forwardedHeaders.set(key, value);
    }
  }
  return forwardedHeaders;
}

// Retrieve the Request Body Based on Content-Type
async function getRequestBody(request) {
  const contentType = request.headers.get('Content-Type') || '';
  if (contentType.includes('application/json')) {
    try {
      return await request.clone().json();
    } catch {
      throw new ProxyError('Invalid JSON Body', 400);
    }
  } else if (contentType.includes('application/x-www-form-urlencoded')) {
    try {
      return await request.clone().formData();
    } catch {
      throw new ProxyError('Invalid Form Data', 400);
    }
  } else if (contentType.startsWith('multipart/')) {
    try {
      return await request.clone().formData();
    } catch {
      throw new ProxyError('Invalid Multipart Data', 400);
    }
  } else {
    try {
      return await request.clone().arrayBuffer();
    } catch {
      throw new ProxyError('Invalid Body Data', 400);
    }
  }
}

// Generate CORS Headers
function generateCorsHeaders(origin) {
  const headers = new Headers();

  if (isAllowedOrigin(origin)) {
    headers.set('Access-Control-Allow-Origin', origin);
    headers.set('Access-Control-Allow-Credentials', 'true');
  } else {
    headers.set('Access-Control-Allow-Origin', 'null');
  }

  headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  headers.set('Access-Control-Allow-Headers', '*');
  headers.set('Access-Control-Expose-Headers', '*');
  headers.set('Access-Control-Max-Age', '86400'); // 1 day
  headers.append('Vary', 'Origin');

  return headers;
}

// Handle Preflight CORS Requests
function handlePreflightRequest(request) {
  const origin = request.headers.get('Origin') || '';
  const corsHeaders = generateCorsHeaders(origin);

  return new Response(null, {
    status: 204,
    headers: corsHeaders,
  });
}

// Create CORS-Compliant Response with Security Headers
async function createCorsResponse(response, origin) {
  const corsHeaders = generateCorsHeaders(origin);
  const responseHeaders = new Headers(response.headers);

  // Remove Disallowed Headers
  for (const header of CONFIG.REMOVE_HEADERS) {
    responseHeaders.delete(header);
  }

  // Apply CORS Headers
  for (const [key, value] of corsHeaders.entries()) {
    responseHeaders.set(key, value);
  }

  // Apply Security Headers
  for (const [key, value] of Object.entries(CONFIG.SECURITY_HEADERS)) {
    responseHeaders.set(key, value);
  }

  // Handle Cache Control
  applyCacheControl(responseHeaders, response.url);

  // Clone the response if streaming is needed
  if (response.body && response.body.locked) {
    // For cases where the body is locked and can't be used directly
    const clonedBody = await response.blob();
    return new Response(clonedBody, {
      status: response.status,
      statusText: response.statusText,
      headers: responseHeaders,
    });
  }

  // Return the Modified Response
  return new Response(response.body, {
    status: response.status,
    statusText: response.statusText,
    headers: responseHeaders,
  });
}

// Apply Cache Control Headers
function applyCacheControl(headers, url) {
  const parsedUrl = new URL(url);
  const pathname = parsedUrl.pathname;
  const customRule = CONFIG.CACHE_CONTROL.CUSTOM_RULES[pathname];

  if (customRule) {
    headers.set('Cache-Control', customRule);
  } else {
    headers.set(
      'Cache-Control',
      `public, max-age=${CONFIG.CACHE_CONTROL.DEFAULT_MAX_AGE}`
    );
  }
}

// Handle Errors and Generate Appropriate Responses
async function handleError(error, request) {
  const status = error instanceof ProxyError ? error.status : 500;
  const message = error.message || 'Internal Server Error';

  logError(error);

  const origin = request.headers.get('Origin') || '';
  const corsHeaders = generateCorsHeaders(origin);
  const headers = new Headers({
    'Content-Type': 'application/json',
    ...CONFIG.SECURITY_HEADERS,
  });

  // Apply CORS Headers
  for (const [key, value] of corsHeaders.entries()) {
    headers.set(key, value);
  }

  // Check for Custom Error Response
  const customErrorResponse = CONFIG.CUSTOM_ERROR_RESPONSES[status];
  if (customErrorResponse) {
    return new Response(JSON.stringify(customErrorResponse), {
      status,
      headers,
    });
  }

  // Default Error Response
  return new Response(JSON.stringify({ error: message }), { status, headers });
}

// Logging Function Based on Configured Logging Level
function logError(error) {
  const logLevel = CONFIG.LOGGING_LEVEL.toLowerCase();
  const logMessage = `[${new Date().toISOString()}] ${error.name}: ${error.message}`;

  if (logLevel === 'error' && error.status >= 500) {
    console.error(logMessage);
  } else if (logLevel === 'warn' && error.status >= 400) {
    console.warn(logMessage);
  } else if (logLevel === 'info') {
    console.info(logMessage);
  } else if (logLevel === 'debug') {
    console.debug(logMessage, error.stack);
  }
}

// Handle Configuration Updates via POST /config
async function handleConfigUpdate(request) {
  const authHeader = request.headers.get('Authorization');
  if (!isAuthorized(authHeader)) {
    throw new ProxyError('Unauthorized', 401);
  }

  try {
    const updatedConfig = await request.json();
    validateConfig(updatedConfig);
    updateConfig(updatedConfig);
    return new Response(
      JSON.stringify({ message: 'Configuration updated successfully' }),
      {
        status: 200,
        headers: {
          'Content-Type': 'application/json',
          ...CONFIG.SECURITY_HEADERS,
        },
      }
    );
  } catch (error) {
    if (error instanceof ProxyError) {
      return handleError(error, request);
    }
    return new Response(JSON.stringify({ error: 'Invalid configuration data' }), {
      status: 400,
      headers: {
        'Content-Type': 'application/json',
        ...CONFIG.SECURITY_HEADERS,
      },
    });
  }
}

// Authorization Check for Configuration Updates
function isAuthorized(authHeader) {
  return authHeader && authHeader === `Bearer ${CONFIG.AUTH_KEY}`;
}

// Validate the Incoming Configuration
function validateConfig(newConfig) {
  // Implement any necessary validation for the incoming configuration
  // For example, ensure that ALLOWED_DOMAINS is an array of valid URLs
  // Throw ProxyError if validation fails

  if ('ALLOWED_DOMAINS' in newConfig && !Array.isArray(newConfig.ALLOWED_DOMAINS)) {
    throw new ProxyError('Invalid ALLOWED_DOMAINS format', 400);
  }

  if ('BLOCKED_TARGET_HOSTS' in newConfig && !Array.isArray(newConfig.BLOCKED_TARGET_HOSTS)) {
    throw new ProxyError('Invalid BLOCKED_TARGET_HOSTS format', 400);
  }

  if ('FORWARD_HEADERS' in newConfig && !Array.isArray(newConfig.FORWARD_HEADERS)) {
    throw new ProxyError('Invalid FORWARD_HEADERS format', 400);
  }

  if ('REMOVE_HEADERS' in newConfig && !Array.isArray(newConfig.REMOVE_HEADERS)) {
    throw new ProxyError('Invalid REMOVE_HEADERS format', 400);
  }

  // Add more validation rules as necessary
}

// Update the Configuration with New Values
function updateConfig(newConfig) {
  for (const [key, value] of Object.entries(newConfig)) {
    if (key in CONFIG) {
      if (value instanceof Array && CONFIG[key] instanceof Set) {
        CONFIG[key] = new Set(value);
      } else if (
        typeof value === 'object' &&
        value !== null &&
        !Array.isArray(value) &&
        typeof CONFIG[key] === 'object' &&
        !(CONFIG[key] instanceof Set)
      ) {
        CONFIG[key] = { ...CONFIG[key], ...value };
      } else {
        CONFIG[key] = value;
      }
    }
  }

  // Ensure TIMEOUT doesn't exceed Cloudflare's limits (30 seconds)
  if ('TIMEOUT' in newConfig) {
    CONFIG.TIMEOUT = Math.min(CONFIG.TIMEOUT, 30000);
  }
}

// Optional: Helper Function to Reset Configuration to Default
function resetConfig() {
  CONFIG = { ...DEFAULT_CONFIG };
}