{"version":3,"sources":["../src/functions/openPage.ts","../src/spartacuz.ts","../src/functions/takeSnapShot.ts","../src/functions/extractWebpage.ts","../src/functions/extractLinks.ts","../src/functions/colorExtract.ts","../src/functions/extractImages.ts","../src/functions/extractVideos.ts","../src/puppeteerSLS.ts"],"sourcesContent":["import puppeteer from 'puppeteer-extra';\nimport StealthPlugin from 'puppeteer-extra-plugin-stealth';\nimport { puppeteerLaunchProps } from '../spartacuz';\n\npuppeteer.use(StealthPlugin());\n\n/**\n * Options for opening a new page.\n */\nexport interface OpenPageOptions {\n  /**\n   * The URL to navigate to.\n   */\n  url: string;\n  /**\n   * Viewport dimensions.\n   */\n  defaultViewport?: {\n    width: number;\n    height: number;\n  };\n  /**\n   * Whether to run in headless mode.\n   * @default false\n   */\n  headless?: boolean;\n  /**\n   * Whether to close the browser after the operation is complete.\n   * @default false\n   */\n  isLocal?: boolean;\n  /**\n   * whether to wait complete page load\n   * @default true\n   */\n  waitUntil?: 'networkidle2' | 'networkidle0' | 'domcontentloaded' | 'load';\n}\n\n/**\n * Opens a new page in a browser instance and navigates to a URL.\n *\n * @param options - The options for opening the page.\n * @returns A promise that resolves to the Puppeteer page object.\n */\nexport async function openPage({\n  url,\n  defaultViewport,\n  headless,\n  isLocal,\n  waitUntil,\n}: OpenPageOptions) {\n  console.log(\n    `Opening page with options: ${JSON.stringify({\n      url,\n      defaultViewport,\n      headless,\n      isLocal,\n    })}`,\n  );\n  try {\n    const launchProps = await puppeteerLaunchProps(\n      defaultViewport,\n      isLocal ?? false,\n      headless,\n    );\n    console.log('Got puppeteer launch properties.');\n    const browser = await puppeteer.launch(\n      !headless\n        ? {\n            ...launchProps,\n            slowMo: 100,\n          }\n        : launchProps,\n    );\n    console.log('Browser launched.');\n    const page = await browser.newPage();\n    console.log('New page created.');\n    const pageLoad = await page.goto(url, {\n      waitUntil: waitUntil ?? 'networkidle2',\n    });\n    console.log(`Navigated to URL: ${pageLoad?.url()}`);\n    return { browser, page };\n  } catch (error) {\n    console.error('Error opening page:', error);\n    throw error;\n  }\n}\n","import chromium from '@sparticuz/chromium';\nimport * as fs from 'fs';\n\n// Check if running locally\nconst isLocal = process.env.IS_OFFLINE || process.env.SERVERLESS_OFFLINE;\n\nchromium.setGraphicsMode = false;\n\nexport const puppeteerLaunchProps = async (\n  defaultViewport?: {\n    width: number;\n    height: number;\n  },\n  _isLocal?: boolean,\n  headless?: boolean,\n) => {\n  let executablePath: string | undefined;\n\n  console.log('isLocal', isLocal, process.env.CHROME_EXECUTABLE_PATH);\n  const CHROME_PATHS = {\n    darwin: [\n      '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n      '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n      '/Applications/Chromium.app/Contents/MacOS/Chromium',\n      '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',\n      '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser',\n      '~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n      '~/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n      '~/Applications/Chromium.app/Contents/MacOS/Chromium',\n    ],\n    linux: [\n      '/usr/bin/google-chrome',\n      '/usr/bin/google-chrome-stable',\n      '/usr/bin/google-chrome-beta',\n      '/usr/bin/google-chrome-unstable',\n      '/usr/bin/chromium',\n      '/usr/bin/chromium-browser',\n      '/usr/bin/microsoft-edge',\n      '/usr/bin/microsoft-edge-stable',\n      '/usr/bin/microsoft-edge-beta',\n      '/usr/bin/microsoft-edge-dev',\n      '/snap/bin/chromium',\n      '/usr/local/bin/chrome',\n      '/usr/local/bin/chromium',\n      '/opt/google/chrome/chrome',\n      '/opt/google/chrome-beta/chrome',\n      '/opt/google/chrome-unstable/chrome',\n      '/opt/chromium/chrome-linux/chrome',\n      '/opt/microsoft/msedge/msedge',\n      '/opt/brave.com/brave/brave',\n      // Flatpak paths\n      '~/.local/share/flatpak/exports/bin/org.chromium.Chromium',\n      '/var/lib/flatpak/exports/bin/org.chromium.Chromium',\n    ],\n    win32: [\n      'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n      'C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n      'C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n      'C:\\\\Program Files\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n      'C:\\\\Program Files\\\\Brave Software\\\\Brave-Browser\\\\Application\\\\brave.exe',\n      'C:\\\\Program Files (x86)\\\\Brave Software\\\\Brave-Browser\\\\Application\\\\brave.exe',\n      // User-specific locations with AppData\n      `${process.env.LOCALAPPDATA}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n      `${process.env.LOCALAPPDATA}\\\\Google\\\\Chrome SxS\\\\Application\\\\chrome.exe`,\n      `${process.env.LOCALAPPDATA}\\\\Chromium\\\\Application\\\\chrome.exe`,\n      `${process.env.LOCALAPPDATA}\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe`,\n      `${process.env.LOCALAPPDATA}\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe`,\n      // Windows 10/11 may have Edge installed in Program Files\n      'C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge Dev\\\\Application\\\\msedge.exe',\n      'C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge Beta\\\\Application\\\\msedge.exe',\n      // Google Chrome default installation path\n      `${process.env.ProgramFiles}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n      `${process.env.ProgramFiles}\\\\Google\\\\Chrome Dev\\\\Application\\\\chrome.exe`,\n      `${process.env.ProgramFiles}\\\\Google\\\\Chrome Beta\\\\Application\\\\chrome.exe`,\n      `${process.env.ProgramFiles}\\\\Google\\\\Chrome SxS\\\\Application\\\\chrome.exe`,\n      // Chromium\n      `${process.env.ProgramFiles}\\\\Chromium\\\\Application\\\\chrome.exe`,\n    ],\n  };\n\n  if (process.env.CHROME_EXECUTABLE_PATH) {\n    executablePath = process.env.CHROME_EXECUTABLE_PATH;\n  } else if (isLocal || _isLocal) {\n    const platform = process.platform as keyof typeof CHROME_PATHS;\n    const paths = CHROME_PATHS[platform];\n\n    if (paths) {\n      for (const p of paths) {\n        if (fs.existsSync(p)) {\n          executablePath = p;\n          break;\n        }\n      }\n    }\n\n    if (!executablePath) {\n      console.error(\n        'Could not find Chrome in default locations. Please install Chrome or specify the path manually via the CHROME_EXECUTABLE_PATH environment variable.',\n      );\n      throw new Error('Chrome not found');\n    }\n  } else {\n    // For Lambda environment\n    executablePath = await chromium.executablePath();\n  }\n\n  const finalHeadless = isLocal || _isLocal ? (headless ?? false) : true;\n\n  const args = finalHeadless\n    ? chromium.args\n    : chromium.args.filter(arg => !arg.startsWith('--headless'));\n\n  console.log('executablePath', executablePath, finalHeadless);\n\n  return {\n    args: [\n      ...args,\n      '--no-sandbox',\n      '--disable-setuid-sandbox',\n      '--disable-dev-shm-usage',\n      '--disable-gpu',\n    ],\n    defaultViewport: {\n      width: defaultViewport?.width || 1920,\n      height: defaultViewport?.height || 1080,\n    },\n    executablePath,\n    headless: finalHeadless,\n  };\n};\n","import { S3Space, S3SpaceConfig } from '@microfox/s3-space';\nimport { openPage, OpenPageOptions } from './openPage';\n\n/**\n * Options for taking a screenshot.\n */\nexport interface TakeSnapShotOptions extends OpenPageOptions {\n  /**\n   * The file name for the screenshot.\n   */\n  fileName: string;\n  /**\n   * The quality of the screenshot. Only for jpeg.\n   * @default 100\n   */\n  quality?: number;\n  /**\n   * The encoding of the screenshot.\n   * @default 'binary'\n   */\n  encoding?: 'base64' | 'binary';\n  /**\n   * S3 configuration for uploading the screenshot.\n   */\n  s3Config: S3SpaceConfig;\n}\n\n/**\n * Opens a page and takes a screenshot, uploads it to S3 and returns public URL.\n *\n * @param options - The options for taking the screenshot.\n * @returns A promise that resolves with the public URL of the screenshot.\n */\nexport async function takeSnapShot(\n  options: TakeSnapShotOptions,\n): Promise<string | undefined> {\n  const { browser, page } = await openPage(options);\n  const screenshotBuffer = await page.screenshot({\n    quality: options.quality,\n    encoding: options.encoding || 'binary',\n    type: options.quality ? 'jpeg' : 'png',\n  });\n  await browser.close();\n\n  const s3 = new S3Space(options.s3Config);\n  const fileInfo = {\n    fileName: options.fileName,\n    fileType: options.quality ? 'image/jpeg' : 'image/png',\n    fileBuffer: screenshotBuffer,\n  };\n  await s3.uploadFile({\n    fileInfoWithFileBuffer: fileInfo,\n  });\n\n  return s3.getPublicFileUrl({\n    file: fileInfo,\n  });\n}\n","import { Page } from 'puppeteer-core';\nimport { openPage, OpenPageOptions } from './openPage';\nimport TurndownService from 'turndown';\nexport type ExtractWebpageContentOptions = OpenPageOptions & {\n  /**\n   * Whether to convert the content to Markdown.\n   * @default false\n   */\n  toMarkdown?: boolean;\n  /**\n   * Whether to convert the content to HTML.\n   * @default false\n   */\n  toHTML?: boolean;\n};\n\n/**\n * Opens a page and converts its content to Markdown.\n *\n * @param options - The options for opening the page.\n * @returns A promise that resolves to the Markdown content of the page.\n */\nexport async function extractToMarkdown(page: Page) {\n  const html = await page.evaluate(() => document.body.innerHTML);\n\n  const turndownService = new TurndownService();\n  const markdown = turndownService.turndown(html);\n\n  return markdown;\n}\n\n/**\n * Opens a page and extracts its full HTML content.\n *\n * @param options - The options for opening the page.\n * @returns A promise that resolves to the HTML content of the page.\n */\nexport async function extractHTML(page: Page) {\n  const content = await page.evaluate(() => document.documentElement.outerHTML);\n  return content;\n}\n\n/**\n * Opens a page and extracts its text content.\n *\n * @param options - The options for opening the page.\n * @returns A promise that resolves to the text content of the page.\n */\nexport async function extractWebpage(options: ExtractWebpageContentOptions) {\n  const { browser, page } = await openPage(options);\n  const content = await page.evaluate(() => document.body.innerText);\n  const markdown = options.toMarkdown\n    ? await extractToMarkdown(page)\n    : undefined;\n  const html = options.toHTML ? await extractHTML(page) : undefined;\n  return {\n    content,\n    browser,\n    markdown,\n    html,\n    page,\n  };\n}\n","import { Page } from 'puppeteer-core';\nimport { openPage, OpenPageOptions } from './openPage';\n\nexport type ExtractedLink = {\n  href: string;\n  displayName: string;\n  type: 'statix' | 'webpage';\n  inPageLink: boolean;\n  externalLink: boolean;\n  internalLink: boolean;\n  staticType?: 'video' | 'image' | 'file' | 'other';\n  fileExtension?: string;\n};\n\n/**\n * Opens a page and extracts all links.\n *\n * @param options - The options for opening the page.\n * @returns A promise that resolves to an array of links.\n */\nexport async function extractLinks(page: Page): Promise<ExtractedLink[]> {\n  const links: ExtractedLink[] = await page.evaluate(() => {\n    const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.svg'];\n    const videoExtensions = ['.mp4', '.mov', '.avi'];\n    const fileExtensions = [\n      '.pdf',\n      '.doc',\n      '.docx',\n      '.xls',\n      '.xlsx',\n      '.zip',\n      '.rar',\n    ];\n\n    return Array.from(\n      document.querySelectorAll<HTMLAnchorElement>('a[href]'),\n    ).map(anchor => {\n      const hrefAttr = anchor.getAttribute('href') || '';\n      const href = anchor.href;\n      const displayName = anchor.innerText.trim();\n      const inPageLink = hrefAttr.startsWith('#');\n\n      let externalLink = false;\n      let isWebLink = false;\n      let url: URL | undefined;\n\n      try {\n        url = new URL(href);\n        isWebLink = true;\n        externalLink = url.hostname !== window.location.hostname;\n      } catch (e) {\n        isWebLink = false;\n        externalLink = false;\n      }\n\n      const internalLink = isWebLink && !externalLink && !inPageLink;\n\n      const linkResult: {\n        href: string;\n        displayName: string;\n        type: 'statix' | 'webpage';\n        inPageLink: boolean;\n        externalLink: boolean;\n        internalLink: boolean;\n        staticType?: 'video' | 'image' | 'file' | 'other';\n        fileExtension?: string;\n      } = {\n        href,\n        displayName,\n        type: 'webpage',\n        inPageLink,\n        externalLink,\n        internalLink,\n      };\n\n      if (url) {\n        const pathname = url.pathname;\n        const extMatch = pathname.match(/\\.([^/.]+)$/);\n        if (extMatch) {\n          const ext = `.${extMatch[1].toLowerCase()}`;\n\n          if (imageExtensions.includes(ext)) {\n            linkResult.type = 'statix';\n            linkResult.staticType = 'image';\n            linkResult.fileExtension = ext.substring(1);\n          } else if (videoExtensions.includes(ext)) {\n            linkResult.type = 'statix';\n            linkResult.staticType = 'video';\n            linkResult.fileExtension = ext.substring(1);\n          } else if (fileExtensions.includes(ext)) {\n            linkResult.type = 'statix';\n            linkResult.staticType = 'file';\n            linkResult.fileExtension = ext.substring(1);\n          }\n        }\n      }\n\n      return linkResult;\n    });\n  });\n  return links;\n}\n\nexport interface ExtractLinksOptions extends OpenPageOptions {\n  onlyExternal?: boolean;\n  onlyInternal?: boolean;\n  onlyInPage?: boolean;\n  onlyStatic?: boolean;\n}\n\nexport async function extractLinksFromUrl(options: ExtractLinksOptions) {\n  const { browser, page } = await openPage(options);\n  const links = await extractLinks(page);\n  await browser.close();\n  return links;\n}\n","/**\n * Color extraction helpers for use in Puppeteer and other contexts\n * Accepts imageData (Uint8ClampedArray) and returns palette, dominantColor, secondaryColor, and accentColor as hex strings\n *\n * The algorithm follows these steps:\n * 1. Sample pixels from image data for performance\n * 2. Use Median Cut quantization to reduce colors to manageable palette\n * 3. Sort by luminance for predictable filtering\n * 4. Filter out perceptually similar colors using CIELAB Delta E\n * 5. Select dominant, secondary, and accent colors based on vibrancy and contrast rules\n */\n\nexport interface AccessibilityInfo {\n  color: string; // Hex color that provides best contrast with dominant color\n  contrastRatio: number; // WCAG contrast ratio (should be >= 4.5 for AA compliance)\n}\n\nexport interface ExtractedPalette {\n  palette: string[]; // Array of distinct hex colors from the image\n  dominantColor: string | undefined; // Most vibrant/striking color in the palette\n  secondaryColor: string | undefined; // Complementary color based on dominant characteristics\n  accentColor?: string | undefined; // Median appearance color with good contrast and luminance\n  accessibility?: AccessibilityInfo; // Best contrast color for accessibility\n  logs?: string[]; // Debug logs showing the extraction process\n}\n\nexport function extractPaletteFromImageData(\n  imageData: Uint8ClampedArray,\n  options: {\n    deltaEThreshold?: number; // Threshold for CIELAB Delta E color similarity (default: 4)\n    paletteSize?: number; // Maximum number of colors in final palette (default: 12),\n    enableLogs?: boolean; // Whether to enable logs (default: false)\n  } = { enableLogs: false },\n): ExtractedPalette {\n  const {\n    deltaEThreshold = 0.5,\n    paletteSize = 12,\n    enableLogs = false,\n  } = options;\n  const logs: string[] = [];\n\n  const log = (message: string) => {\n    if (enableLogs) {\n      logs.push(message);\n    }\n  };\n\n  // --- Color science helper functions ---\n  /**\n   * Converts hex color string to RGB object\n   * @param hex - Hex color string (e.g., \"#FF0000\" or \"FF0000\")\n   * @returns RGB object or null if invalid hex\n   */\n  const hexToRgb = (\n    hex: string,\n  ): { r: number; g: number; b: number } | null => {\n    const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n    return result\n      ? {\n          r: parseInt(result[1], 16),\n          g: parseInt(result[2], 16),\n          b: parseInt(result[3], 16),\n        }\n      : null;\n  };\n  /**\n   * Calculates relative luminance of an RGB color (WCAG 2.1 formula)\n   * Used for contrast ratio calculations\n   * @param rgb - RGB color object\n   * @returns Luminance value between 0 and 1\n   */\n  const getLuminance = (rgb: { r: number; g: number; b: number }): number => {\n    const a = [rgb.r, rgb.g, rgb.b].map(v => {\n      v /= 255;\n      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n    });\n    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;\n  };\n\n  /**\n   * Calculates contrast ratio between two RGB colors (WCAG 2.1 formula)\n   * @param rgb1 - First RGB color\n   * @param rgb2 - Second RGB color\n   * @returns Contrast ratio (1:1 = no contrast, 21:1 = maximum contrast)\n   */\n  const getContrastRatio = (\n    rgb1: { r: number; g: number; b: number },\n    rgb2: { r: number; g: number; b: number },\n  ): number => {\n    const lum1 = getLuminance(rgb1);\n    const lum2 = getLuminance(rgb2);\n    const brightest = Math.max(lum1, lum2);\n    const darkest = Math.min(lum1, lum2);\n    return (brightest + 0.05) / (darkest + 0.05);\n  };\n  /**\n   * Converts RGB color to HSL (Hue, Saturation, Lightness)\n   * Used for color analysis and vibrancy calculations\n   * @param rgb - RGB color object\n   * @returns HSL object with h (0-360), s (0-1), l (0-1)\n   */\n  const rgbToHsl = (rgb: { r: number; g: number; b: number }) => {\n    // Make r, g, and b fractions of 1\n    const r = rgb.r / 255;\n    const g = rgb.g / 255;\n    const b = rgb.b / 255;\n\n    // Find greatest and smallest channel values\n    const cmin = Math.min(r, g, b);\n    const cmax = Math.max(r, g, b);\n    const delta = cmax - cmin;\n    let h = 0;\n    let s = 0;\n    let l = 0;\n\n    // Calculate hue (0-360 degrees)\n    if (delta == 0) h = 0;\n    else if (cmax == r) h = ((g - b) / delta) % 6;\n    else if (cmax == g) h = (b - r) / delta + 2;\n    else h = (r - g) / delta + 4;\n\n    h = Math.round(h * 60);\n    if (h < 0) h += 360;\n\n    // Calculate lightness (0-1, where 0 is black, 1 is white)\n    l = (cmax + cmin) / 2;\n\n    // Calculate saturation (0-1, where 0 is grayscale, 1 is fully saturated)\n    s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));\n\n    return { h, s, l };\n  };\n  /**\n   * Converts RGB color to CIELAB color space\n   * Used for perceptual color difference calculations (Delta E)\n   * @param rgb - RGB color object\n   * @returns LAB object with l (lightness), a (green-red), b (blue-yellow)\n   */\n  const rgbToLab = (rgb: { r: number; g: number; b: number }) => {\n    let r = rgb.r / 255,\n      g = rgb.g / 255,\n      b = rgb.b / 255;\n    // Gamma correction\n    r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;\n    g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;\n    b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;\n    // Convert to XYZ color space\n    let x = r * 0.4124 + g * 0.3576 + b * 0.1805;\n    let y = r * 0.2126 + g * 0.7152 + b * 0.0722;\n    let z = r * 0.0193 + g * 0.1192 + b * 0.9505;\n    // Normalize to D65 illuminant\n    x /= 95.047;\n    y /= 100;\n    z /= 108.883;\n    // Convert to LAB\n    x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;\n    y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;\n    z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;\n    return { l: 116 * y - 16, a: 500 * (x - y), b: 200 * (y - z) };\n  };\n\n  /**\n   * Calculates CIELAB Delta E (perceptual color difference)\n   * Used to determine if two colors are perceptually similar\n   * @param labA - First LAB color\n   * @param labB - Second LAB color\n   * @returns Delta E value (0 = identical, higher = more different)\n   */\n  const deltaE = (\n    labA: { l: number; a: number; b: number },\n    labB: { l: number; a: number; b: number },\n  ) => {\n    const deltaL = labA.l - labB.l;\n    const deltaA = labA.a - labB.a;\n    const deltaB = labA.b - labB.b;\n    return Math.sqrt(deltaL * deltaL + deltaA * deltaA + deltaB * deltaB);\n  };\n\n  /**\n   * Converts RGB color to hex string\n   * @param pixel - RGB color object\n   * @returns Hex color string (e.g., \"#FF0000\")\n   */\n  const rgbToHex = (pixel: { r: number; g: number; b: number }) => {\n    const componentToHex = (c: number) => {\n      const hex = c.toString(16);\n      return hex.length == 1 ? '0' + hex : hex;\n    };\n    return (\n      '#' +\n      componentToHex(pixel.r) +\n      componentToHex(pixel.g) +\n      componentToHex(pixel.b)\n    ).toUpperCase();\n  };\n\n  /**\n   * Extracts RGB values from image data with sampling for performance\n   * @param imageData - Raw image pixel data (RGBA format)\n   * @param sampleRate - How many pixels to skip (higher = faster but less accurate)\n   * @returns Array of RGB color objects\n   */\n  const buildRgb = (imageData: Uint8ClampedArray, sampleRate: number = 5) => {\n    const rgbValues = [];\n    // Sample pixels for performance, iterating by sampleRate * 4 (RGBA = 4 bytes per pixel)\n    for (let i = 0; i < imageData.length; i += sampleRate * 4) {\n      rgbValues.push({\n        r: imageData[i], // Red channel\n        g: imageData[i + 1], // Green channel\n        b: imageData[i + 2], // Blue channel\n        // Note: Alpha channel (i + 3) is ignored\n      });\n    }\n    return rgbValues;\n  };\n\n  /**\n   * Finds the color channel (R, G, or B) with the largest range\n   * Used by Median Cut quantization algorithm\n   * @param rgbValues - Array of RGB colors\n   * @returns Channel name with biggest range ('r', 'g', or 'b')\n   */\n  const findBiggestColorRange = (\n    rgbValues: { r: number; g: number; b: number }[],\n  ) => {\n    let rMin = Number.MAX_VALUE,\n      gMin = Number.MAX_VALUE,\n      bMin = Number.MAX_VALUE;\n    let rMax = Number.MIN_VALUE,\n      gMax = Number.MIN_VALUE,\n      bMax = Number.MIN_VALUE;\n\n    // Find min/max values for each channel\n    rgbValues.forEach(pixel => {\n      rMin = Math.min(rMin, pixel.r);\n      gMin = Math.min(gMin, pixel.g);\n      bMin = Math.min(bMin, pixel.b);\n      rMax = Math.max(rMax, pixel.r);\n      gMax = Math.max(gMax, pixel.g);\n      bMax = Math.max(bMax, pixel.b);\n    });\n\n    // Calculate ranges and return channel with largest range\n    const rRange = rMax - rMin;\n    const gRange = gMax - gMin;\n    const bRange = bMax - bMin;\n    const biggestRange = Math.max(rRange, gRange, bRange);\n    if (biggestRange === rRange) return 'r';\n    if (biggestRange === gRange) return 'g';\n    return 'b';\n  };\n\n  /**\n   * Median Cut quantization algorithm\n   * Recursively splits color space to create a palette of representative colors\n   * @param rgbValues - Array of RGB colors to quantize\n   * @param depth - Current recursion depth (0-5)\n   * @returns Array of quantized RGB colors\n   */\n  const quantization = (\n    rgbValues: { r: number; g: number; b: number }[],\n    depth: number,\n  ): { r: number; g: number; b: number }[] => {\n    const MAX_DEPTH = 5; // Maximum recursion depth for performance\n\n    // Base case: stop recursion or return average color\n    if (depth === MAX_DEPTH || rgbValues.length === 0) {\n      const color = rgbValues.reduce(\n        (prev, curr) => {\n          prev.r += curr.r;\n          prev.g += curr.g;\n          prev.b += curr.b;\n          return prev;\n        },\n        { r: 0, g: 0, b: 0 },\n      );\n      // Calculate average color\n      color.r = Math.round(color.r / rgbValues.length);\n      color.g = Math.round(color.g / rgbValues.length);\n      color.b = Math.round(color.b / rgbValues.length);\n      return [color];\n    }\n\n    // Find channel with biggest range and sort by it\n    const componentToSortBy = findBiggestColorRange(rgbValues);\n    rgbValues.sort((p1, p2) => p1[componentToSortBy] - p2[componentToSortBy]);\n\n    // Split at median and recurse\n    const mid = Math.floor(rgbValues.length / 2);\n    return [\n      ...quantization(rgbValues.slice(0, mid), depth + 1),\n      ...quantization(rgbValues.slice(mid), depth + 1),\n    ];\n  };\n\n  /**\n   * Sorts colors by luminance (brightness) in descending order\n   * @param rgbValues - Array of RGB colors\n   * @returns Sorted array (brightest first)\n   */\n  const orderByLuminance = (\n    rgbValues: { r: number; g: number; b: number }[],\n  ) => {\n    const calculateLuminance = (p: { r: number; g: number; b: number }) =>\n      0.2126 * p.r + 0.7152 * p.g + 0.0722 * p.b; // Standard luminance formula\n    return rgbValues.sort(\n      (p1, p2) => calculateLuminance(p2) - calculateLuminance(p1),\n    );\n  };\n  // --- End helpers ---\n\n  // Initialize result variables\n  let palette: string[] = [];\n  let dominantColor: string | undefined = undefined;\n  let secondaryColor: string | undefined = undefined;\n  let accentColor: string | undefined = undefined;\n  let accessibility: AccessibilityInfo | undefined = undefined;\n\n  try {\n    log(\n      `Starting palette extraction. Options: deltaEThreshold=${deltaEThreshold}, paletteSize=${paletteSize}`,\n    );\n\n    // Step 1: Build a list of RGB values from the image data, sampling for performance\n    let rgbArray = buildRgb(imageData, 5);\n    log(`Built RGB array of ${rgbArray.length} sample pixels.`);\n\n    // Step 2: Reduce the number of colors to a manageable palette using Median Cut quantization\n    let quantColors = quantization(rgbArray, 0);\n    log(`Quantized colors down to ${quantColors.length} primary colors.`);\n\n    // Step 3: Sort the palette by luminance (brightness) to handle filtering predictably\n    let orderedByColor = orderByLuminance(quantColors);\n    log('Sorted quantized colors by luminance.');\n\n    // Step 4: Filter out colors that are too perceptually similar using CIELAB Delta E\n    const distinctColors: { r: number; g: number; b: number }[] = [];\n    if (orderedByColor.length > 0) {\n      distinctColors.push(orderedByColor[0]); // Always include the first (brightest) color\n      const labCache = [rgbToLab(orderedByColor[0])]; // Cache LAB values for performance\n\n      for (let i = 1; i < orderedByColor.length; i++) {\n        if (distinctColors.length >= paletteSize) {\n          log(`Reached target palette size of ${paletteSize}. Stopping.`);\n          break;\n        }\n        const currentLab = rgbToLab(orderedByColor[i]);\n        let isDistinct = true;\n\n        // Check against all previously accepted distinct colors\n        for (const existingLab of labCache) {\n          if (deltaE(currentLab, existingLab) < deltaEThreshold) {\n            isDistinct = false;\n            break; // Color is too similar, skip it\n          }\n        }\n\n        if (isDistinct) {\n          distinctColors.push(orderedByColor[i]);\n          labCache.push(currentLab);\n        }\n      }\n    }\n    log(\n      `Filtered down to ${distinctColors.length} perceptually distinct colors.`,\n    );\n\n    // Step 5: Convert the final list of distinct RGB colors to hex strings\n    palette = distinctColors.map(rgbToHex);\n    log(`Final palette generated: [${palette.join(', ')}]`);\n\n    // Step 6: Select dominant, secondary, and accent colors based on vibrancy and contrast rules\n    if (palette.length > 0) {\n      // Convert palette to RGB and HSL for analysis\n      const paletteRgb = palette.map(hex => ({ hex, rgb: hexToRgb(hex)! }));\n      const paletteHsl = paletteRgb.map(c => ({ ...c, hsl: rgbToHsl(c.rgb) }));\n\n      // a) Find the most \"striking\" color as dominant (highest vibrancy score)\n      const getVibrancy = (hsl: { h: number; s: number; l: number }) =>\n        hsl.s * (1 - Math.abs(hsl.l - 0.5)); // Higher for balanced saturation/luminance\n      paletteHsl.sort((a, b) => getVibrancy(b.hsl) - getVibrancy(a.hsl));\n      const dominantInfo = paletteHsl[0];\n      dominantColor = dominantInfo.hex;\n      log(`Selected most vibrant color as dominantColor: ${dominantColor}`);\n\n      // Create a pool of remaining colors (excluding dominant)\n      const remainingColorsHsl = paletteHsl.filter(\n        c => c.hex !== dominantColor,\n      );\n\n      // b) Classify the dominant color and apply rules for secondary color selection\n      const dominantLuminance = dominantInfo.hsl.l;\n      const remainingByLuminance = [...remainingColorsHsl].sort(\n        (a, b) => b.hsl.l - a.hsl.l,\n      ); // Brightest first\n      const remainingBySaturation = [...remainingColorsHsl].sort(\n        (a, b) => a.hsl.s - b.hsl.s,\n      ); // Muted first\n\n      // Select secondary color based on dominant color characteristics\n      if (dominantLuminance > 0.65) {\n        // --- Dominant is BRIGHT ---\n        log(`Dominant color is BRIGHT.`);\n        secondaryColor = remainingByLuminance[0]?.hex; // Next brightest\n        log(`-> Secondary (brightest remaining): ${secondaryColor}`);\n      } else if (dominantLuminance < 0.35) {\n        // --- Dominant is DARK ---\n        log(`Dominant color is DARK.`);\n        secondaryColor = remainingBySaturation[0]?.hex; // Most muted\n        log(`-> Secondary (most muted): ${secondaryColor}`);\n      } else {\n        // --- Dominant is MUTED/MID-TONE ---\n        log(`Dominant color is MUTED.`);\n        secondaryColor = remainingBySaturation[0]?.hex; // Most muted\n        log(`-> Secondary (most muted): ${secondaryColor}`);\n      }\n\n      // c) Select accent color with good contrast, luminance, and median appearance\n      // Filter out dominant and secondary colors to find median appearance\n      const accentCandidates = paletteHsl.filter(\n        c => c.hex !== dominantColor && c.hex !== secondaryColor,\n      );\n\n      if (accentCandidates.length > 0) {\n        // Calculate vibrancy score for each candidate (saturation * luminance balance)\n        const candidatesWithScores = accentCandidates.map(c => ({\n          ...c,\n          vibrancyScore: c.hsl.s * (1 - Math.abs(c.hsl.l - 0.5)), // Higher for balanced saturation/luminance\n          contrastWithDominant: getContrastRatio(c.rgb, dominantInfo.rgb),\n        }));\n\n        // Sort by vibrancy score (most striking first) and ensure good contrast\n        candidatesWithScores.sort((a, b) => {\n          // Prioritize good contrast with dominant color (minimum 3:1 ratio)\n          const aHasGoodContrast = a.contrastWithDominant >= 3.0;\n          const bHasGoodContrast = b.contrastWithDominant >= 3.0;\n\n          if (aHasGoodContrast && !bHasGoodContrast) return -1;\n          if (!aHasGoodContrast && bHasGoodContrast) return 1;\n\n          // If both have good contrast, sort by vibrancy\n          return b.vibrancyScore - a.vibrancyScore;\n        });\n\n        // Select the most striking color with good contrast as accent\n        accentColor = candidatesWithScores[0]?.hex;\n        log(\n          `-> Accent (most striking with good contrast): ${accentColor} (vibrancy: ${candidatesWithScores[0]?.vibrancyScore.toFixed(3)}, contrast: ${candidatesWithScores[0]?.contrastWithDominant.toFixed(2)})`,\n        );\n      }\n\n      // d) Calculate accessibility color (best contrast option: black or white)\n      const dominantRgb = hexToRgb(dominantColor);\n      if (dominantRgb) {\n        const black = { r: 0, g: 0, b: 0 };\n        const white = { r: 255, g: 255, b: 255 };\n        const contrastWithBlack = getContrastRatio(dominantRgb, black);\n        const contrastWithWhite = getContrastRatio(dominantRgb, white);\n\n        // Choose the color with higher contrast ratio\n        if (contrastWithBlack > contrastWithWhite) {\n          accessibility = {\n            color: '#000000',\n            contrastRatio: contrastWithBlack,\n          };\n        } else {\n          accessibility = {\n            color: '#FFFFFF',\n            contrastRatio: contrastWithWhite,\n          };\n        }\n        log(\n          `Accessibility color is ${\n            accessibility.color\n          } with contrast ${accessibility.contrastRatio.toFixed(2)}.`,\n        );\n      }\n    }\n  } catch (e: any) {\n    log(`ERROR during palette extraction: ${e.message || 'Unknown error'}`);\n    // ignore errors, leave colors undefined\n  }\n  return {\n    palette,\n    dominantColor,\n    secondaryColor,\n    accentColor,\n    accessibility,\n    logs,\n  };\n}\n","import { Page } from 'puppeteer-core';\nimport { openPage, OpenPageOptions } from './openPage';\nimport { extractPaletteFromImageData, ExtractedPalette } from './colorExtract';\n\nexport interface AccessibilityInfo {\n  color: string;\n  contrastRatio: number;\n}\nexport interface ExtractedImage {\n  src: string | null;\n  srcset: string | null;\n  responsiveImages: { url: string; size: string }[] | null;\n  alt: string | null;\n  imgPermalink: string | null;\n  pagePermalink: string;\n  width: number | null;\n  height: number | null;\n  dominantColor?: string | null;\n  secondaryColor?: string | null;\n  accentColor?: string | null;\n  accessibility?: AccessibilityInfo | null;\n  palette?: string[] | null;\n  colorExtractionLogs?: string[];\n}\n\nexport async function extractImages(\n  page: Page,\n  options?: { enableColorExtraction?: boolean },\n): Promise<ExtractedImage[]> {\n  console.log('Extracting images from page...');\n  const pageUrl = page.url();\n  const enableColorExtraction = options?.enableColorExtraction;\n  // Convert the function to a string to pass it into the browser context reliably.\n  const extractPaletteFnString = extractPaletteFromImageData.toString();\n\n  const images = await page.$$eval(\n    'img',\n    (\n      imgs: HTMLImageElement[],\n      pageUrl: string,\n      enableColorExtraction: boolean,\n      _extractPaletteString: string,\n    ) => {\n      // Reconstruct the function inside the browser context from the string.\n      const _extractPalette = new Function(\n        `return ${_extractPaletteString}`,\n      )() as (imageData: Uint8ClampedArray) => ExtractedPalette;\n\n      return imgs.map((img: HTMLImageElement) => {\n        let palette: string[] | undefined = undefined;\n        let dominantColor: string | undefined = undefined;\n        let secondaryColor: string | undefined = undefined;\n        let accentColor: string | undefined = undefined;\n        let accessibility: AccessibilityInfo | undefined = undefined;\n        const logs: string[] = [];\n        if (enableColorExtraction) {\n          logs.push(`Color extraction enabled for image: ${img.src}`);\n          try {\n            const canvas = document.createElement('canvas');\n            canvas.width = img.naturalWidth || img.width;\n            canvas.height = img.naturalHeight || img.height;\n            if (canvas.width && canvas.height) {\n              logs.push(\n                `Created canvas with dimensions: ${canvas.width}x${canvas.height}`,\n              );\n              const ctx = canvas.getContext('2d');\n              if (ctx) {\n                ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n                const imageData = ctx.getImageData(\n                  0,\n                  0,\n                  canvas.width,\n                  canvas.height,\n                ).data;\n                const result = _extractPalette(imageData);\n                palette = result.palette;\n                dominantColor = result.dominantColor;\n                secondaryColor = result.secondaryColor;\n                accentColor = result.accentColor;\n                accessibility = result.accessibility;\n                if (result.logs) {\n                  logs.push(...result.logs);\n                }\n              } else {\n                logs.push('Failed to get 2D context from canvas.');\n              }\n            } else {\n              logs.push(\n                `Skipping color extraction: Invalid image dimensions (${img.naturalWidth}x${img.naturalHeight})`,\n              );\n            }\n          } catch (e: any) {\n            logs.push(\n              `ERROR during canvas operations: ${e.message || 'Unknown error'}`,\n            );\n          }\n        }\n        const parentAnchor = img.closest('a');\n        const imgPermalink = parentAnchor ? parentAnchor.href : pageUrl;\n        const result: any = {\n          src: img.getAttribute('src'),\n          srcset: img.getAttribute('srcset'),\n          responsiveImages:\n            img\n              .getAttribute('srcset')\n              ?.split(',')\n              .map(src => {\n                const trimmedSrc = src.trim();\n                if (!trimmedSrc) {\n                  return null;\n                }\n                const parts = trimmedSrc.split(/\\s+/);\n                const url = parts[0];\n                const size = parts.length > 1 ? parts[1] : '';\n                if (!url) {\n                  return null;\n                }\n                return { url, size };\n              })\n              .filter(\n                (item): item is { url: string; size: string } => item !== null,\n              ) || null,\n          alt: img.getAttribute('alt'),\n          imgPermalink: imgPermalink,\n          pagePermalink: pageUrl,\n          width: img.width || null,\n          height: img.height || null,\n        };\n        if (enableColorExtraction) {\n          result.dominantColor = dominantColor || null;\n          result.secondaryColor = secondaryColor || null;\n          result.accentColor = accentColor || null;\n          result.accessibility = accessibility || null;\n          result.palette = palette || null;\n          result.colorExtractionLogs = logs;\n        }\n        return result;\n      });\n    },\n    pageUrl,\n    Boolean(enableColorExtraction),\n    extractPaletteFnString,\n  );\n  console.log(`Extracted ${images.length} images.`);\n  return images;\n}\n\nexport async function extractBackgroundImages(\n  page: Page,\n): Promise<ExtractedImage[]> {\n  console.log('Deep extracting background images from page...');\n  const pageUrl = page.url();\n  const images = await page.evaluate(pageUrl => {\n    const allImages: ExtractedImage[] = [];\n    const elements = document.querySelectorAll('a[href^=\"/jobs/\"]');\n    console.log(\n      `Found ${elements.length} elements to scan for background images.`,\n    );\n\n    for (const element of Array.from(elements)) {\n      let backgroundImage = (element as HTMLElement).style?.backgroundImage;\n\n      if (!backgroundImage || backgroundImage === 'none') {\n        backgroundImage = window\n          .getComputedStyle(element)\n          .getPropertyValue('background-image');\n      }\n\n      if (backgroundImage && backgroundImage !== 'none') {\n        const anchor = (element as HTMLElement).closest('a');\n        const imgPermalink = anchor ? anchor.href : pageUrl;\n        const width = (element as HTMLElement).clientWidth;\n        const height = (element as HTMLElement).clientHeight;\n        console.log(\n          `Processing element ${element.tagName} with background-image: ${backgroundImage}`,\n        );\n        const imageSetRegex = /(-webkit-)?image-set\\(([^)]+)\\)/g;\n        let imageSetMatch;\n        let processedImageSet = false;\n\n        while ((imageSetMatch = imageSetRegex.exec(backgroundImage)) !== null) {\n          processedImageSet = true;\n          const imageSetContent = imageSetMatch[2];\n          if (imageSetContent) {\n            const responsiveImages: { url: string; size: string }[] = [];\n            const parts = imageSetContent.split(',');\n            parts.forEach(part => {\n              const trimmedPart = part.trim();\n              const urlMatch = trimmedPart.match(/url\\((['\"]?)(.*?)\\1\\)/);\n              const sizeMatch = trimmedPart.match(/\\s+([\\d.]+)x/);\n              if (urlMatch && urlMatch[2]) {\n                const url = urlMatch[2];\n                if (url && !url.startsWith('data:')) {\n                  responsiveImages.push({\n                    url: url,\n                    size: sizeMatch ? sizeMatch[1] + 'x' : '1x',\n                  });\n                }\n              }\n            });\n\n            if (responsiveImages.length > 0) {\n              allImages.push({\n                src: responsiveImages[0]?.url || null,\n                srcset: responsiveImages\n                  .map(img => `${img.url} ${img.size}`)\n                  .join(', '),\n                responsiveImages: responsiveImages,\n                alt: `Background image from ${element.tagName.toLowerCase()}`,\n                imgPermalink: imgPermalink,\n                pagePermalink: pageUrl,\n                width,\n                height,\n              });\n            }\n          }\n        }\n\n        if (processedImageSet) {\n          continue;\n        }\n\n        const urlRegex = /url\\((['\"]?)(.*?)\\1\\)/g;\n        let urlMatch;\n        while ((urlMatch = urlRegex.exec(backgroundImage)) !== null) {\n          const url = urlMatch[2].trim();\n          if (url && !url.startsWith('data:')) {\n            if (\n              !allImages.some(\n                img =>\n                  img.src === url ||\n                  (img.responsiveImages &&\n                    img.responsiveImages.some(r => r.url === url)),\n              )\n            ) {\n              allImages.push({\n                src: url,\n                srcset: null,\n                responsiveImages: null,\n                alt: `Background image from ${element.tagName.toLowerCase()}`,\n                imgPermalink: imgPermalink,\n                pagePermalink: pageUrl,\n                width,\n                height,\n              });\n            }\n          }\n        }\n      }\n    }\n    return allImages;\n  }, pageUrl);\n\n  console.log(`Deep extracted ${images.length} background images.`);\n  return images;\n}\n\nexport async function extractImagesFromURL(\n  options: OpenPageOptions & {\n    deepExtract?: boolean;\n    enableColorExtraction?: boolean;\n  },\n) {\n  try {\n    console.log(`Starting image extraction from URL: ${options.url}`);\n    const { browser, page } = await openPage(options);\n    console.log('Page has been opened.');\n\n    if (options.deepExtract) {\n      console.log('Scrolling page to trigger lazy loading...');\n      await page.evaluate(async () => {\n        const scrollableElement =\n          document.getElementById('pageScroll') || document.body;\n        await new Promise<void>(resolve => {\n          let lastHeight = -1;\n          let steadyCount = 0;\n          let totalScrolls = 0;\n          const maxSteadyCount = 3;\n          const maxScrolls = 30; // limit to avoid infinite scroll\n          const timer = setInterval(() => {\n            totalScrolls++;\n            const newHeight = scrollableElement.scrollHeight;\n            if (newHeight === lastHeight) {\n              steadyCount++;\n            } else {\n              steadyCount = 0; // reset if new content loaded\n            }\n\n            if (steadyCount >= maxSteadyCount || totalScrolls >= maxScrolls) {\n              clearInterval(timer);\n              resolve();\n              return;\n            }\n\n            scrollableElement.scrollTo(0, newHeight);\n            lastHeight = newHeight;\n          }, 500);\n        });\n      });\n      console.log(\n        'Finished scrolling. Waiting for 5 seconds for content to load...',\n      );\n      await new Promise(resolve => setTimeout(resolve, 5000));\n    }\n    let images = await extractImages(page, {\n      enableColorExtraction: options.enableColorExtraction,\n    });\n    if (options.deepExtract) {\n      const backgroundImages = await extractBackgroundImages(page);\n      images = images.concat(backgroundImages);\n    }\n    // Log the results for debugging\n    images.forEach(img => {\n      if (img.colorExtractionLogs && img.colorExtractionLogs.length > 0) {\n        console.log(`--- Logs for image: ${img.src} ---`);\n        img.colorExtractionLogs.forEach(log => console.log(log));\n        console.log('--- End of logs ---');\n      }\n    });\n    console.log('Closing browser session.');\n    await browser.close();\n    console.log('Browser has been closed.');\n    return images;\n  } catch (error) {\n    console.error('Error extracting images:', error);\n    throw error;\n  }\n}\n","import { Page } from 'puppeteer-core';\nimport { openPage, OpenPageOptions } from './openPage';\n\nexport interface ExtractedVideo {\n  src: string | null;\n  sources: { src: string; type: string | null }[] | null;\n  poster: string | null;\n  videoPermalink: string | null;\n  pagePermalink: string;\n  width: number | null;\n  height: number | null;\n}\n\nexport async function extractVideos(page: Page): Promise<ExtractedVideo[]> {\n  console.log('Extracting videos from page...');\n  const pageUrl = page.url();\n  const videos = await page.$$eval(\n    'video',\n    (videos: HTMLVideoElement[], pageUrl: string) =>\n      videos.map((video: HTMLVideoElement) => {\n        const parentAnchor = video.closest('a');\n        const videoPermalink = parentAnchor ? parentAnchor.href : pageUrl;\n\n        const sourceElements = Array.from(video.querySelectorAll('source'));\n        const sources =\n          sourceElements.length > 0\n            ? sourceElements.map(source => ({\n                src: source.src,\n                type: source.getAttribute('type'),\n              }))\n            : null;\n\n        return {\n          src: video.getAttribute('src'),\n          sources: sources,\n          poster: video.getAttribute('poster'),\n          videoPermalink: videoPermalink,\n          pagePermalink: pageUrl,\n          width: video.videoWidth || video.width || null,\n          height: video.videoHeight || video.height || null,\n        };\n      }),\n    pageUrl,\n  );\n  console.log(`Extracted ${videos.length} videos.`);\n  return videos;\n}\n\nexport async function extractVideosFromURL(\n  options: OpenPageOptions & {\n    deepExtract?: boolean;\n  },\n) {\n  try {\n    console.log(`Starting video extraction from URL: ${options.url}`);\n    const { browser, page } = await openPage(options);\n    console.log('Page has been opened.');\n\n    if (options.deepExtract) {\n      console.log('Scrolling page to trigger lazy loading...');\n      await page.evaluate(async () => {\n        const scrollableElement =\n          document.getElementById('pageScroll') || document.body;\n        await new Promise<void>(resolve => {\n          let lastHeight = -1;\n          let steadyCount = 0;\n          let totalScrolls = 0;\n          const maxSteadyCount = 3;\n          const maxScrolls = 30; // limit to avoid infinite scroll\n          const timer = setInterval(() => {\n            totalScrolls++;\n            const newHeight = scrollableElement.scrollHeight;\n            if (newHeight === lastHeight) {\n              steadyCount++;\n            } else {\n              steadyCount = 0; // reset if new content loaded\n            }\n\n            if (steadyCount >= maxSteadyCount || totalScrolls >= maxScrolls) {\n              clearInterval(timer);\n              resolve();\n              return;\n            }\n\n            scrollableElement.scrollTo(0, newHeight);\n            lastHeight = newHeight;\n          }, 500);\n        });\n      });\n      console.log(\n        'Finished scrolling. Waiting for 5 seconds for content to load...',\n      );\n      await new Promise(resolve => setTimeout(resolve, 5000));\n    }\n\n    const videos = await extractVideos(page);\n\n    console.log('Closing browser session.');\n    await browser.close();\n    console.log('Browser has been closed.');\n    return videos;\n  } catch (error) {\n    console.error('Error extracting videos:', error);\n    throw error;\n  }\n}\n","import { extractImagesFromURL } from './functions/extractImages';\nimport { extractLinksFromUrl } from './functions/extractLinks';\nimport { extractVideosFromURL } from './functions/extractVideos';\nimport { extractWebpage } from './functions/extractWebpage';\nimport { openPage } from './functions/openPage';\nimport { takeSnapShot } from './functions/takeSnapShot';\n\n/**\n * @description PuppeteerSLS is a class that provides a set of functions for running Puppeteer on serverless functions.\n * every instance starts from a new browser instance.\n * @example\n * ```ts\n * const puppeteerSLS = new PuppeteerSLS();\n * const images = await puppeteerSLS.extractImagesFromURL('https://www.google.com');\n * ```\n */\nexport const PuppeteerSLS = {\n  extractImagesFromURL,\n  extractLinksFromUrl,\n  extractWebpage,\n  openPage,\n  takeSnapShot,\n};\n"],"mappings":"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","names":["isLocal","imageData","pageUrl","enableColorExtraction","result","urlMatch","videos","pageUrl"]}