{"version":3,"file":"index.mjs","sources":["../src/env.ts","../src/rates.ts","../src/util.ts"],"sourcesContent":["import { object, safeParse, string, url } from \"valibot\";\n\nconst schema = object({\n  BNR_FX_RATES_MOST_RECENT_URL: string([url()]),\n  BNR_FX_RATES_OF_YEAR_URL: string([url()]),\n});\n\nconst parseResult = safeParse(schema, {\n  BNR_FX_RATES_MOST_RECENT_URL: \"https://www.bnr.ro/nbrfxrates.xml\",\n  BNR_FX_RATES_OF_YEAR_URL: \"https://bnr.ro/files/xml/years/nbrfxrates{year}.xml\",\n  ...process.env,\n});\n\nif (!parseResult.success) {\n  throw new Error(\"Environment variables are not defined.\");\n}\n\nconst env = parseResult.data;\n\nexport default env;\n","import { XMLParser } from \"fast-xml-parser\";\nimport env from \"@/env\";\nimport { getYearlyExchangeRatesUrl, ISO_DATE_RE } from \"@/util\";\nimport {\n  array,\n  coerce,\n  minLength,\n  number,\n  object,\n  optional,\n  regex,\n  safeParse,\n  string,\n  transform,\n  parse,\n} from \"valibot\";\n\nexport enum CurrencyCode {\n  AED = \"AED\",\n  AUD = \"AUD\",\n  BGN = \"BGN\",\n  BRL = \"BRL\",\n  CAD = \"CAD\",\n  CHF = \"CHF\",\n  CNY = \"CNY\",\n  CZK = \"CZK\",\n  DKK = \"DKK\",\n  EGP = \"EGP\",\n  EUR = \"EUR\",\n  GBP = \"GBP\",\n  HRK = \"HRK\",\n  HUF = \"HUF\",\n  INR = \"INR\",\n  JPY = \"JPY\",\n  KRW = \"KRW\",\n  MDL = \"MDL\",\n  MXN = \"MXN\",\n  NOK = \"NOK\",\n  NZD = \"NZD\",\n  PLN = \"PLN\",\n  RSD = \"RSD\",\n  RUB = \"RUB\",\n  SEK = \"SEK\",\n  THB = \"THB\",\n  TRY = \"TRY\",\n  UAH = \"UAH\",\n  USD = \"USD\",\n  XAU = \"XAU\",\n  XDR = \"XDR\",\n  ZAR = \"ZAR\",\n}\n\nexport interface Rate {\n  date: string;\n  currency: CurrencyCode;\n  value: number;\n  multiplier?: number;\n}\n\nasync function fetchRates(url: string) {\n  let xml = \"\";\n  try {\n    const xmlParser = new XMLParser({\n      attributeNamePrefix: \"\",\n      ignoreAttributes: false,\n      isArray: (name) => name === \"Rate\" || name === \"Cube\",\n      parseAttributeValue: false,\n      processEntities: false,\n      textNodeName: \"value\",\n      trimValues: true,\n    });\n    xml = await fetch(url).then((r) => r.text());\n    const schema = transform(\n      object({\n        DataSet: object({\n          Body: object({\n            Cube: array(\n              object({\n                date: string([regex(ISO_DATE_RE)]),\n                Rate: array(\n                  object({\n                    currency: string(),\n                    value: number(),\n                    multiplier: optional(coerce(number(), (v) => Number(v))),\n                  }),\n                  [minLength(1)]\n                ),\n              })\n            ),\n          }),\n        }),\n      }),\n      (data) =>\n        data.DataSet.Body.Cube.flatMap(({ date, Rate }) =>\n          Rate.map<Rate>((rate) =>\n            Object.assign(\n              {\n                date,\n                value: rate.value,\n                currency: rate.currency as CurrencyCode,\n              },\n              rate.multiplier ? { multiplier: rate.multiplier } : null\n            )\n          )\n        ).filter(\n          // Allow only rates from known currencies\n          (rate) => rate.currency in CurrencyCode\n        )\n    );\n    return parse(schema, xmlParser.parse(xml));\n  } catch (err) {\n    throw new Error(\"Server did not return a valid response\", { cause: err });\n  }\n}\n\nexport function getMostRecentExchangeRates() {\n  return fetchRates(env.BNR_FX_RATES_MOST_RECENT_URL);\n}\n\nexport function getExchangeRatesOfYear(year: number) {\n  return fetchRates(getYearlyExchangeRatesUrl(year));\n}\n\nexport async function getExchangeRatesForDate(date: string) {\n  const parseResult = safeParse(\n    transform(string([regex(ISO_DATE_RE)]), (date) => new Date(date)),\n    date\n  );\n  if (!parseResult.success) {\n    throw new Error(\"Invalid date format\");\n  }\n  const rates = await getExchangeRatesOfYear(parseResult.data.getFullYear());\n  return rates.filter((rate) => rate.date === date);\n}\n","import env from \"@/env\";\n\nexport const ISO_DATE_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport function getYearlyExchangeRatesUrl(year: number) {\n  return env.BNR_FX_RATES_OF_YEAR_URL.replace(\"{year}\", year.toString());\n}\n"],"names":["schema","object","BNR_FX_RATES_MOST_RECENT_URL","string","url","BNR_FX_RATES_OF_YEAR_URL","parseResult","safeParse","_extends","process","env","success","Error","CurrencyCode","data","ISO_DATE_RE","getExchangeRatesForDate","date","transform","regex","Date","Promise","resolve","getExchangeRatesOfYear","getFullYear","then","rates","filter","rate","e","reject","fetchRates","xml","xmlParser","XMLParser","attributeNamePrefix","ignoreAttributes","isArray","name","parseAttributeValue","processEntities","textNodeName","trimValues","fetch","r","text","_fetch$then","DataSet","Body","Cube","array","Rate","currency","value","number","multiplier","optional","coerce","v","Number","minLength","flatMap","_ref","map","Object","assign","parse","_catch","err","cause","getMostRecentExchangeRates","year","replace","toString","getYearlyExchangeRatesUrl"],"mappings":"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"}