UNPKG

currzy

Version:

Free, open-source library for fetching, managing, and converting up-to-date currency rates from multiple reliable sources with the ability to easily choose the source.

282 lines (275 loc) 7.84 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { CbrfProvider: () => CbrfProvider, Currzy: () => Currzy }); module.exports = __toCommonJS(index_exports); // src/providers/cbrf/index.ts var import_ofetch = require("ofetch"); var import_fast_xml_parser = require("fast-xml-parser"); // src/cache/drivers.ts var import_promises = __toESM(require("fs/promises"), 1); var import_path = __toESM(require("path"), 1); var FileCacheDriver = class { constructor(providerName) { this.cacheFile = import_path.default.resolve("cache", `${providerName}-cache.json`); } async load() { try { const raw = await import_promises.default.readFile(this.cacheFile, "utf-8"); return JSON.parse(raw); } catch { return null; } } async save(data) { await import_promises.default.mkdir(import_path.default.dirname(this.cacheFile), { recursive: true }); await import_promises.default.writeFile(this.cacheFile, JSON.stringify(data, null, 2), "utf-8"); } async clear() { try { await import_promises.default.unlink(this.cacheFile); } catch { } } }; var LocalStorageCacheDriver = class { constructor(providerName) { this.key = `currenzy-${providerName}-cache`; } async load() { const raw = localStorage.getItem(this.key); return raw ? JSON.parse(raw) : null; } async save(data) { localStorage.setItem(this.key, JSON.stringify(data)); } async clear() { localStorage.removeItem(this.key); } }; // src/cache/index.ts function createCacheDriver(providerName) { if (typeof window !== "undefined" && "localStorage" in window) { return new LocalStorageCacheDriver(providerName); } else { return new FileCacheDriver(providerName); } } // src/providers/cbrf/types/currency.ts var AVAILABLE_CURRENCIES = [ "AUD", "AZN", "DZD", "GBP", "AMD", "BHD", "BYN", "BGN", "BOB", "BRL", "HUF", "VND", "HKD", "GEL", "DKK", "AED", "USD", "EUR", "EGP", "INR", "IDR", "IRR", "KZT", "CAD", "QAR", "KGS", "CNY", "CUP", "MDL", "MNT", "NGN", "NZD", "NOK", "OMR", "PLN", "SAR", "RON", "XDR", "SGD", "TJS", "THB", "BDT", "TRY", "TMT", "UZS", "UAH", "CZK", "SEK", "CHF", "ETB", "RSD", "ZAR", "KRW", "JPY", "MMK", "RUB" ]; function assertCurrency(code) { if (!AVAILABLE_CURRENCIES.includes(code)) { throw new Error(`Unknown currency: ${code}`); } } // src/providers/cbrf/index.ts var CbrfProvider = class { constructor() { this.url = "https://api.allorigins.win/raw?url=https://www.cbr.ru/scripts/XML_daily.asp"; this.rates = {}; this.lastUpdate = null; this.initialized = false; this.cacheTTL = 1e3 * 60 * 60; this.cache = createCacheDriver("cbrf"); this.availableCurrencies = AVAILABLE_CURRENCIES; } async loadCache() { const data = await this.cache.load(); if (data) { this.rates = data.payload.rates; this.lastUpdate = data.lastUpdate ? new Date(data.lastUpdate) : null; this.initialized = true; } } async saveCache() { await this.cache.save({ payload: { rates: this.rates }, lastUpdate: this.lastUpdate ? this.lastUpdate.toISOString() : null }); } async clearCache() { await this.cache.clear(); this.rates = {}; this.lastUpdate = null; this.initialized = false; } async fetchRates() { try { const xml = await (0, import_ofetch.ofetch)(this.url, { responseType: "text" }); const parser = new import_fast_xml_parser.XMLParser(); const data = parser.parse(xml); const items = Array.isArray(data.ValCurs.Valute) ? data.ValCurs.Valute : [data.ValCurs.Valute]; this.rates = {}; for (const item of items) { const nominal = Number(item.Nominal); const value = parseFloat(item.Value.replace(",", ".")); const vunitRate = value / nominal; const rate = { code: item.CharCode, nominal, value, vunitRate }; if (this.availableCurrencies.includes(rate.code)) { this.rates[rate.code] = rate; } } this.rates["RUB"] = { code: "RUB", nominal: 1, value: 1, vunitRate: 1 }; this.lastUpdate = /* @__PURE__ */ new Date(); this.initialized = true; await this.saveCache(); } catch (e) { console.error("Error fetching CBRF rates:", e); if (!this.initialized) { await this.loadCache(); if (!this.initialized) throw new Error("No CBRF data and no cache"); } } } async ensureInitialized() { if (!this.initialized) await this.loadCache(); const expired = this.lastUpdate === null || (/* @__PURE__ */ new Date()).getTime() - this.lastUpdate.getTime() > this.cacheTTL; if (!this.initialized || expired) { await this.fetchRates(); } } async getRate(code, base = "USD") { await this.ensureInitialized(); assertCurrency(code); assertCurrency(base); const rateInRub = this.rates[code].vunitRate; const baseRateInRub = this.rates[base].vunitRate; return baseRateInRub / rateInRub; } async convert(amount, from, to) { await this.ensureInitialized(); assertCurrency(from); assertCurrency(to); const fromRateInRub = this.rates[from].vunitRate; const toRateInRub = this.rates[to].vunitRate; return amount * fromRateInRub / toRateInRub; } async getAllRates(base = "USD") { await this.ensureInitialized(); assertCurrency(base); const result = {}; for (const code of this.availableCurrencies) { if (code === base) continue; result[code] = await this.getRate(code, base); } return result; } getLastUpdate() { return this.lastUpdate; } }; // src/index.ts var Currzy = class { constructor(providerName) { if (providerName === "cbrf") this.provider = new CbrfProvider(); else throw new Error("Unknown provider"); } async getRate(code) { return await this.provider.getRate(code); } async convert(amount, from, to) { return await this.provider.convert(amount, from, to); } async getAllRatesTo(code) { return await this.provider.getAllRates(code); } async clearCache() { return this.provider.clearCache(); } getLastUpdate() { return this.provider.getLastUpdate(); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CbrfProvider, Currzy }); //# sourceMappingURL=index.cjs.map