{"version":3,"sources":["../src/exceptions.ts","../src/utils.ts","../src/scraper.ts","../src/index.ts"],"names":["dayjs","customParseFormat","utc","timezone","axios","cheerio","CookieJar","wrapper"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base exception for all BCCR-related errors\n */\nexport class BCCRError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'BCCRError';\n    // Maintains proper stack trace for where our error was thrown (only available on V8)\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, this.constructor);\n    }\n  }\n}\n\n/**\n * Raised when scraping the BCCR website fails\n */\nexport class BCCRScrapingError extends BCCRError {\n  constructor(message: string) {\n    super(message);\n    this.name = 'BCCRScrapingError';\n  }\n}\n\n/**\n * Raised when date validation or parsing fails\n */\nexport class BCCRDateError extends BCCRError {\n  constructor(message: string) {\n    super(message);\n    this.name = 'BCCRDateError';\n  }\n}\n\n/**\n * Raised when connection to BCCR website fails\n */\nexport class BCCRConnectionError extends BCCRError {\n  constructor(message: string) {\n    super(message);\n    this.name = 'BCCRConnectionError';\n  }\n}\n\n/**\n * Raised when parsing HTML response fails\n */\nexport class BCCRParseError extends BCCRError {\n  constructor(message: string) {\n    super(message);\n    this.name = 'BCCRParseError';\n  }\n}\n","import dayjs from 'dayjs';\nimport customParseFormat from 'dayjs/plugin/customParseFormat.js';\nimport utc from 'dayjs/plugin/utc.js';\nimport timezone from 'dayjs/plugin/timezone.js';\nimport { BCCRDateError } from './exceptions';\n\n// Enable plugins\ndayjs.extend(customParseFormat);\ndayjs.extend(utc);\ndayjs.extend(timezone);\n\n/**\n * Spanish month names mapping\n */\nconst SPANISH_MONTHS: Record<string, number> = {\n  enero: 1,\n  febrero: 2,\n  marzo: 3,\n  abril: 4,\n  mayo: 5,\n  junio: 6,\n  julio: 7,\n  agosto: 8,\n  septiembre: 9,\n  octubre: 10,\n  noviembre: 11,\n  diciembre: 12,\n};\n\n/**\n * Parses Spanish date string to ISO format\n * @param dateStr - Spanish date string (e.g., \"lunes, 4 de noviembre de 2025\")\n * @returns ISO date string (YYYY-MM-DD)\n * @throws {BCCRDateError} If date parsing fails\n */\nexport function parseSpanishDate(dateStr: string): string {\n  try {\n    // Remove day of week if present (e.g., \"lunes, \")\n    let cleanDate = dateStr.replace(/^[a-záéíóúñ]+,\\s*/i, '');\n\n    // Extract day, month, and year using regex\n    // Pattern: \"4 de noviembre de 2025\"\n    const pattern = /(\\d{1,2})\\s+de\\s+([a-záéíóúñ]+)\\s+de\\s+(\\d{4})/i;\n    const match = cleanDate.match(pattern);\n\n    if (!match) {\n      throw new Error(`Could not parse date format: ${dateStr}`);\n    }\n\n    const day = parseInt(match[1], 10);\n    const monthName = match[2].toLowerCase();\n    const year = parseInt(match[3], 10);\n\n    const month = SPANISH_MONTHS[monthName];\n    if (!month) {\n      throw new Error(`Unknown Spanish month: ${monthName}`);\n    }\n\n    // Validate day range before creating date\n    if (day < 1 || day > 31) {\n      throw new Error(`Invalid day: ${day} (must be between 1 and 31)`);\n    }\n\n    // Create date and validate\n    const date = dayjs(`${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`);\n\n    if (!date.isValid()) {\n      throw new Error(`Invalid date values: day=${day}, month=${month}, year=${year}`);\n    }\n\n    // Additional validation: check if the created date matches input values\n    // This catches cases like February 30th which dayjs might silently correct\n    if (date.date() !== day || date.month() + 1 !== month || date.year() !== year) {\n      throw new Error(`Invalid date: ${day}/${month}/${year} (date does not exist in calendar)`);\n    }\n\n    return date.format('YYYY-MM-DD');\n  } catch (error) {\n    throw new BCCRDateError(\n      `Failed to parse Spanish date \"${dateStr}\": ${error instanceof Error ? error.message : String(error)}`\n    );\n  }\n}\n\n/**\n * Formats date object to Spanish date format (DD/MM/YYYY) for BCCR\n * @param date - Date object or ISO string\n * @returns Formatted date string (DD/MM/YYYY)\n */\nexport function formatSpanishDate(date: Date | string): string {\n  const d = dayjs(date);\n  if (!d.isValid()) {\n    throw new BCCRDateError(`Invalid date: ${date}`);\n  }\n  return d.format('DD/MM/YYYY');\n}\n\n/**\n * Parses BCCR timestamp string to ISO format\n * @param timestampStr - Timestamp string (e.g., \"04/11/2025 10:30:00 a.m.\" or \"04/11/2025 10:30 a.m.\")\n * @returns ISO timestamp string\n */\nexport function formatLastUpdate(timestampStr: string): string {\n  try {\n    // Clean up the string\n    let cleaned = timestampStr.trim();\n\n    // Replace Spanish AM/PM indicators with standard format\n    // Handle variations: \"a.m.\", \"a. m.\", \"p.m.\", \"p. m.\"\n    cleaned = cleaned.replace(/\\s*a\\.\\s*m\\./i, ' AM').replace(/\\s*p\\.\\s*m\\./i, ' PM');\n\n    // Normalize multiple spaces to single space (handles extra whitespace from HTML)\n    cleaned = cleaned.replace(/\\s+/g, ' ');\n\n    // Try parsing with seconds first: \"DD/MM/YYYY hh:mm:ss A\"\n    // Parse in Costa Rica timezone (UTC-6) since BCCR times are local\n    let parsed = dayjs.tz(cleaned, 'DD/MM/YYYY hh:mm:ss A', 'America/Costa_Rica');\n\n    if (!parsed.isValid()) {\n      // Try without seconds: \"DD/MM/YYYY hh:mm A\"\n      parsed = dayjs.tz(cleaned, 'DD/MM/YYYY hh:mm A', 'America/Costa_Rica');\n    }\n\n    if (!parsed.isValid()) {\n      // Try without time\n      const dateOnly = dayjs.tz(cleaned.split(' ')[0], 'DD/MM/YYYY', 'America/Costa_Rica');\n      if (dateOnly.isValid()) {\n        return dateOnly.toISOString();\n      }\n      throw new Error('Invalid timestamp format');\n    }\n\n    return parsed.toISOString();\n  } catch (error) {\n    // Return original string if parsing fails\n    return timestampStr;\n  }\n}\n\n/**\n * Validates date parameter\n * @param dateStr - Date string in YYYY-MM-DD or DD/MM/YYYY format\n * @returns Validated date object\n * @throws {BCCRDateError} If date is invalid\n */\nexport function validateDateParameter(dateStr: string): dayjs.Dayjs {\n  let date: dayjs.Dayjs;\n\n  // Try ISO format first (YYYY-MM-DD)\n  date = dayjs(dateStr, 'YYYY-MM-DD', true);\n\n  if (!date.isValid()) {\n    // Try DD/MM/YYYY format (with leading zeros)\n    date = dayjs(dateStr, 'DD/MM/YYYY', true);\n  }\n\n  if (!date.isValid()) {\n    // Try D/M/YYYY format (without leading zeros)\n    date = dayjs(dateStr, 'D/M/YYYY', true);\n  }\n\n  if (!date.isValid()) {\n    // Try DD/M/YYYY format (day with leading zero, month without)\n    date = dayjs(dateStr, 'DD/M/YYYY', true);\n  }\n\n  if (!date.isValid()) {\n    // Try D/MM/YYYY format (day without leading zero, month with)\n    date = dayjs(dateStr, 'D/MM/YYYY', true);\n  }\n\n  if (!date.isValid()) {\n    throw new BCCRDateError(\n      `Invalid date format: ${dateStr}. Expected YYYY-MM-DD or DD/MM/YYYY`\n    );\n  }\n\n  return date;\n}\n\n/**\n * Validates that date is within acceptable range\n * @param dateStr - Date string\n * @param maxDaysBack - Maximum number of days back allowed (default: Infinity)\n * @throws {BCCRDateError} If date is out of range\n */\nexport function validateDateRange(dateStr: string, maxDaysBack: number = Infinity): void {\n  const date = validateDateParameter(dateStr);\n  const today = dayjs();\n  const minDate = dayjs('2000-01-01'); // BCCR calendar epoch\n\n  if (date.isAfter(today)) {\n    throw new BCCRDateError(`Date cannot be in the future: ${dateStr}`);\n  }\n\n  if (date.isBefore(minDate)) {\n    throw new BCCRDateError(\n      `Date cannot be before ${minDate.format('YYYY-MM-DD')}: ${dateStr}`\n    );\n  }\n\n  // Check configurable max_days_back limit\n  if (maxDaysBack !== Infinity) {\n    const daysBack = today.diff(date, 'day');\n    if (daysBack > maxDaysBack) {\n      const oldestAllowed = today.subtract(maxDaysBack, 'day').format('YYYY-MM-DD');\n      throw new BCCRDateError(\n        `Date is too far in the past. Maximum ${maxDaysBack} days back allowed. Oldest date: ${oldestAllowed}`\n      );\n    }\n  }\n}\n\n/**\n * Converts date to calendar days argument for ASP.NET calendar control\n * The calendar uses an epoch of January 1, 2000\n * @param targetDate - Target date\n * @returns Number of days since January 1, 2000\n */\nexport function dateToCalendarDays(targetDate: dayjs.Dayjs): number {\n  const epoch = dayjs('2000-01-01');\n  return targetDate.diff(epoch, 'day');\n}\n\n/**\n * Parses rate string to number\n * @param rateStr - Rate string (e.g., \"532.50\", \"532,50\", \"-\", \"N/D\")\n * @returns Parsed rate or null if not available\n */\nexport function parseRate(rateStr: string): number | null {\n  const cleaned = rateStr.trim();\n\n  // Handle missing data indicators\n  if (cleaned === '-' || cleaned === 'N/D' || cleaned === '' || cleaned === 'N.D.') {\n    return null;\n  }\n\n  // Replace comma with period for decimal separator\n  const normalized = cleaned.replace(',', '.');\n\n  const parsed = parseFloat(normalized);\n\n  if (isNaN(parsed)) {\n    return null;\n  }\n\n  return parsed;\n}\n\n/**\n * Calculates number of months between two dates\n * Uses explicit calculation to match Python implementation exactly\n * @param startDate - Start date (earlier date)\n * @param endDate - End date (later date)\n * @returns Number of months difference\n */\nexport function monthsBetween(startDate: dayjs.Dayjs, endDate: dayjs.Dayjs): number {\n  // Explicit calculation matching Python: (endDate.year - startDate.year) * 12 + (endDate.month - startDate.month)\n  return (endDate.year() - startDate.year()) * 12 + (endDate.month() - startDate.month());\n}\n","import axios, { AxiosError, AxiosInstance } from 'axios';\nimport * as cheerio from 'cheerio';\nimport dayjs from 'dayjs';\nimport { wrapper } from 'axios-cookiejar-support';\nimport { CookieJar } from 'tough-cookie';\nimport {\n  BCCRConnectionError,\n  BCCRScrapingError,\n  BCCRParseError,\n} from './exceptions';\nimport {\n  parseSpanishDate,\n  formatLastUpdate,\n  parseRate,\n  dateToCalendarDays,\n  monthsBetween,\n} from './utils';\nimport type {\n  EntityData,\n  ScrapeResult,\n  ViewStateData,\n  HierarchicalData,\n  EntitySummary,\n} from './types';\n\nconst VENTANILLA_URL =\n  'https://gee.bccr.fi.cr/indicadoreseconomicos/Cuadros/frmConsultaTCVentanilla.aspx';\n\n/**\n * Main scraper function - orchestrates data fetching\n * @param date - Optional date in YYYY-MM-DD format (defaults to today)\n * @returns Scrape result with entities and date\n */\nexport async function scrapeVentanillaPage(\n  date?: string\n): Promise<ScrapeResult> {\n  try {\n    let html: string;\n\n    if (date) {\n      // Fetch historical data\n      html = await fetchVentanillaForSpecificDate(dayjs(date));\n    } else {\n      // Fetch current data (simple GET request)\n      const response = await axios.get(VENTANILLA_URL, {\n        timeout: 30000,\n        headers: {\n          'User-Agent':\n            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',\n        },\n      });\n      html = response.data;\n    }\n\n    const $ = cheerio.load(html);\n\n    // Extract date from page\n    const pageDate = extractPageDate($);\n\n    // Parse the exchange rate table\n    const entities = parseExchangeRateTable($);\n\n    return {\n      entities,\n      date: pageDate,\n    };\n  } catch (error) {\n    if (error instanceof BCCRConnectionError || error instanceof BCCRScrapingError || error instanceof BCCRParseError) {\n      throw error;\n    }\n\n    if (axios.isAxiosError(error)) {\n      const axiosError = error as AxiosError;\n      throw new BCCRConnectionError(\n        `Failed to connect to BCCR: ${axiosError.message}`\n      );\n    }\n\n    throw new BCCRScrapingError(\n      `Scraping failed: ${error instanceof Error ? error.message : String(error)}`\n    );\n  }\n}\n\n/**\n * Fetches exchange rates for a specific historical date\n * Handles ASP.NET ViewState and calendar navigation\n * @param targetDate - Target date\n * @returns HTML content for the target date\n */\nasync function fetchVentanillaForSpecificDate(\n  targetDate: dayjs.Dayjs\n): Promise<string> {\n  try {\n    // Create axios instance with cookie jar support\n    const jar = new CookieJar();\n    const client = wrapper(axios.create({ jar }));\n\n    // Step 1: Initial GET to fetch ViewState\n    const initialResponse = await client.get(VENTANILLA_URL, {\n      timeout: 30000,\n      headers: {\n        'User-Agent':\n          'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',\n      },\n    });\n\n    let viewState = extractViewState(cheerio.load(initialResponse.data));\n\n    // Step 2: Open calendar by clicking the calendar image\n    const calendarResponse = await postFormData(\n      {\n        ...viewState,\n        __EVENTTARGET: '',\n        __EVENTARGUMENT: '',\n        'imgCalendario.x': '10',\n        'imgCalendario.y': '10',\n        'CtrlBuscar2:txtPalabras': '',\n      },\n      client\n    );\n\n    viewState = extractViewState(cheerio.load(calendarResponse));\n\n    // Step 3: Navigate to target month\n    // Calculate months to navigate backwards\n    const today = dayjs();\n    const monthsToNavigate = monthsBetween(targetDate, today);\n\n    let currentResponse = calendarResponse;\n\n    for (let i = 0; i < monthsToNavigate; i++) {\n      // Extract previous month link from current calendar HTML\n      const $ = cheerio.load(currentResponse);\n      const prevMonthLink = extractPrevMonthLink($);\n\n      if (!prevMonthLink) {\n        throw new BCCRScrapingError('Could not find previous month link in calendar');\n      }\n\n      // Navigate to previous month\n      const navResponse = await postFormData({\n        ...viewState,\n        __EVENTTARGET: 'Calendar1',\n        __EVENTARGUMENT: prevMonthLink,\n        'CtrlBuscar2:txtPalabras': '',\n      }, client);\n\n      // Update for next iteration\n      currentResponse = navResponse;\n      viewState = extractViewState(cheerio.load(navResponse));\n    }\n\n    // Step 4: Select the specific date\n    const calendarDays = dateToCalendarDays(targetDate);\n    const finalResponse = await postFormData({\n      ...viewState,\n      __EVENTTARGET: 'Calendar1',\n      __EVENTARGUMENT: calendarDays.toString(),\n      'CtrlBuscar2:txtPalabras': '',\n    }, client);\n\n    return finalResponse;\n  } catch (error) {\n    if (error instanceof BCCRConnectionError || error instanceof BCCRScrapingError) {\n      throw error;\n    }\n\n    throw new BCCRScrapingError(\n      `Failed to fetch historical data: ${error instanceof Error ? error.message : String(error)}`\n    );\n  }\n}\n\n/**\n * Posts form data to BCCR with proper headers\n * @param formData - Form data to post\n * @param client - Optional axios instance (with cookie jar for sessions)\n * @returns Response HTML\n */\nasync function postFormData(\n  formData: ViewStateData & Record<string, string>,\n  client: AxiosInstance = axios\n): Promise<string> {\n  try {\n    // Clean form data - remove undefined values but keep empty strings\n    const cleanedFormData: Record<string, string> = {};\n    for (const [key, value] of Object.entries(formData)) {\n      if (value !== undefined && value !== null) {\n        cleanedFormData[key] = value;\n      }\n    }\n\n    const response = await client.post(VENTANILLA_URL, new URLSearchParams(cleanedFormData).toString(), {\n      timeout: 30000,\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n        'User-Agent':\n          'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',\n        'Referer': VENTANILLA_URL,\n      },\n      withCredentials: true,\n      validateStatus: (status) => status < 600, // Don't throw on 4xx/5xx\n    });\n\n    if (response.status >= 400) {\n      const errorMsg = `POST request failed with status ${response.status}`;\n      const responseText = typeof response.data === 'string' ? response.data.substring(0, 500) : '';\n      throw new BCCRConnectionError(`${errorMsg}. Response: ${responseText}`);\n    }\n\n    return response.data;\n  } catch (error) {\n    if (error instanceof BCCRConnectionError) {\n      throw error;\n    }\n    if (axios.isAxiosError(error)) {\n      throw new BCCRConnectionError(\n        `POST request failed: ${error.message}`\n      );\n    }\n    throw error;\n  }\n}\n\n/**\n * Extracts ASP.NET ViewState from HTML\n * @param $ - Cheerio instance\n * @returns ViewState data\n */\nfunction extractViewState($: cheerio.CheerioAPI): ViewStateData {\n  const viewState = $('input[name=\"__VIEWSTATE\"]').val();\n  const eventValidation = $('input[name=\"__EVENTVALIDATION\"]').val();\n  const viewStateGenerator = $('input[name=\"__VIEWSTATEGENERATOR\"]').val();\n\n  if (!viewState || !eventValidation) {\n    throw new BCCRParseError('Could not extract ViewState from page');\n  }\n\n  return {\n    __VIEWSTATE: viewState.toString(),\n    __EVENTVALIDATION: eventValidation.toString(),\n    __VIEWSTATEGENERATOR: viewStateGenerator ? viewStateGenerator.toString() : '',\n  };\n}\n\n/**\n * Extracts the previous month link from calendar\n * @param $ - Cheerio instance\n * @returns Previous month link argument (e.g., \"V9405\")\n */\nexport function extractPrevMonthLink($: cheerio.CheerioAPI): string | null {\n  // Look for the Calendar1 table\n  const calendar = $('table#Calendar1');\n\n  if (calendar.length === 0) {\n    return null;\n  }\n\n  // Find all links in the calendar\n  const links = calendar.find('a');\n\n  for (let i = 0; i < links.length; i++) {\n    const link = links.eq(i);\n    const title = (link.attr('title') || '').toLowerCase();\n\n    // Look for \"previous month\" or Spanish \"mes anterior\"\n    if (title.includes('previous month') || title.includes('anterior')) {\n      const href = link.attr('href') || '';\n\n      // Extract __EVENTARGUMENT from javascript:__doPostBack('Calendar1','V9405')\n      const match = href.match(/__doPostBack\\('([^']*)',\\s*'([^']*)'\\)/);\n      if (match) {\n        return match[2];  // Return the event argument (e.g., \"V9405\")\n      }\n    }\n  }\n\n  return null;\n}\n\n/**\n * Extracts the date from the page header\n * @param $ - Cheerio instance\n * @returns ISO date string (YYYY-MM-DD)\n */\nexport function extractPageDate($: cheerio.CheerioAPI): string {\n  // Strategy 1: Look for text containing date pattern\n  const datePattern = /(\\w+,?\\s+)?\\d+\\s+de\\s+\\w+\\s+de\\s+\\d{4}/;\n\n  // Search through all text nodes\n  const pageText = $.root().text();\n  const dateMatch = pageText.match(datePattern);\n\n  if (dateMatch) {\n    return parseSpanishDate(dateMatch[0]);\n  }\n\n  // Fallback to today\n  const dayjs = require('dayjs');\n  return dayjs().format('YYYY-MM-DD');\n}\n\n/**\n * Parses the exchange rate table\n * @param $ - Cheerio instance\n * @returns Array of entity data\n */\nexport function parseExchangeRateTable($: cheerio.CheerioAPI): EntityData[] {\n  const entities: EntityData[] = [];\n  const table = $('#DG');\n\n  if (table.length === 0) {\n    throw new BCCRParseError('Could not find exchange rate table (id=\"DG\")');\n  }\n\n  let currentEntityType = '';\n\n  // Iterate through table rows\n  table.find('tr').each((_, row) => {\n    const $row = $(row);\n    const cells = $row.find('td');\n\n    if (cells.length === 0) {\n      return; // Skip header row\n    }\n\n    if (cells.length < 5) {\n      return; // Skip malformed rows\n    }\n\n    // Extract entity data based on column count\n    let entityTypeCell: string;\n    let entityName: string;\n    let buyRate: string;\n    let sellRate: string;\n    let spread: string;\n    let lastUpdate: string;\n\n    if (cells.length === 6) {\n      // Row with entity type column\n      entityTypeCell = cells.eq(0).text().trim();\n      entityName = cells.eq(1).text().trim();\n      buyRate = cells.eq(2).text().trim();\n      sellRate = cells.eq(3).text().trim();\n      spread = cells.eq(4).text().trim();\n      lastUpdate = cells.eq(5).text().trim();\n\n      // Update current entity type if this cell has content\n      if (entityTypeCell) {\n        currentEntityType = entityTypeCell;\n      }\n    } else if (cells.length === 5) {\n      // Row without entity type column (continuation with rowspan)\n      entityName = cells.eq(0).text().trim();\n      buyRate = cells.eq(1).text().trim();\n      sellRate = cells.eq(2).text().trim();\n      spread = cells.eq(3).text().trim();\n      lastUpdate = cells.eq(4).text().trim();\n    } else {\n      return; // Skip other malformed rows\n    }\n\n    if (!entityName) {\n      return; // Skip empty rows\n    }\n\n    entities.push({\n      entity_type: currentEntityType,\n      entity_name: entityName,\n      buy_rate: parseRate(buyRate),\n      sell_rate: parseRate(sellRate),\n      spread: parseRate(spread),\n      last_update: formatLastUpdate(lastUpdate),\n      last_update_str: lastUpdate,\n    });\n  });\n\n  if (entities.length === 0) {\n    throw new BCCRParseError('No exchange rate data found in table');\n  }\n\n  return entities;\n}\n\n/**\n * Groups entities by type\n * @param entities - Array of entity data\n * @returns Hierarchical data organized by entity type\n */\nexport function groupEntitiesByType(\n  entities: EntityData[]\n): HierarchicalData {\n  const grouped: HierarchicalData = {};\n\n  for (const entity of entities) {\n    if (!grouped[entity.entity_type]) {\n      grouped[entity.entity_type] = [];\n    }\n    grouped[entity.entity_type].push(entity);\n  }\n\n  return grouped;\n}\n\n/**\n * Generates summary statistics for entities\n * @param entities - Array of entity data\n * @returns Entity summary\n */\nexport function getEntitySummary(entities: EntityData[]): EntitySummary {\n  const byType: Record<string, number> = {};\n\n  for (const entity of entities) {\n    if (!byType[entity.entity_type]) {\n      byType[entity.entity_type] = 0;\n    }\n    byType[entity.entity_type]++;\n  }\n\n  return {\n    total: entities.length,\n    by_type: byType,\n  };\n}\n","import { validateDateParameter, validateDateRange } from './utils';\nimport { scrapeVentanillaPage, groupEntitiesByType } from './scraper';\nimport type { EntityData, Format, HierarchicalData } from './types';\n\n/**\n * Filters out header rows and entities without valid exchange rates\n * @param entities - Array of entity data\n * @returns Filtered array containing only entities with buy_rate or sell_rate\n */\nfunction filterValidEntities(entities: EntityData[]): EntityData[] {\n  return entities.filter(\n    (entity) => entity.buy_rate !== null || entity.sell_rate !== null\n  );\n}\n\n/**\n * Gets current exchange rates from BCCR\n * @param format - Output format: 'flat' (default) or 'hierarchical'\n * @returns Array of entity data (flat) or hierarchical object\n * @example\n * ```typescript\n * // Get flat list of all entities\n * const rates = await getCurrentRates();\n *\n * // Get rates organized by entity type\n * const ratesByType = await getCurrentRates('hierarchical');\n * ```\n */\nexport async function getCurrentRates(\n  format: Format = 'flat'\n): Promise<EntityData[] | HierarchicalData> {\n  const result = await scrapeVentanillaPage();\n  const filtered = filterValidEntities(result.entities);\n\n  if (format === 'hierarchical') {\n    return groupEntitiesByType(filtered);\n  }\n\n  return filtered;\n}\n\n/**\n * Gets exchange rates for a specific date\n * @param date - Date in YYYY-MM-DD or DD/MM/YYYY format\n * @param format - Output format: 'flat' (default) or 'hierarchical'\n * @param maxDaysBack - Maximum number of days back allowed (default: Infinity)\n * @returns Array of entity data (flat) or hierarchical object\n * @throws {BCCRDateError} If date is invalid or out of range\n * @example\n * ```typescript\n * // Get rates for a specific date\n * const rates = await getRatesByDate('2025-11-04');\n *\n * // Get rates organized by entity type\n * const ratesByType = await getRatesByDate('2025-11-04', 'hierarchical');\n *\n * // Limit query to last 365 days\n * const recentRates = await getRatesByDate('2025-01-01', 'flat', 365);\n * ```\n */\nexport async function getRatesByDate(\n  date: string,\n  format: Format = 'flat',\n  maxDaysBack: number = Infinity\n): Promise<EntityData[] | HierarchicalData> {\n  // Validate date\n  const validatedDate = validateDateParameter(date);\n  validateDateRange(date, maxDaysBack);\n\n  const result = await scrapeVentanillaPage(validatedDate.format('YYYY-MM-DD'));\n  const filtered = filterValidEntities(result.entities);\n\n  if (format === 'hierarchical') {\n    return groupEntitiesByType(filtered);\n  }\n\n  return filtered;\n}\n\n/**\n * Searches for entities matching a query string\n * @param query - Search query (searches in entity name and type)\n * @param date - Optional date in YYYY-MM-DD or DD/MM/YYYY format\n * @param format - Output format: 'flat' (default) or 'hierarchical'\n * @param maxDaysBack - Maximum number of days back allowed (default: Infinity)\n * @returns Filtered array of entity data (flat) or hierarchical object\n * @example\n * ```typescript\n * // Search for entities containing \"Nacional\"\n * const results = await searchEntities('Nacional');\n *\n * // Search in historical data\n * const historicalResults = await searchEntities('Banco', '2025-11-04');\n *\n * // Search and organize by type\n * const resultsByType = await searchEntities('Banco', undefined, 'hierarchical');\n *\n * // Search with date range limit\n * const recentResults = await searchEntities('Banco', '2025-01-01', 'flat', 365);\n * ```\n */\nexport async function searchEntities(\n  query: string,\n  date?: string,\n  format: Format = 'flat',\n  maxDaysBack: number = Infinity\n): Promise<EntityData[] | HierarchicalData> {\n  let result;\n\n  if (date) {\n    const validatedDate = validateDateParameter(date);\n    validateDateRange(date, maxDaysBack);\n    result = await scrapeVentanillaPage(validatedDate.format('YYYY-MM-DD'));\n  } else {\n    result = await scrapeVentanillaPage();\n  }\n\n  // Filter out invalid entities first, then filter by query\n  const validEntities = filterValidEntities(result.entities);\n  const queryLower = query.toLowerCase();\n  const filtered = validEntities.filter(\n    (entity) =>\n      entity.entity_name.toLowerCase().includes(queryLower) ||\n      entity.entity_type.toLowerCase().includes(queryLower)\n  );\n\n  if (format === 'hierarchical') {\n    return groupEntitiesByType(filtered);\n  }\n\n  return filtered;\n}\n\n/**\n * Gets exchange rate data for a specific entity by name\n * @param entityName - Exact or partial entity name to search for\n * @param date - Optional date in YYYY-MM-DD or DD/MM/YYYY format\n * @param maxDaysBack - Maximum number of days back allowed (default: Infinity)\n * @returns Entity data or null if not found\n * @example\n * ```typescript\n * // Get current rates for Banco Nacional\n * const entity = await getEntityByName('Banco Nacional');\n *\n * // Get historical rates for a specific entity\n * const historicalEntity = await getEntityByName('Banco Nacional', '2025-11-04');\n *\n * // Get entity with date range limit\n * const recentEntity = await getEntityByName('Banco Nacional', '2025-01-01', 365);\n * ```\n */\nexport async function getEntityByName(\n  entityName: string,\n  date?: string,\n  maxDaysBack: number = Infinity\n): Promise<EntityData | null> {\n  let result;\n\n  if (date) {\n    const validatedDate = validateDateParameter(date);\n    validateDateRange(date, maxDaysBack);\n    result = await scrapeVentanillaPage(validatedDate.format('YYYY-MM-DD'));\n  } else {\n    result = await scrapeVentanillaPage();\n  }\n\n  // Filter out invalid entities first\n  const validEntities = filterValidEntities(result.entities);\n\n  // Find entity by exact name match (case-insensitive)\n  const entityLower = entityName.toLowerCase();\n  const found = validEntities.find(\n    (entity) => entity.entity_name.toLowerCase() === entityLower\n  );\n\n  if (found) {\n    return found;\n  }\n\n  // If no exact match, try partial match\n  const partialMatch = validEntities.find((entity) =>\n    entity.entity_name.toLowerCase().includes(entityLower)\n  );\n\n  return partialMatch || null;\n}\n\n// Re-export types and exceptions for convenience\nexport type { EntityData, Format, HierarchicalData, EntitySummary } from './types';\nexport {\n  BCCRError,\n  BCCRScrapingError,\n  BCCRDateError,\n  BCCRConnectionError,\n  BCCRParseError,\n} from './exceptions';\n"]}