subunit-money 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -146,7 +146,7 @@ var _Money = class _Money {
|
|
|
146
146
|
* Shows the amount and currency instead of just the class name.
|
|
147
147
|
*/
|
|
148
148
|
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
149
|
-
return `Money {
|
|
149
|
+
return `Money { displayAmount: '${this.displayAmount}', currency: '${this.currency}', amount: '${this.amount}' }`;
|
|
150
150
|
}
|
|
151
151
|
// ============ Arithmetic Operations ============
|
|
152
152
|
/**
|
|
@@ -386,9 +386,6 @@ parseAmount_fn = function(amount) {
|
|
|
386
386
|
_Money_static = new WeakSet();
|
|
387
387
|
formatForDisplay_fn = function(fullAmount, currencyDef) {
|
|
388
388
|
const preferredDecimals = currencyDef.displayDecimals ?? currencyDef.decimalDigits;
|
|
389
|
-
if (preferredDecimals === currencyDef.decimalDigits) {
|
|
390
|
-
return fullAmount;
|
|
391
|
-
}
|
|
392
389
|
const [whole, frac = ""] = fullAmount.split(".");
|
|
393
390
|
if (!frac) return whole;
|
|
394
391
|
let trimmedFrac = frac.replace(/0+$/, "");
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/index.ts","../lib/errors.ts","../lib/currency.ts","../lib/money.ts","../lib/exchange-rate-service.ts","../lib/money-converter.ts","../currencymap.json"],"sourcesContent":["/**\n * subunit-money - A type-safe value object for monetary amounts\n *\n * @example\n * import { Money, ExchangeRateService, MoneyConverter } from '@cbrunnkvist/subunit-money'\n *\n * // Basic usage\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n *\n * // Currency conversion\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(total, 'EUR')\n */\n\n// Core classes\nexport { Money, type MoneyObject } from './money.js'\nexport { ExchangeRateService, type ExchangeRate, type RatePair } from './exchange-rate-service.js'\nexport { MoneyConverter } from './money-converter.js'\n\n// Error types\nexport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n ExchangeRateError,\n} from './errors.js'\n\n// Currency utilities\nexport {\n registerCurrency,\n getCurrency,\n hasCurrency,\n getAllCurrencies,\n loadCurrencyMap,\n clearCurrencies,\n type CurrencyDefinition,\n} from './currency.js'\n\n// Auto-load default currencies\n// The currencymap.json file is the official ISO 4217 currency list (List One) as of 2026-01-01,\n// sourced from SIX Financial Information AG (the ISO 4217 Maintenance Agency).\n//\n// To regenerate:\n// 1. Download list-one.xml from https://www.six-group.com/en/products-services/financial-information/data-standards.html\n// 2. Convert with: yq -p xml -o json '.' list-one.xml | jq '.ISO_4217.CcyTbl.CcyNtry | map(select(.Ccy) | {(.Ccy): {decimal_digits: (if (.CcyMnrUnts == \"N.A.\" or .CcyMnrUnts == null) then 0 else (.CcyMnrUnts | tonumber) end)}}) | add | to_entries | sort_by(.key) | from_entries' > currencymap.json\n//\n// Note: This excludes historical currencies, supranational funds, and precious metals,\n// keeping only active national and regional currencies for practical use.\nimport { loadCurrencyMap } from './currency.js'\nimport currencyMap from '../currencymap.json'\nloadCurrencyMap(currencyMap as Record<string, { decimal_digits: number }>)\n","/**\n * Custom error types for Money operations.\n * All errors extend built-in Error types for proper instanceof checks.\n */\n\n/**\n * Thrown when attempting operations between different currencies.\n * @example\n * new Money('USD', 10).add(new Money('EUR', 5)) // throws CurrencyMismatchError\n */\nexport class CurrencyMismatchError extends TypeError {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`Cannot operate on ${fromCurrency} and ${toCurrency} - currencies must match`)\n this.name = 'CurrencyMismatchError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, CurrencyMismatchError)\n }\n}\n\n/**\n * Thrown when using an unregistered currency code.\n * @example\n * new Money('FAKE', 10) // throws CurrencyUnknownError\n */\nexport class CurrencyUnknownError extends TypeError {\n readonly currency: string\n\n constructor(currency: string) {\n super(`Unknown currency '${currency}' - register it first with Money.registerCurrency()`)\n this.name = 'CurrencyUnknownError'\n this.currency = currency\n Error.captureStackTrace?.(this, CurrencyUnknownError)\n }\n}\n\n/**\n * Thrown when an amount has more decimal places than the currency allows.\n * @example\n * new Money('USD', '1.234') // throws SubunitError (USD only allows 2 decimals)\n */\nexport class SubunitError extends RangeError {\n readonly currency: string\n readonly maxDecimals: number\n\n constructor(currency: string, maxDecimals: number) {\n super(`${currency} only supports ${maxDecimals} decimal place(s)`)\n this.name = 'SubunitError'\n this.currency = currency\n this.maxDecimals = maxDecimals\n Error.captureStackTrace?.(this, SubunitError)\n }\n}\n\n/**\n * Thrown when an amount cannot be parsed as a valid number.\n * @example\n * new Money('USD', 'abc') // throws AmountError\n */\nexport class AmountError extends TypeError {\n readonly amount: unknown\n\n constructor(amount: unknown) {\n super(`Invalid amount: ${JSON.stringify(amount)}`)\n this.name = 'AmountError'\n this.amount = amount\n Error.captureStackTrace?.(this, AmountError)\n }\n}\n\n/**\n * Thrown when an exchange rate is not available.\n * @example\n * converter.convert(usdMoney, 'XYZ') // throws ExchangeRateError if no USD->XYZ rate\n */\nexport class ExchangeRateError extends Error {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`No exchange rate available from ${fromCurrency} to ${toCurrency}`)\n this.name = 'ExchangeRateError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, ExchangeRateError)\n }\n}\n","/**\n * Currency registry and types.\n * Manages ISO 4217 currency definitions and custom currencies.\n */\n\nexport interface CurrencyDefinition {\n code: string\n decimalDigits: number\n displayDecimals?: number\n}\n\n// Internal registry - mutable for registerCurrency()\nconst currencies: Map<string, CurrencyDefinition> = new Map()\n\n/**\n * Register a new currency or update an existing one.\n * @param code - ISO 4217 currency code (e.g., 'USD', 'EUR', 'BTC')\n * @param decimalDigits - Number of decimal places (e.g., 2 for USD, 8 for BTC)\n * @param displayDecimals - Optional number of decimal places to use for display/formatting (defaults to decimalDigits)\n */\nexport function registerCurrency(code: string, decimalDigits: number, displayDecimals?: number): void {\n currencies.set(code, { code, decimalDigits, displayDecimals })\n}\n\n/**\n * Get a currency definition by code.\n * @returns The currency definition, or undefined if not registered\n */\nexport function getCurrency(code: string): CurrencyDefinition | undefined {\n return currencies.get(code)\n}\n\n/**\n * Check if a currency is registered.\n */\nexport function hasCurrency(code: string): boolean {\n return currencies.has(code)\n}\n\n/**\n * Get all registered currencies, sorted by code.\n */\nexport function getAllCurrencies(): CurrencyDefinition[] {\n return Array.from(currencies.values()).sort((a, b) => a.code.localeCompare(b.code))\n}\n\n/**\n * Load currencies from the legacy currencymap.json format.\n * @param map - Object with currency codes as keys and {decimal_digits: number} as values\n */\nexport function loadCurrencyMap(map: Record<string, { decimal_digits: number }>): void {\n for (const [code, data] of Object.entries(map)) {\n registerCurrency(code, data.decimal_digits)\n }\n}\n\n/**\n * Clear all registered currencies. Useful for testing.\n */\nexport function clearCurrencies(): void {\n currencies.clear()\n}\n","/**\n * Money - An immutable value object for monetary amounts.\n *\n * Design principles:\n * - Immutable: all operations return new instances\n * - Type-safe: currency mismatches are caught at compile time (when possible) and runtime\n * - Precise: uses BigInt internally to avoid floating-point errors\n * - String-based API: amounts are strings to preserve precision in JSON/DB round-trips\n */\n\nimport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n} from './errors.js'\nimport { getCurrency, hasCurrency, type CurrencyDefinition } from './currency.js'\n\n/**\n * Serialized form of a Money object, safe for JSON.\n */\nexport interface MoneyObject<C extends string = string> {\n currency: C\n amount: string\n}\n\n/**\n * Money class - represents a monetary amount in a specific currency.\n *\n * @typeParam C - The currency code type (enables compile-time currency checking)\n *\n * @example\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n * console.log(total.amount) // \"21.59\"\n */\nexport class Money<C extends string = string> {\n readonly currency: C\n readonly amount: string\n readonly displayAmount: string\n\n // Private BigInt storage - stores currency native subunits directly\n readonly #subunits: bigint\n readonly #currencyDef: CurrencyDefinition\n\n /**\n * Create a new Money instance.\n *\n * @param currency - ISO 4217 currency code (must be registered)\n * @param amount - The amount as a number or string\n * @throws {CurrencyUnknownError} If the currency is not registered\n * @throws {AmountError} If the amount is not a valid number\n * @throws {SubunitError} If the amount has more decimals than the currency allows\n */\n constructor(currency: C, amount: number | string) {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n this.currency = currency\n this.#currencyDef = currencyDef\n this.#subunits = this.#parseAmount(amount)\n \n // Pre-calculate string representations for better DX and performance\n this.amount = Money.#formatSubunits(this.#subunits, currencyDef)\n this.displayAmount = Money.#formatForDisplay(this.amount, currencyDef)\n }\n\n /**\n * Parse an amount into native subunits.\n */\n #parseAmount(amount: number | string): bigint {\n const str = typeof amount === 'number' ? String(amount) : amount\n\n const match = str.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!match) {\n throw new AmountError(amount)\n }\n\n const [, sign, whole, frac = ''] = match\n\n if (frac.length > this.#currencyDef.decimalDigits) {\n throw new SubunitError(this.currency, this.#currencyDef.decimalDigits)\n }\n\n const paddedFrac = frac.padEnd(this.#currencyDef.decimalDigits, '0')\n const combined = BigInt(whole + paddedFrac)\n\n return sign === '-' ? -combined : combined\n }\n\n /**\n * Custom console inspection for Node.js.\n * Shows the amount and currency instead of just the class name.\n */\n [Symbol.for('nodejs.util.inspect.custom')](): string {\n return `Money { amount: '${this.displayAmount}', currency: '${this.currency}' }`\n }\n\n /**\n * Format the full amount string for display purposes.\n */\n static #formatForDisplay(fullAmount: string, currencyDef: CurrencyDefinition): string {\n const preferredDecimals = currencyDef.displayDecimals ?? currencyDef.decimalDigits\n\n // If we want full precision anyway, just return it\n if (preferredDecimals === currencyDef.decimalDigits) {\n return fullAmount\n }\n\n // Split into whole and fractional parts\n const [whole, frac = ''] = fullAmount.split('.')\n\n if (!frac) return whole\n\n // Trim trailing zeros\n let trimmedFrac = frac.replace(/0+$/, '')\n\n // Pad back to preferred decimals if needed\n if (trimmedFrac.length < preferredDecimals) {\n trimmedFrac = trimmedFrac.padEnd(preferredDecimals, '0')\n }\n\n // If fractional part is empty and we want 0 decimals, return whole\n if (trimmedFrac === '' && preferredDecimals === 0) {\n return whole\n }\n \n return `${whole}.${trimmedFrac}`\n }\n\n\n\n /**\n * Ensure another Money has the same currency.\n */\n #assertSameCurrency(other: Money<string>): void {\n if (this.currency !== other.currency) {\n throw new CurrencyMismatchError(this.currency, other.currency)\n }\n }\n\n /**\n * Get the internal BigInt value (for operations).\n */\n #getInternalValue(): bigint {\n return this.#subunits\n }\n\n // ============ Arithmetic Operations ============\n\n /**\n * Add another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n add(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits + other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Subtract another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n subtract(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits - other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Multiply by a factor.\n *\n * DESIGN: Rounds immediately after multiplication using banker's rounding\n * (round half-to-even). This prevents the \"split penny problem\".\n */\n multiply(factor: number): Money<C> {\n if (typeof factor !== 'number' || !Number.isFinite(factor)) {\n throw new TypeError(`Factor must be a finite number, got: ${factor}`)\n }\n\n const { value: factorValue, scale } = Money.#parseFactor(factor)\n const product = this.#subunits * factorValue\n const divisor = 10n ** scale\n \n const result = Money.#roundedDivide(product, divisor)\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Helper to parse a number factor into a BigInt and a power-of-10 scale.\n * Uses String() conversion to avoid floating-point epsilon noise,\n * ensuring that 0.545 is treated as exactly 0.545, not 0.54500000000000004.\n */\n static #parseFactor(factor: number): { value: bigint, scale: bigint } {\n const str = String(factor)\n const [base, exponent] = str.split('e')\n \n const baseMatch = base.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!baseMatch) {\n // Fallback for unlikely cases, though String(number) should strictly produce valid formats\n throw new TypeError(`Invalid factor format: ${str}`)\n }\n \n const [, sign, whole, frac = ''] = baseMatch\n const baseValue = BigInt((sign || '') + whole + frac)\n const baseDecimals = frac.length\n \n const exp = exponent ? Number(exponent) : 0\n const netExp = exp - baseDecimals\n \n if (netExp >= 0) {\n return { value: baseValue * 10n ** BigInt(netExp), scale: 0n }\n } else {\n return { value: baseValue, scale: BigInt(-netExp) }\n }\n }\n\n /**\n * Divide with banker's rounding (round half-to-even).\n * IEEE 754-2008 recommended default rounding mode for financial calculations.\n */\n static #roundedDivide(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Allocate this amount proportionally.\n * Handles remainder distribution to avoid losing pennies.\n *\n * @param proportions - Array of proportions (e.g., [1, 1, 1] for three-way split)\n * @returns Array of Money objects that sum to the original amount\n */\n allocate(proportions: number[]): Money<C>[] {\n if (!Array.isArray(proportions) || proportions.length === 0) {\n throw new TypeError('Proportions must be a non-empty array')\n }\n\n for (const p of proportions) {\n if (typeof p !== 'number' || !Number.isFinite(p) || p < 0) {\n throw new TypeError('All proportions must be non-negative finite numbers')\n }\n }\n\n const total = proportions.reduce((sum, p) => sum + p, 0)\n if (total <= 0) {\n throw new TypeError('Sum of proportions must be positive')\n }\n\n const totalSubunits = this.#subunits\n\n // Calculate base allocations\n const allocations: bigint[] = proportions.map((p) => {\n return (totalSubunits * BigInt(Math.round(p * 1000000))) / BigInt(Math.round(total * 1000000))\n })\n\n // Distribute remainder\n let remainder = totalSubunits - allocations.reduce((sum, a) => sum + a, 0n)\n let i = 0\n while (remainder > 0n) {\n allocations[i % allocations.length] += 1n\n remainder -= 1n\n i++\n }\n while (remainder < 0n) {\n allocations[i % allocations.length] -= 1n\n remainder += 1n\n i++\n }\n\n // Convert back to Money objects\n return allocations.map((subunits) => {\n return Money.#createFromSubunits(subunits, this.currency, this.#currencyDef)\n })\n }\n\n // ============ Comparison Operations ============\n\n /**\n * Check if this amount equals another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n equalTo(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits === other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits > other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits < other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits >= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits <= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is zero.\n */\n isZero(): boolean {\n return this.#subunits === 0n\n }\n\n /**\n * Check if this amount is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.#subunits > 0n\n }\n\n /**\n * Check if this amount is negative (less than zero).\n */\n isNegative(): boolean {\n return this.#subunits < 0n\n }\n\n // ============ Serialization ============\n\n /**\n * Convert to a plain object (safe for JSON).\n */\n toJSON(): MoneyObject<C> {\n return {\n currency: this.currency,\n amount: this.amount,\n }\n }\n\n /**\n * Convert to string representation.\n */\n toString(): string {\n return `${this.displayAmount} ${this.currency}`\n }\n\n /**\n * Get the amount as a number (may lose precision for large values).\n * Use with caution - prefer string-based operations.\n */\n toNumber(): number {\n return Number(this.amount)\n }\n\n /**\n * Get the amount in subunits (e.g., cents for USD).\n * Useful for database storage (Stripe-style integer storage).\n */\n toSubunits(): bigint {\n return this.#subunits\n }\n\n // ============ Static Factory Methods ============\n\n /**\n * Create a Money instance from a plain object.\n */\n static fromObject<C extends string>(obj: MoneyObject<C>): Money<C> {\n return new Money(obj.currency, obj.amount)\n }\n\n /**\n * Create a Money instance from subunits (e.g., cents).\n * Useful for loading from database (Stripe-style integer storage).\n */\n static fromSubunits<C extends string>(subunits: bigint | number, currency: C): Money<C> {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n const bigintSubunits = typeof subunits === 'number' ? BigInt(subunits) : subunits\n return Money.#createFromSubunits(bigintSubunits, currency, currencyDef)\n }\n\n /**\n * Compare two Money objects (for use with Array.sort).\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n static compare<C extends string>(a: Money<C>, b: Money<C>): -1 | 0 | 1 {\n if (a.currency !== b.currency) {\n throw new CurrencyMismatchError(a.currency, b.currency)\n }\n const aVal = a.#getInternalValue()\n const bVal = b.#getInternalValue()\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n }\n\n /**\n * Create a zero amount in the specified currency.\n */\n static zero<C extends string>(currency: C): Money<C> {\n return new Money(currency, '0')\n }\n\n /**\n * Internal factory that bypasses parsing.\n */\n static #createFromSubunits<C extends string>(\n subunits: bigint,\n currency: C,\n currencyDef: CurrencyDefinition\n ): Money<C> {\n return new Money(currency, Money.#formatSubunits(subunits, currencyDef))\n }\n\n /**\n * Format subunits to string amount.\n */\n static #formatSubunits(subunits: bigint, currencyDef: CurrencyDefinition): string {\n const decimals = currencyDef.decimalDigits\n const abs = subunits < 0n ? -subunits : subunits\n const isNegative = subunits < 0n\n\n if (decimals === 0) {\n return `${isNegative ? '-' : ''}${abs}`\n }\n\n const multiplier = 10n ** BigInt(decimals)\n const wholePart = abs / multiplier\n const fracPart = abs % multiplier\n\n const sign = isNegative ? '-' : ''\n return `${sign}${wholePart}.${fracPart.toString().padStart(decimals, '0')}`\n }\n}\n","/**\n * Exchange Rate Service - Central authority for currency conversion rates.\n *\n * Design principles:\n * - Rates are stored as strings to preserve precision\n * - Timestamps track when rates were set\n * - Optional source tracking for audit trails\n * - Inverse rates can be auto-generated or explicitly set\n */\n\nexport interface ExchangeRate {\n from: string\n to: string\n rate: string\n timestamp: Date\n source?: string\n}\n\nexport interface RatePair {\n forward: ExchangeRate\n reverse: ExchangeRate\n /** Relative discrepancy between forward and 1/reverse rates */\n discrepancy: number\n}\n\n/**\n * Service for managing exchange rates between currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92, 'ECB')\n * rates.getRate('USD', 'EUR') // { from: 'USD', to: 'EUR', rate: '0.92', ... }\n */\nexport class ExchangeRateService {\n readonly #rates: Map<string, ExchangeRate> = new Map()\n\n /**\n * Create a rate key for storage.\n */\n #key(from: string, to: string): string {\n return `${from}:${to}`\n }\n\n /**\n * Set an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @param rate - Exchange rate (1 unit of 'from' = rate units of 'to')\n * @param source - Optional source identifier (e.g., 'ECB', 'Coinbase')\n * @param autoInverse - If true, automatically create inverse rate (default: true)\n */\n setRate(\n from: string,\n to: string,\n rate: number | string,\n source?: string,\n autoInverse: boolean = true\n ): void {\n const rateStr = typeof rate === 'number' ? rate.toPrecision(15) : rate\n\n this.#rates.set(this.#key(from, to), {\n from,\n to,\n rate: rateStr,\n timestamp: new Date(),\n source,\n })\n\n // Auto-create inverse rate if requested and not already explicitly set\n if (autoInverse) {\n const inverseKey = this.#key(to, from)\n if (!this.#rates.has(inverseKey)) {\n const inverseRate = 1 / Number(rateStr)\n this.#rates.set(inverseKey, {\n from: to,\n to: from,\n rate: inverseRate.toPrecision(15),\n timestamp: new Date(),\n source: source ? `${source} (inverse)` : '(inverse)',\n })\n }\n }\n }\n\n /**\n * Get an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @returns The exchange rate, or undefined if not set\n */\n getRate(from: string, to: string): ExchangeRate | undefined {\n // Same currency = rate of 1\n if (from === to) {\n return {\n from,\n to,\n rate: '1',\n timestamp: new Date(),\n source: '(identity)',\n }\n }\n\n return this.#rates.get(this.#key(from, to))\n }\n\n /**\n * Check if a rate exists.\n */\n hasRate(from: string, to: string): boolean {\n return from === to || this.#rates.has(this.#key(from, to))\n }\n\n /**\n * Remove a rate.\n */\n removeRate(from: string, to: string): boolean {\n return this.#rates.delete(this.#key(from, to))\n }\n\n /**\n * Get both forward and reverse rates, with discrepancy analysis.\n * Useful for detecting rate inconsistencies.\n *\n * @param currencyA - First currency\n * @param currencyB - Second currency\n * @returns Rate pair with discrepancy, or undefined if either rate is missing\n */\n getRatePair(currencyA: string, currencyB: string): RatePair | undefined {\n const forward = this.getRate(currencyA, currencyB)\n const reverse = this.getRate(currencyB, currencyA)\n\n if (!forward || !reverse) {\n return undefined\n }\n\n // Calculate discrepancy: how far is forward * reverse from 1.0?\n const product = Number(forward.rate) * Number(reverse.rate)\n const discrepancy = Math.abs(1 - product)\n\n return { forward, reverse, discrepancy }\n }\n\n /**\n * Get all rates for a specific base currency.\n *\n * @param base - The base currency code\n * @returns Array of rates from this currency\n */\n getRatesFrom(base: string): ExchangeRate[] {\n const rates: ExchangeRate[] = []\n for (const rate of this.#rates.values()) {\n if (rate.from === base) {\n rates.push(rate)\n }\n }\n return rates.sort((a, b) => a.to.localeCompare(b.to))\n }\n\n /**\n * Get all registered rates.\n */\n getAllRates(): ExchangeRate[] {\n return Array.from(this.#rates.values()).sort((a, b) => {\n const fromCompare = a.from.localeCompare(b.from)\n return fromCompare !== 0 ? fromCompare : a.to.localeCompare(b.to)\n })\n }\n\n /**\n * Clear all rates.\n */\n clear(): void {\n this.#rates.clear()\n }\n\n /**\n * Load rates from a simple object.\n *\n * @param rates - Object where keys are \"FROM:TO\" and values are rates\n * @param source - Optional source identifier\n *\n * @example\n * service.loadRates({\n * 'USD:EUR': 0.92,\n * 'USD:GBP': 0.79,\n * }, 'daily-update')\n */\n loadRates(rates: Record<string, number | string>, source?: string): void {\n for (const [key, rate] of Object.entries(rates)) {\n const [from, to] = key.split(':')\n if (from && to) {\n this.setRate(from, to, rate, source, false) // Don't auto-inverse when batch loading\n }\n }\n }\n}\n","/**\n * Money Converter - Safe cross-currency operations.\n *\n * Bridges Money objects with ExchangeRateService to enable:\n * - Currency conversion\n * - Multi-currency arithmetic\n * - Percentage calculations across currencies\n */\n\nimport { Money } from './money.js'\nimport { ExchangeRateService } from './exchange-rate-service.js'\nimport { ExchangeRateError, CurrencyUnknownError } from './errors.js'\nimport { getCurrency } from './currency.js'\n\n/**\n * Converter for performing operations between different currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n *\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(new Money('USD', '100'), 'EUR')\n * console.log(euros.toString()) // \"92.00 EUR\"\n */\nexport class MoneyConverter {\n readonly #rateService: ExchangeRateService\n\n constructor(rateService: ExchangeRateService) {\n this.#rateService = rateService\n }\n\n #bankersRound(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Convert a Money amount to another currency.\n *\n * @param money - The amount to convert\n * @param targetCurrency - The target currency code\n * @returns A new Money in the target currency\n * @throws {ExchangeRateError} If no rate is available\n */\n convert<From extends string, To extends string>(\n money: Money<From>,\n targetCurrency: To\n ): Money<To> {\n if ((money.currency as string) === (targetCurrency as string)) {\n return money as unknown as Money<To>\n }\n\n const currencyDef = getCurrency(targetCurrency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(targetCurrency)\n }\n\n const rate = this.#rateService.getRate(money.currency, targetCurrency)\n if (!rate) {\n throw new ExchangeRateError(money.currency, targetCurrency)\n }\n\n const sourceCurrencyDef = getCurrency(money.currency)!\n const sourceSubunits = money.toSubunits()\n const sourceMultiplier = 10n ** BigInt(sourceCurrencyDef.decimalDigits)\n const targetMultiplier = 10n ** BigInt(currencyDef.decimalDigits)\n\n const RATE_PRECISION = 15n\n const rateMultiplier = 10n ** RATE_PRECISION\n const rateValue = Number(rate.rate)\n const rateBigInt = BigInt(Math.round(rateValue * Number(rateMultiplier)))\n\n const product = sourceSubunits * rateBigInt * targetMultiplier\n const divisor = rateMultiplier * sourceMultiplier\n const targetSubunits = this.#bankersRound(product, divisor)\n\n return Money.fromSubunits(targetSubunits, targetCurrency)\n }\n\n /**\n * Add two Money amounts, converting as needed.\n *\n * @param a - First amount\n * @param b - Second amount\n * @param resultCurrency - Currency for the result (must be one of the input currencies)\n * @returns Sum in the result currency\n */\n add<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.add(bConverted) as Money<R>\n }\n\n /**\n * Subtract two Money amounts, converting as needed.\n *\n * @param a - Amount to subtract from\n * @param b - Amount to subtract\n * @param resultCurrency - Currency for the result\n * @returns Difference in the result currency\n */\n subtract<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.subtract(bConverted) as Money<R>\n }\n\n /**\n * Calculate what percentage one amount is of another.\n * Converts both to the same currency before comparison.\n *\n * @param part - The partial amount\n * @param whole - The whole amount\n * @returns Percentage as a number (e.g., 25 for 25%)\n */\n percentageOf<A extends string, B extends string>(\n part: Money<A>,\n whole: Money<B>\n ): number {\n // Convert both to the 'whole' currency for comparison\n const partConverted = this.convert(part, whole.currency)\n return (partConverted.toNumber() / whole.toNumber()) * 100\n }\n\n /**\n * Sum multiple Money amounts, converting all to a target currency.\n *\n * @param amounts - Array of Money objects (can be different currencies)\n * @param targetCurrency - Currency for the result\n * @returns Total in the target currency\n */\n sum<C extends string>(amounts: Money<string>[], targetCurrency: C): Money<C> {\n let total = Money.zero(targetCurrency)\n\n for (const amount of amounts) {\n const converted = this.convert(amount, targetCurrency)\n total = total.add(converted)\n }\n\n return total\n }\n\n /**\n * Compare two Money amounts across currencies.\n * Returns negative if a < b, zero if equal, positive if a > b.\n *\n * @param a - First amount\n * @param b - Second amount\n * @returns Comparison result\n */\n compare<A extends string, B extends string>(a: Money<A>, b: Money<B>): -1 | 0 | 1 {\n // Convert b to a's currency for comparison\n const bConverted = this.convert(b, a.currency)\n return Money.compare(a, bConverted)\n }\n\n /**\n * Get the exchange rate service (for direct rate access).\n */\n get rateService(): ExchangeRateService {\n return this.#rateService\n }\n}\n","{\n \"AED\": {\n \"decimal_digits\": 2\n },\n \"AFN\": {\n \"decimal_digits\": 2\n },\n \"ALL\": {\n \"decimal_digits\": 2\n },\n \"AMD\": {\n \"decimal_digits\": 2\n },\n \"AOA\": {\n \"decimal_digits\": 2\n },\n \"ARS\": {\n \"decimal_digits\": 2\n },\n \"AUD\": {\n \"decimal_digits\": 2\n },\n \"AWG\": {\n \"decimal_digits\": 2\n },\n \"AZN\": {\n \"decimal_digits\": 2\n },\n \"BAM\": {\n \"decimal_digits\": 2\n },\n \"BBD\": {\n \"decimal_digits\": 2\n },\n \"BDT\": {\n \"decimal_digits\": 2\n },\n \"BHD\": {\n \"decimal_digits\": 3\n },\n \"BIF\": {\n \"decimal_digits\": 0\n },\n \"BMD\": {\n \"decimal_digits\": 2\n },\n \"BND\": {\n \"decimal_digits\": 2\n },\n \"BOB\": {\n \"decimal_digits\": 2\n },\n \"BOV\": {\n \"decimal_digits\": 2\n },\n \"BRL\": {\n \"decimal_digits\": 2\n },\n \"BSD\": {\n \"decimal_digits\": 2\n },\n \"BTN\": {\n \"decimal_digits\": 2\n },\n \"BWP\": {\n \"decimal_digits\": 2\n },\n \"BYN\": {\n \"decimal_digits\": 2\n },\n \"BZD\": {\n \"decimal_digits\": 2\n },\n \"CAD\": {\n \"decimal_digits\": 2\n },\n \"CDF\": {\n \"decimal_digits\": 2\n },\n \"CHE\": {\n \"decimal_digits\": 2\n },\n \"CHF\": {\n \"decimal_digits\": 2\n },\n \"CHW\": {\n \"decimal_digits\": 2\n },\n \"CLF\": {\n \"decimal_digits\": 4\n },\n \"CLP\": {\n \"decimal_digits\": 0\n },\n \"CNY\": {\n \"decimal_digits\": 2\n },\n \"COP\": {\n \"decimal_digits\": 2\n },\n \"COU\": {\n \"decimal_digits\": 2\n },\n \"CRC\": {\n \"decimal_digits\": 2\n },\n \"CUP\": {\n \"decimal_digits\": 2\n },\n \"CVE\": {\n \"decimal_digits\": 2\n },\n \"CZK\": {\n \"decimal_digits\": 2\n },\n \"DJF\": {\n \"decimal_digits\": 0\n },\n \"DKK\": {\n \"decimal_digits\": 2\n },\n \"DOP\": {\n \"decimal_digits\": 2\n },\n \"DZD\": {\n \"decimal_digits\": 2\n },\n \"EGP\": {\n \"decimal_digits\": 2\n },\n \"ERN\": {\n \"decimal_digits\": 2\n },\n \"ETB\": {\n \"decimal_digits\": 2\n },\n \"EUR\": {\n \"decimal_digits\": 2\n },\n \"FJD\": {\n \"decimal_digits\": 2\n },\n \"FKP\": {\n \"decimal_digits\": 2\n },\n \"GBP\": {\n \"decimal_digits\": 2\n },\n \"GEL\": {\n \"decimal_digits\": 2\n },\n \"GHS\": {\n \"decimal_digits\": 2\n },\n \"GIP\": {\n \"decimal_digits\": 2\n },\n \"GMD\": {\n \"decimal_digits\": 2\n },\n \"GNF\": {\n \"decimal_digits\": 0\n },\n \"GTQ\": {\n \"decimal_digits\": 2\n },\n \"GYD\": {\n \"decimal_digits\": 2\n },\n \"HKD\": {\n \"decimal_digits\": 2\n },\n \"HNL\": {\n \"decimal_digits\": 2\n },\n \"HTG\": {\n \"decimal_digits\": 2\n },\n \"HUF\": {\n \"decimal_digits\": 2\n },\n \"IDR\": {\n \"decimal_digits\": 2\n },\n \"ILS\": {\n \"decimal_digits\": 2\n },\n \"INR\": {\n \"decimal_digits\": 2\n },\n \"IQD\": {\n \"decimal_digits\": 3\n },\n \"IRR\": {\n \"decimal_digits\": 2\n },\n \"ISK\": {\n \"decimal_digits\": 0\n },\n \"JMD\": {\n \"decimal_digits\": 2\n },\n \"JOD\": {\n \"decimal_digits\": 3\n },\n \"JPY\": {\n \"decimal_digits\": 0\n },\n \"KES\": {\n \"decimal_digits\": 2\n },\n \"KGS\": {\n \"decimal_digits\": 2\n },\n \"KHR\": {\n \"decimal_digits\": 2\n },\n \"KMF\": {\n \"decimal_digits\": 0\n },\n \"KPW\": {\n \"decimal_digits\": 2\n },\n \"KRW\": {\n \"decimal_digits\": 0\n },\n \"KWD\": {\n \"decimal_digits\": 3\n },\n \"KYD\": {\n \"decimal_digits\": 2\n },\n \"KZT\": {\n \"decimal_digits\": 2\n },\n \"LAK\": {\n \"decimal_digits\": 2\n },\n \"LBP\": {\n \"decimal_digits\": 2\n },\n \"LKR\": {\n \"decimal_digits\": 2\n },\n \"LRD\": {\n \"decimal_digits\": 2\n },\n \"LSL\": {\n \"decimal_digits\": 2\n },\n \"LYD\": {\n \"decimal_digits\": 3\n },\n \"MAD\": {\n \"decimal_digits\": 2\n },\n \"MDL\": {\n \"decimal_digits\": 2\n },\n \"MGA\": {\n \"decimal_digits\": 2\n },\n \"MKD\": {\n \"decimal_digits\": 2\n },\n \"MMK\": {\n \"decimal_digits\": 2\n },\n \"MNT\": {\n \"decimal_digits\": 2\n },\n \"MOP\": {\n \"decimal_digits\": 2\n },\n \"MRU\": {\n \"decimal_digits\": 2\n },\n \"MUR\": {\n \"decimal_digits\": 2\n },\n \"MVR\": {\n \"decimal_digits\": 2\n },\n \"MWK\": {\n \"decimal_digits\": 2\n },\n \"MXN\": {\n \"decimal_digits\": 2\n },\n \"MXV\": {\n \"decimal_digits\": 2\n },\n \"MYR\": {\n \"decimal_digits\": 2\n },\n \"MZN\": {\n \"decimal_digits\": 2\n },\n \"NAD\": {\n \"decimal_digits\": 2\n },\n \"NGN\": {\n \"decimal_digits\": 2\n },\n \"NIO\": {\n \"decimal_digits\": 2\n },\n \"NOK\": {\n \"decimal_digits\": 2\n },\n \"NPR\": {\n \"decimal_digits\": 2\n },\n \"NZD\": {\n \"decimal_digits\": 2\n },\n \"OMR\": {\n \"decimal_digits\": 3\n },\n \"PAB\": {\n \"decimal_digits\": 2\n },\n \"PEN\": {\n \"decimal_digits\": 2\n },\n \"PGK\": {\n \"decimal_digits\": 2\n },\n \"PHP\": {\n \"decimal_digits\": 2\n },\n \"PKR\": {\n \"decimal_digits\": 2\n },\n \"PLN\": {\n \"decimal_digits\": 2\n },\n \"PYG\": {\n \"decimal_digits\": 0\n },\n \"QAR\": {\n \"decimal_digits\": 2\n },\n \"RON\": {\n \"decimal_digits\": 2\n },\n \"RSD\": {\n \"decimal_digits\": 2\n },\n \"RUB\": {\n \"decimal_digits\": 2\n },\n \"RWF\": {\n \"decimal_digits\": 0\n },\n \"SAR\": {\n \"decimal_digits\": 2\n },\n \"SBD\": {\n \"decimal_digits\": 2\n },\n \"SCR\": {\n \"decimal_digits\": 2\n },\n \"SDG\": {\n \"decimal_digits\": 2\n },\n \"SEK\": {\n \"decimal_digits\": 2\n },\n \"SGD\": {\n \"decimal_digits\": 2\n },\n \"SHP\": {\n \"decimal_digits\": 2\n },\n \"SLE\": {\n \"decimal_digits\": 2\n },\n \"SOS\": {\n \"decimal_digits\": 2\n },\n \"SRD\": {\n \"decimal_digits\": 2\n },\n \"SSP\": {\n \"decimal_digits\": 2\n },\n \"STN\": {\n \"decimal_digits\": 2\n },\n \"SVC\": {\n \"decimal_digits\": 2\n },\n \"SYP\": {\n \"decimal_digits\": 2\n },\n \"SZL\": {\n \"decimal_digits\": 2\n },\n \"THB\": {\n \"decimal_digits\": 2\n },\n \"TJS\": {\n \"decimal_digits\": 2\n },\n \"TMT\": {\n \"decimal_digits\": 2\n },\n \"TND\": {\n \"decimal_digits\": 3\n },\n \"TOP\": {\n \"decimal_digits\": 2\n },\n \"TRY\": {\n \"decimal_digits\": 2\n },\n \"TTD\": {\n \"decimal_digits\": 2\n },\n \"TWD\": {\n \"decimal_digits\": 2\n },\n \"TZS\": {\n \"decimal_digits\": 2\n },\n \"UAH\": {\n \"decimal_digits\": 2\n },\n \"UGX\": {\n \"decimal_digits\": 0\n },\n \"USD\": {\n \"decimal_digits\": 2\n },\n \"USN\": {\n \"decimal_digits\": 2\n },\n \"UYI\": {\n \"decimal_digits\": 0\n },\n \"UYU\": {\n \"decimal_digits\": 2\n },\n \"UYW\": {\n \"decimal_digits\": 4\n },\n \"UZS\": {\n \"decimal_digits\": 2\n },\n \"VED\": {\n \"decimal_digits\": 2\n },\n \"VES\": {\n \"decimal_digits\": 2\n },\n \"VND\": {\n \"decimal_digits\": 0\n },\n \"VUV\": {\n \"decimal_digits\": 0\n },\n \"WST\": {\n \"decimal_digits\": 2\n },\n \"XAD\": {\n \"decimal_digits\": 2\n },\n \"XAF\": {\n \"decimal_digits\": 0\n },\n \"XAG\": {\n \"decimal_digits\": 0\n },\n \"XAU\": {\n \"decimal_digits\": 0\n },\n \"XBA\": {\n \"decimal_digits\": 0\n },\n \"XBB\": {\n \"decimal_digits\": 0\n },\n \"XBC\": {\n \"decimal_digits\": 0\n },\n \"XBD\": {\n \"decimal_digits\": 0\n },\n \"XCD\": {\n \"decimal_digits\": 2\n },\n \"XCG\": {\n \"decimal_digits\": 2\n },\n \"XDR\": {\n \"decimal_digits\": 0\n },\n \"XOF\": {\n \"decimal_digits\": 0\n },\n \"XPD\": {\n \"decimal_digits\": 0\n },\n \"XPF\": {\n \"decimal_digits\": 0\n },\n \"XPT\": {\n \"decimal_digits\": 0\n },\n \"XSU\": {\n \"decimal_digits\": 0\n },\n \"XTS\": {\n \"decimal_digits\": 0\n },\n \"XUA\": {\n \"decimal_digits\": 0\n },\n \"XXX\": {\n \"decimal_digits\": 0\n },\n \"YER\": {\n \"decimal_digits\": 2\n },\n \"ZAR\": {\n \"decimal_digits\": 2\n },\n \"ZMW\": {\n \"decimal_digits\": 2\n },\n \"ZWG\": {\n \"decimal_digits\": 2\n }\n}"],"mappings":"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AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AACH;;;ANheA,gBAAgB,mBAAyD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../lib/index.ts","../lib/errors.ts","../lib/currency.ts","../lib/money.ts","../lib/exchange-rate-service.ts","../lib/money-converter.ts","../currencymap.json"],"sourcesContent":["/**\n * subunit-money - A type-safe value object for monetary amounts\n *\n * @example\n * import { Money, ExchangeRateService, MoneyConverter } from '@cbrunnkvist/subunit-money'\n *\n * // Basic usage\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n *\n * // Currency conversion\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(total, 'EUR')\n */\n\n// Core classes\nexport { Money, type MoneyObject } from './money.js'\nexport { ExchangeRateService, type ExchangeRate, type RatePair } from './exchange-rate-service.js'\nexport { MoneyConverter } from './money-converter.js'\n\n// Error types\nexport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n ExchangeRateError,\n} from './errors.js'\n\n// Currency utilities\nexport {\n registerCurrency,\n getCurrency,\n hasCurrency,\n getAllCurrencies,\n loadCurrencyMap,\n clearCurrencies,\n type CurrencyDefinition,\n} from './currency.js'\n\n// Auto-load default currencies\n// The currencymap.json file is the official ISO 4217 currency list (List One) as of 2026-01-01,\n// sourced from SIX Financial Information AG (the ISO 4217 Maintenance Agency).\n//\n// To regenerate:\n// 1. Download list-one.xml from https://www.six-group.com/en/products-services/financial-information/data-standards.html\n// 2. Convert with: yq -p xml -o json '.' list-one.xml | jq '.ISO_4217.CcyTbl.CcyNtry | map(select(.Ccy) | {(.Ccy): {decimal_digits: (if (.CcyMnrUnts == \"N.A.\" or .CcyMnrUnts == null) then 0 else (.CcyMnrUnts | tonumber) end)}}) | add | to_entries | sort_by(.key) | from_entries' > currencymap.json\n//\n// Note: This excludes historical currencies, supranational funds, and precious metals,\n// keeping only active national and regional currencies for practical use.\nimport { loadCurrencyMap } from './currency.js'\nimport currencyMap from '../currencymap.json'\nloadCurrencyMap(currencyMap as Record<string, { decimal_digits: number }>)\n","/**\n * Custom error types for Money operations.\n * All errors extend built-in Error types for proper instanceof checks.\n */\n\n/**\n * Thrown when attempting operations between different currencies.\n * @example\n * new Money('USD', 10).add(new Money('EUR', 5)) // throws CurrencyMismatchError\n */\nexport class CurrencyMismatchError extends TypeError {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`Cannot operate on ${fromCurrency} and ${toCurrency} - currencies must match`)\n this.name = 'CurrencyMismatchError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, CurrencyMismatchError)\n }\n}\n\n/**\n * Thrown when using an unregistered currency code.\n * @example\n * new Money('FAKE', 10) // throws CurrencyUnknownError\n */\nexport class CurrencyUnknownError extends TypeError {\n readonly currency: string\n\n constructor(currency: string) {\n super(`Unknown currency '${currency}' - register it first with Money.registerCurrency()`)\n this.name = 'CurrencyUnknownError'\n this.currency = currency\n Error.captureStackTrace?.(this, CurrencyUnknownError)\n }\n}\n\n/**\n * Thrown when an amount has more decimal places than the currency allows.\n * @example\n * new Money('USD', '1.234') // throws SubunitError (USD only allows 2 decimals)\n */\nexport class SubunitError extends RangeError {\n readonly currency: string\n readonly maxDecimals: number\n\n constructor(currency: string, maxDecimals: number) {\n super(`${currency} only supports ${maxDecimals} decimal place(s)`)\n this.name = 'SubunitError'\n this.currency = currency\n this.maxDecimals = maxDecimals\n Error.captureStackTrace?.(this, SubunitError)\n }\n}\n\n/**\n * Thrown when an amount cannot be parsed as a valid number.\n * @example\n * new Money('USD', 'abc') // throws AmountError\n */\nexport class AmountError extends TypeError {\n readonly amount: unknown\n\n constructor(amount: unknown) {\n super(`Invalid amount: ${JSON.stringify(amount)}`)\n this.name = 'AmountError'\n this.amount = amount\n Error.captureStackTrace?.(this, AmountError)\n }\n}\n\n/**\n * Thrown when an exchange rate is not available.\n * @example\n * converter.convert(usdMoney, 'XYZ') // throws ExchangeRateError if no USD->XYZ rate\n */\nexport class ExchangeRateError extends Error {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`No exchange rate available from ${fromCurrency} to ${toCurrency}`)\n this.name = 'ExchangeRateError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, ExchangeRateError)\n }\n}\n","/**\n * Currency registry and types.\n * Manages ISO 4217 currency definitions and custom currencies.\n */\n\nexport interface CurrencyDefinition {\n code: string\n decimalDigits: number\n displayDecimals?: number\n}\n\n// Internal registry - mutable for registerCurrency()\nconst currencies: Map<string, CurrencyDefinition> = new Map()\n\n/**\n * Register a new currency or update an existing one.\n * @param code - ISO 4217 currency code (e.g., 'USD', 'EUR', 'BTC')\n * @param decimalDigits - Number of decimal places (e.g., 2 for USD, 8 for BTC)\n * @param displayDecimals - Optional number of decimal places to use for display/formatting (defaults to decimalDigits)\n */\nexport function registerCurrency(code: string, decimalDigits: number, displayDecimals?: number): void {\n currencies.set(code, { code, decimalDigits, displayDecimals })\n}\n\n/**\n * Get a currency definition by code.\n * @returns The currency definition, or undefined if not registered\n */\nexport function getCurrency(code: string): CurrencyDefinition | undefined {\n return currencies.get(code)\n}\n\n/**\n * Check if a currency is registered.\n */\nexport function hasCurrency(code: string): boolean {\n return currencies.has(code)\n}\n\n/**\n * Get all registered currencies, sorted by code.\n */\nexport function getAllCurrencies(): CurrencyDefinition[] {\n return Array.from(currencies.values()).sort((a, b) => a.code.localeCompare(b.code))\n}\n\n/**\n * Load currencies from the legacy currencymap.json format.\n * @param map - Object with currency codes as keys and {decimal_digits: number} as values\n */\nexport function loadCurrencyMap(map: Record<string, { decimal_digits: number }>): void {\n for (const [code, data] of Object.entries(map)) {\n registerCurrency(code, data.decimal_digits)\n }\n}\n\n/**\n * Clear all registered currencies. Useful for testing.\n */\nexport function clearCurrencies(): void {\n currencies.clear()\n}\n","/**\n * Money - An immutable value object for monetary amounts.\n *\n * Design principles:\n * - Immutable: all operations return new instances\n * - Type-safe: currency mismatches are caught at compile time (when possible) and runtime\n * - Precise: uses BigInt internally to avoid floating-point errors\n * - String-based API: amounts are strings to preserve precision in JSON/DB round-trips\n */\n\nimport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n} from './errors.js'\nimport { getCurrency, hasCurrency, type CurrencyDefinition } from './currency.js'\n\n/**\n * Serialized form of a Money object, safe for JSON.\n */\nexport interface MoneyObject<C extends string = string> {\n currency: C\n amount: string\n}\n\n/**\n * Money class - represents a monetary amount in a specific currency.\n *\n * @typeParam C - The currency code type (enables compile-time currency checking)\n *\n * @example\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n * console.log(total.amount) // \"21.59\"\n */\nexport class Money<C extends string = string> {\n readonly currency: C\n readonly amount: string\n readonly displayAmount: string\n\n // Private BigInt storage - stores currency native subunits directly\n readonly #subunits: bigint\n readonly #currencyDef: CurrencyDefinition\n\n /**\n * Create a new Money instance.\n *\n * @param currency - ISO 4217 currency code (must be registered)\n * @param amount - The amount as a number or string\n * @throws {CurrencyUnknownError} If the currency is not registered\n * @throws {AmountError} If the amount is not a valid number\n * @throws {SubunitError} If the amount has more decimals than the currency allows\n */\n constructor(currency: C, amount: number | string) {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n this.currency = currency\n this.#currencyDef = currencyDef\n this.#subunits = this.#parseAmount(amount)\n \n // Pre-calculate string representations for better DX and performance\n this.amount = Money.#formatSubunits(this.#subunits, currencyDef)\n this.displayAmount = Money.#formatForDisplay(this.amount, currencyDef)\n }\n\n /**\n * Parse an amount into native subunits.\n */\n #parseAmount(amount: number | string): bigint {\n const str = typeof amount === 'number' ? String(amount) : amount\n\n const match = str.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!match) {\n throw new AmountError(amount)\n }\n\n const [, sign, whole, frac = ''] = match\n\n if (frac.length > this.#currencyDef.decimalDigits) {\n throw new SubunitError(this.currency, this.#currencyDef.decimalDigits)\n }\n\n const paddedFrac = frac.padEnd(this.#currencyDef.decimalDigits, '0')\n const combined = BigInt(whole + paddedFrac)\n\n return sign === '-' ? -combined : combined\n }\n\n /**\n * Custom console inspection for Node.js.\n * Shows the amount and currency instead of just the class name.\n */\n [Symbol.for('nodejs.util.inspect.custom')](): string {\n return `Money { displayAmount: '${this.displayAmount}', currency: '${this.currency}', amount: '${this.amount}' }`\n }\n\n /**\n * Format the full amount string for display purposes.\n */\n static #formatForDisplay(fullAmount: string, currencyDef: CurrencyDefinition): string {\n const preferredDecimals = currencyDef.displayDecimals ?? currencyDef.decimalDigits\n\n // Split into whole and fractional parts\n const [whole, frac = ''] = fullAmount.split('.')\n\n if (!frac) return whole\n\n // Trim trailing zeros\n let trimmedFrac = frac.replace(/0+$/, '')\n\n // Pad back to preferred decimals if needed\n if (trimmedFrac.length < preferredDecimals) {\n trimmedFrac = trimmedFrac.padEnd(preferredDecimals, '0')\n }\n\n // If fractional part is empty and we want 0 decimals, return whole\n if (trimmedFrac === '' && preferredDecimals === 0) {\n return whole\n }\n \n return `${whole}.${trimmedFrac}`\n }\n\n\n\n /**\n * Ensure another Money has the same currency.\n */\n #assertSameCurrency(other: Money<string>): void {\n if (this.currency !== other.currency) {\n throw new CurrencyMismatchError(this.currency, other.currency)\n }\n }\n\n /**\n * Get the internal BigInt value (for operations).\n */\n #getInternalValue(): bigint {\n return this.#subunits\n }\n\n // ============ Arithmetic Operations ============\n\n /**\n * Add another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n add(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits + other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Subtract another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n subtract(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits - other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Multiply by a factor.\n *\n * DESIGN: Rounds immediately after multiplication using banker's rounding\n * (round half-to-even). This prevents the \"split penny problem\".\n */\n multiply(factor: number): Money<C> {\n if (typeof factor !== 'number' || !Number.isFinite(factor)) {\n throw new TypeError(`Factor must be a finite number, got: ${factor}`)\n }\n\n const { value: factorValue, scale } = Money.#parseFactor(factor)\n const product = this.#subunits * factorValue\n const divisor = 10n ** scale\n \n const result = Money.#roundedDivide(product, divisor)\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Helper to parse a number factor into a BigInt and a power-of-10 scale.\n * Uses String() conversion to avoid floating-point epsilon noise,\n * ensuring that 0.545 is treated as exactly 0.545, not 0.54500000000000004.\n */\n static #parseFactor(factor: number): { value: bigint, scale: bigint } {\n const str = String(factor)\n const [base, exponent] = str.split('e')\n \n const baseMatch = base.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!baseMatch) {\n // Fallback for unlikely cases, though String(number) should strictly produce valid formats\n throw new TypeError(`Invalid factor format: ${str}`)\n }\n \n const [, sign, whole, frac = ''] = baseMatch\n const baseValue = BigInt((sign || '') + whole + frac)\n const baseDecimals = frac.length\n \n const exp = exponent ? Number(exponent) : 0\n const netExp = exp - baseDecimals\n \n if (netExp >= 0) {\n return { value: baseValue * 10n ** BigInt(netExp), scale: 0n }\n } else {\n return { value: baseValue, scale: BigInt(-netExp) }\n }\n }\n\n /**\n * Divide with banker's rounding (round half-to-even).\n * IEEE 754-2008 recommended default rounding mode for financial calculations.\n */\n static #roundedDivide(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Allocate this amount proportionally.\n * Handles remainder distribution to avoid losing pennies.\n *\n * @param proportions - Array of proportions (e.g., [1, 1, 1] for three-way split)\n * @returns Array of Money objects that sum to the original amount\n */\n allocate(proportions: number[]): Money<C>[] {\n if (!Array.isArray(proportions) || proportions.length === 0) {\n throw new TypeError('Proportions must be a non-empty array')\n }\n\n for (const p of proportions) {\n if (typeof p !== 'number' || !Number.isFinite(p) || p < 0) {\n throw new TypeError('All proportions must be non-negative finite numbers')\n }\n }\n\n const total = proportions.reduce((sum, p) => sum + p, 0)\n if (total <= 0) {\n throw new TypeError('Sum of proportions must be positive')\n }\n\n const totalSubunits = this.#subunits\n\n // Calculate base allocations\n const allocations: bigint[] = proportions.map((p) => {\n return (totalSubunits * BigInt(Math.round(p * 1000000))) / BigInt(Math.round(total * 1000000))\n })\n\n // Distribute remainder\n let remainder = totalSubunits - allocations.reduce((sum, a) => sum + a, 0n)\n let i = 0\n while (remainder > 0n) {\n allocations[i % allocations.length] += 1n\n remainder -= 1n\n i++\n }\n while (remainder < 0n) {\n allocations[i % allocations.length] -= 1n\n remainder += 1n\n i++\n }\n\n // Convert back to Money objects\n return allocations.map((subunits) => {\n return Money.#createFromSubunits(subunits, this.currency, this.#currencyDef)\n })\n }\n\n // ============ Comparison Operations ============\n\n /**\n * Check if this amount equals another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n equalTo(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits === other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits > other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits < other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits >= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits <= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is zero.\n */\n isZero(): boolean {\n return this.#subunits === 0n\n }\n\n /**\n * Check if this amount is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.#subunits > 0n\n }\n\n /**\n * Check if this amount is negative (less than zero).\n */\n isNegative(): boolean {\n return this.#subunits < 0n\n }\n\n // ============ Serialization ============\n\n /**\n * Convert to a plain object (safe for JSON).\n */\n toJSON(): MoneyObject<C> {\n return {\n currency: this.currency,\n amount: this.amount,\n }\n }\n\n /**\n * Convert to string representation.\n */\n toString(): string {\n return `${this.displayAmount} ${this.currency}`\n }\n\n /**\n * Get the amount as a number (may lose precision for large values).\n * Use with caution - prefer string-based operations.\n */\n toNumber(): number {\n return Number(this.amount)\n }\n\n /**\n * Get the amount in subunits (e.g., cents for USD).\n * Useful for database storage (Stripe-style integer storage).\n */\n toSubunits(): bigint {\n return this.#subunits\n }\n\n // ============ Static Factory Methods ============\n\n /**\n * Create a Money instance from a plain object.\n */\n static fromObject<C extends string>(obj: MoneyObject<C>): Money<C> {\n return new Money(obj.currency, obj.amount)\n }\n\n /**\n * Create a Money instance from subunits (e.g., cents).\n * Useful for loading from database (Stripe-style integer storage).\n */\n static fromSubunits<C extends string>(subunits: bigint | number, currency: C): Money<C> {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n const bigintSubunits = typeof subunits === 'number' ? BigInt(subunits) : subunits\n return Money.#createFromSubunits(bigintSubunits, currency, currencyDef)\n }\n\n /**\n * Compare two Money objects (for use with Array.sort).\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n static compare<C extends string>(a: Money<C>, b: Money<C>): -1 | 0 | 1 {\n if (a.currency !== b.currency) {\n throw new CurrencyMismatchError(a.currency, b.currency)\n }\n const aVal = a.#getInternalValue()\n const bVal = b.#getInternalValue()\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n }\n\n /**\n * Create a zero amount in the specified currency.\n */\n static zero<C extends string>(currency: C): Money<C> {\n return new Money(currency, '0')\n }\n\n /**\n * Internal factory that bypasses parsing.\n */\n static #createFromSubunits<C extends string>(\n subunits: bigint,\n currency: C,\n currencyDef: CurrencyDefinition\n ): Money<C> {\n return new Money(currency, Money.#formatSubunits(subunits, currencyDef))\n }\n\n /**\n * Format subunits to string amount.\n */\n static #formatSubunits(subunits: bigint, currencyDef: CurrencyDefinition): string {\n const decimals = currencyDef.decimalDigits\n const abs = subunits < 0n ? -subunits : subunits\n const isNegative = subunits < 0n\n\n if (decimals === 0) {\n return `${isNegative ? '-' : ''}${abs}`\n }\n\n const multiplier = 10n ** BigInt(decimals)\n const wholePart = abs / multiplier\n const fracPart = abs % multiplier\n\n const sign = isNegative ? '-' : ''\n return `${sign}${wholePart}.${fracPart.toString().padStart(decimals, '0')}`\n }\n}\n","/**\n * Exchange Rate Service - Central authority for currency conversion rates.\n *\n * Design principles:\n * - Rates are stored as strings to preserve precision\n * - Timestamps track when rates were set\n * - Optional source tracking for audit trails\n * - Inverse rates can be auto-generated or explicitly set\n */\n\nexport interface ExchangeRate {\n from: string\n to: string\n rate: string\n timestamp: Date\n source?: string\n}\n\nexport interface RatePair {\n forward: ExchangeRate\n reverse: ExchangeRate\n /** Relative discrepancy between forward and 1/reverse rates */\n discrepancy: number\n}\n\n/**\n * Service for managing exchange rates between currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92, 'ECB')\n * rates.getRate('USD', 'EUR') // { from: 'USD', to: 'EUR', rate: '0.92', ... }\n */\nexport class ExchangeRateService {\n readonly #rates: Map<string, ExchangeRate> = new Map()\n\n /**\n * Create a rate key for storage.\n */\n #key(from: string, to: string): string {\n return `${from}:${to}`\n }\n\n /**\n * Set an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @param rate - Exchange rate (1 unit of 'from' = rate units of 'to')\n * @param source - Optional source identifier (e.g., 'ECB', 'Coinbase')\n * @param autoInverse - If true, automatically create inverse rate (default: true)\n */\n setRate(\n from: string,\n to: string,\n rate: number | string,\n source?: string,\n autoInverse: boolean = true\n ): void {\n const rateStr = typeof rate === 'number' ? rate.toPrecision(15) : rate\n\n this.#rates.set(this.#key(from, to), {\n from,\n to,\n rate: rateStr,\n timestamp: new Date(),\n source,\n })\n\n // Auto-create inverse rate if requested and not already explicitly set\n if (autoInverse) {\n const inverseKey = this.#key(to, from)\n if (!this.#rates.has(inverseKey)) {\n const inverseRate = 1 / Number(rateStr)\n this.#rates.set(inverseKey, {\n from: to,\n to: from,\n rate: inverseRate.toPrecision(15),\n timestamp: new Date(),\n source: source ? `${source} (inverse)` : '(inverse)',\n })\n }\n }\n }\n\n /**\n * Get an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @returns The exchange rate, or undefined if not set\n */\n getRate(from: string, to: string): ExchangeRate | undefined {\n // Same currency = rate of 1\n if (from === to) {\n return {\n from,\n to,\n rate: '1',\n timestamp: new Date(),\n source: '(identity)',\n }\n }\n\n return this.#rates.get(this.#key(from, to))\n }\n\n /**\n * Check if a rate exists.\n */\n hasRate(from: string, to: string): boolean {\n return from === to || this.#rates.has(this.#key(from, to))\n }\n\n /**\n * Remove a rate.\n */\n removeRate(from: string, to: string): boolean {\n return this.#rates.delete(this.#key(from, to))\n }\n\n /**\n * Get both forward and reverse rates, with discrepancy analysis.\n * Useful for detecting rate inconsistencies.\n *\n * @param currencyA - First currency\n * @param currencyB - Second currency\n * @returns Rate pair with discrepancy, or undefined if either rate is missing\n */\n getRatePair(currencyA: string, currencyB: string): RatePair | undefined {\n const forward = this.getRate(currencyA, currencyB)\n const reverse = this.getRate(currencyB, currencyA)\n\n if (!forward || !reverse) {\n return undefined\n }\n\n // Calculate discrepancy: how far is forward * reverse from 1.0?\n const product = Number(forward.rate) * Number(reverse.rate)\n const discrepancy = Math.abs(1 - product)\n\n return { forward, reverse, discrepancy }\n }\n\n /**\n * Get all rates for a specific base currency.\n *\n * @param base - The base currency code\n * @returns Array of rates from this currency\n */\n getRatesFrom(base: string): ExchangeRate[] {\n const rates: ExchangeRate[] = []\n for (const rate of this.#rates.values()) {\n if (rate.from === base) {\n rates.push(rate)\n }\n }\n return rates.sort((a, b) => a.to.localeCompare(b.to))\n }\n\n /**\n * Get all registered rates.\n */\n getAllRates(): ExchangeRate[] {\n return Array.from(this.#rates.values()).sort((a, b) => {\n const fromCompare = a.from.localeCompare(b.from)\n return fromCompare !== 0 ? fromCompare : a.to.localeCompare(b.to)\n })\n }\n\n /**\n * Clear all rates.\n */\n clear(): void {\n this.#rates.clear()\n }\n\n /**\n * Load rates from a simple object.\n *\n * @param rates - Object where keys are \"FROM:TO\" and values are rates\n * @param source - Optional source identifier\n *\n * @example\n * service.loadRates({\n * 'USD:EUR': 0.92,\n * 'USD:GBP': 0.79,\n * }, 'daily-update')\n */\n loadRates(rates: Record<string, number | string>, source?: string): void {\n for (const [key, rate] of Object.entries(rates)) {\n const [from, to] = key.split(':')\n if (from && to) {\n this.setRate(from, to, rate, source, false) // Don't auto-inverse when batch loading\n }\n }\n }\n}\n","/**\n * Money Converter - Safe cross-currency operations.\n *\n * Bridges Money objects with ExchangeRateService to enable:\n * - Currency conversion\n * - Multi-currency arithmetic\n * - Percentage calculations across currencies\n */\n\nimport { Money } from './money.js'\nimport { ExchangeRateService } from './exchange-rate-service.js'\nimport { ExchangeRateError, CurrencyUnknownError } from './errors.js'\nimport { getCurrency } from './currency.js'\n\n/**\n * Converter for performing operations between different currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n *\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(new Money('USD', '100'), 'EUR')\n * console.log(euros.toString()) // \"92.00 EUR\"\n */\nexport class MoneyConverter {\n readonly #rateService: ExchangeRateService\n\n constructor(rateService: ExchangeRateService) {\n this.#rateService = rateService\n }\n\n #bankersRound(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Convert a Money amount to another currency.\n *\n * @param money - The amount to convert\n * @param targetCurrency - The target currency code\n * @returns A new Money in the target currency\n * @throws {ExchangeRateError} If no rate is available\n */\n convert<From extends string, To extends string>(\n money: Money<From>,\n targetCurrency: To\n ): Money<To> {\n if ((money.currency as string) === (targetCurrency as string)) {\n return money as unknown as Money<To>\n }\n\n const currencyDef = getCurrency(targetCurrency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(targetCurrency)\n }\n\n const rate = this.#rateService.getRate(money.currency, targetCurrency)\n if (!rate) {\n throw new ExchangeRateError(money.currency, targetCurrency)\n }\n\n const sourceCurrencyDef = getCurrency(money.currency)!\n const sourceSubunits = money.toSubunits()\n const sourceMultiplier = 10n ** BigInt(sourceCurrencyDef.decimalDigits)\n const targetMultiplier = 10n ** BigInt(currencyDef.decimalDigits)\n\n const RATE_PRECISION = 15n\n const rateMultiplier = 10n ** RATE_PRECISION\n const rateValue = Number(rate.rate)\n const rateBigInt = BigInt(Math.round(rateValue * Number(rateMultiplier)))\n\n const product = sourceSubunits * rateBigInt * targetMultiplier\n const divisor = rateMultiplier * sourceMultiplier\n const targetSubunits = this.#bankersRound(product, divisor)\n\n return Money.fromSubunits(targetSubunits, targetCurrency)\n }\n\n /**\n * Add two Money amounts, converting as needed.\n *\n * @param a - First amount\n * @param b - Second amount\n * @param resultCurrency - Currency for the result (must be one of the input currencies)\n * @returns Sum in the result currency\n */\n add<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.add(bConverted) as Money<R>\n }\n\n /**\n * Subtract two Money amounts, converting as needed.\n *\n * @param a - Amount to subtract from\n * @param b - Amount to subtract\n * @param resultCurrency - Currency for the result\n * @returns Difference in the result currency\n */\n subtract<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.subtract(bConverted) as Money<R>\n }\n\n /**\n * Calculate what percentage one amount is of another.\n * Converts both to the same currency before comparison.\n *\n * @param part - The partial amount\n * @param whole - The whole amount\n * @returns Percentage as a number (e.g., 25 for 25%)\n */\n percentageOf<A extends string, B extends string>(\n part: Money<A>,\n whole: Money<B>\n ): number {\n // Convert both to the 'whole' currency for comparison\n const partConverted = this.convert(part, whole.currency)\n return (partConverted.toNumber() / whole.toNumber()) * 100\n }\n\n /**\n * Sum multiple Money amounts, converting all to a target currency.\n *\n * @param amounts - Array of Money objects (can be different currencies)\n * @param targetCurrency - Currency for the result\n * @returns Total in the target currency\n */\n sum<C extends string>(amounts: Money<string>[], targetCurrency: C): Money<C> {\n let total = Money.zero(targetCurrency)\n\n for (const amount of amounts) {\n const converted = this.convert(amount, targetCurrency)\n total = total.add(converted)\n }\n\n return total\n }\n\n /**\n * Compare two Money amounts across currencies.\n * Returns negative if a < b, zero if equal, positive if a > b.\n *\n * @param a - First amount\n * @param b - Second amount\n * @returns Comparison result\n */\n compare<A extends string, B extends string>(a: Money<A>, b: Money<B>): -1 | 0 | 1 {\n // Convert b to a's currency for comparison\n const bConverted = this.convert(b, a.currency)\n return Money.compare(a, bConverted)\n }\n\n /**\n * Get the exchange rate service (for direct rate access).\n */\n get rateService(): ExchangeRateService {\n return this.#rateService\n }\n}\n","{\n \"AED\": {\n \"decimal_digits\": 2\n },\n \"AFN\": {\n \"decimal_digits\": 2\n },\n \"ALL\": {\n \"decimal_digits\": 2\n },\n \"AMD\": {\n \"decimal_digits\": 2\n },\n \"AOA\": {\n \"decimal_digits\": 2\n },\n \"ARS\": {\n \"decimal_digits\": 2\n },\n \"AUD\": {\n \"decimal_digits\": 2\n },\n \"AWG\": {\n \"decimal_digits\": 2\n },\n \"AZN\": {\n \"decimal_digits\": 2\n },\n \"BAM\": {\n \"decimal_digits\": 2\n },\n \"BBD\": {\n \"decimal_digits\": 2\n },\n \"BDT\": {\n \"decimal_digits\": 2\n },\n \"BHD\": {\n \"decimal_digits\": 3\n },\n \"BIF\": {\n \"decimal_digits\": 0\n },\n \"BMD\": {\n \"decimal_digits\": 2\n },\n \"BND\": {\n \"decimal_digits\": 2\n },\n \"BOB\": {\n \"decimal_digits\": 2\n },\n \"BOV\": {\n \"decimal_digits\": 2\n },\n \"BRL\": {\n \"decimal_digits\": 2\n },\n \"BSD\": {\n \"decimal_digits\": 2\n },\n \"BTN\": {\n \"decimal_digits\": 2\n },\n \"BWP\": {\n \"decimal_digits\": 2\n },\n \"BYN\": {\n \"decimal_digits\": 2\n },\n \"BZD\": {\n \"decimal_digits\": 2\n },\n \"CAD\": {\n \"decimal_digits\": 2\n },\n \"CDF\": {\n \"decimal_digits\": 2\n },\n \"CHE\": {\n \"decimal_digits\": 2\n },\n \"CHF\": {\n \"decimal_digits\": 2\n },\n \"CHW\": {\n \"decimal_digits\": 2\n },\n \"CLF\": {\n \"decimal_digits\": 4\n },\n \"CLP\": {\n \"decimal_digits\": 0\n },\n \"CNY\": {\n \"decimal_digits\": 2\n },\n \"COP\": {\n \"decimal_digits\": 2\n },\n \"COU\": {\n \"decimal_digits\": 2\n },\n \"CRC\": {\n \"decimal_digits\": 2\n },\n \"CUP\": {\n \"decimal_digits\": 2\n },\n \"CVE\": {\n \"decimal_digits\": 2\n },\n \"CZK\": {\n \"decimal_digits\": 2\n },\n \"DJF\": {\n \"decimal_digits\": 0\n },\n \"DKK\": {\n \"decimal_digits\": 2\n },\n \"DOP\": {\n \"decimal_digits\": 2\n },\n \"DZD\": {\n \"decimal_digits\": 2\n },\n \"EGP\": {\n \"decimal_digits\": 2\n },\n \"ERN\": {\n \"decimal_digits\": 2\n },\n \"ETB\": {\n \"decimal_digits\": 2\n },\n \"EUR\": {\n \"decimal_digits\": 2\n },\n \"FJD\": {\n \"decimal_digits\": 2\n },\n \"FKP\": {\n \"decimal_digits\": 2\n },\n \"GBP\": {\n \"decimal_digits\": 2\n },\n \"GEL\": {\n \"decimal_digits\": 2\n },\n \"GHS\": {\n \"decimal_digits\": 2\n },\n \"GIP\": {\n \"decimal_digits\": 2\n },\n \"GMD\": {\n \"decimal_digits\": 2\n },\n \"GNF\": {\n \"decimal_digits\": 0\n },\n \"GTQ\": {\n \"decimal_digits\": 2\n },\n \"GYD\": {\n \"decimal_digits\": 2\n },\n \"HKD\": {\n \"decimal_digits\": 2\n },\n \"HNL\": {\n \"decimal_digits\": 2\n },\n \"HTG\": {\n \"decimal_digits\": 2\n },\n \"HUF\": {\n \"decimal_digits\": 2\n },\n \"IDR\": {\n \"decimal_digits\": 2\n },\n \"ILS\": {\n \"decimal_digits\": 2\n },\n \"INR\": {\n \"decimal_digits\": 2\n },\n \"IQD\": {\n \"decimal_digits\": 3\n },\n \"IRR\": {\n \"decimal_digits\": 2\n },\n \"ISK\": {\n \"decimal_digits\": 0\n },\n \"JMD\": {\n \"decimal_digits\": 2\n },\n \"JOD\": {\n \"decimal_digits\": 3\n },\n \"JPY\": {\n \"decimal_digits\": 0\n },\n \"KES\": {\n \"decimal_digits\": 2\n },\n \"KGS\": {\n \"decimal_digits\": 2\n },\n \"KHR\": {\n \"decimal_digits\": 2\n },\n \"KMF\": {\n \"decimal_digits\": 0\n },\n \"KPW\": {\n \"decimal_digits\": 2\n },\n \"KRW\": {\n \"decimal_digits\": 0\n },\n \"KWD\": {\n \"decimal_digits\": 3\n },\n \"KYD\": {\n \"decimal_digits\": 2\n },\n \"KZT\": {\n \"decimal_digits\": 2\n },\n \"LAK\": {\n \"decimal_digits\": 2\n },\n \"LBP\": {\n \"decimal_digits\": 2\n },\n \"LKR\": {\n \"decimal_digits\": 2\n },\n \"LRD\": {\n \"decimal_digits\": 2\n },\n \"LSL\": {\n \"decimal_digits\": 2\n },\n \"LYD\": {\n \"decimal_digits\": 3\n },\n \"MAD\": {\n \"decimal_digits\": 2\n },\n \"MDL\": {\n \"decimal_digits\": 2\n },\n \"MGA\": {\n \"decimal_digits\": 2\n },\n \"MKD\": {\n \"decimal_digits\": 2\n },\n \"MMK\": {\n \"decimal_digits\": 2\n },\n \"MNT\": {\n \"decimal_digits\": 2\n },\n \"MOP\": {\n \"decimal_digits\": 2\n },\n \"MRU\": {\n \"decimal_digits\": 2\n },\n \"MUR\": {\n \"decimal_digits\": 2\n },\n \"MVR\": {\n \"decimal_digits\": 2\n },\n \"MWK\": {\n \"decimal_digits\": 2\n },\n \"MXN\": {\n \"decimal_digits\": 2\n },\n \"MXV\": {\n \"decimal_digits\": 2\n },\n \"MYR\": {\n \"decimal_digits\": 2\n },\n \"MZN\": {\n \"decimal_digits\": 2\n },\n \"NAD\": {\n \"decimal_digits\": 2\n },\n \"NGN\": {\n \"decimal_digits\": 2\n },\n \"NIO\": {\n \"decimal_digits\": 2\n },\n \"NOK\": {\n \"decimal_digits\": 2\n },\n \"NPR\": {\n \"decimal_digits\": 2\n },\n \"NZD\": {\n \"decimal_digits\": 2\n },\n \"OMR\": {\n \"decimal_digits\": 3\n },\n \"PAB\": {\n \"decimal_digits\": 2\n },\n \"PEN\": {\n \"decimal_digits\": 2\n },\n \"PGK\": {\n \"decimal_digits\": 2\n },\n \"PHP\": {\n \"decimal_digits\": 2\n },\n \"PKR\": {\n \"decimal_digits\": 2\n },\n \"PLN\": {\n \"decimal_digits\": 2\n },\n \"PYG\": {\n \"decimal_digits\": 0\n },\n \"QAR\": {\n \"decimal_digits\": 2\n },\n \"RON\": {\n \"decimal_digits\": 2\n },\n \"RSD\": {\n \"decimal_digits\": 2\n },\n \"RUB\": {\n \"decimal_digits\": 2\n },\n \"RWF\": {\n \"decimal_digits\": 0\n },\n \"SAR\": {\n \"decimal_digits\": 2\n },\n \"SBD\": {\n \"decimal_digits\": 2\n },\n \"SCR\": {\n \"decimal_digits\": 2\n },\n \"SDG\": {\n \"decimal_digits\": 2\n },\n \"SEK\": {\n \"decimal_digits\": 2\n },\n \"SGD\": {\n \"decimal_digits\": 2\n },\n \"SHP\": {\n \"decimal_digits\": 2\n },\n \"SLE\": {\n \"decimal_digits\": 2\n },\n \"SOS\": {\n \"decimal_digits\": 2\n },\n \"SRD\": {\n \"decimal_digits\": 2\n },\n \"SSP\": {\n \"decimal_digits\": 2\n },\n \"STN\": {\n \"decimal_digits\": 2\n },\n \"SVC\": {\n \"decimal_digits\": 2\n },\n \"SYP\": {\n \"decimal_digits\": 2\n },\n \"SZL\": {\n \"decimal_digits\": 2\n },\n \"THB\": {\n \"decimal_digits\": 2\n },\n \"TJS\": {\n \"decimal_digits\": 2\n },\n \"TMT\": {\n \"decimal_digits\": 2\n },\n \"TND\": {\n \"decimal_digits\": 3\n },\n \"TOP\": {\n \"decimal_digits\": 2\n },\n \"TRY\": {\n \"decimal_digits\": 2\n },\n \"TTD\": {\n \"decimal_digits\": 2\n },\n \"TWD\": {\n \"decimal_digits\": 2\n },\n \"TZS\": {\n \"decimal_digits\": 2\n },\n \"UAH\": {\n \"decimal_digits\": 2\n },\n \"UGX\": {\n \"decimal_digits\": 0\n },\n \"USD\": {\n \"decimal_digits\": 2\n },\n \"USN\": {\n \"decimal_digits\": 2\n },\n \"UYI\": {\n \"decimal_digits\": 0\n },\n \"UYU\": {\n \"decimal_digits\": 2\n },\n \"UYW\": {\n \"decimal_digits\": 4\n },\n \"UZS\": {\n \"decimal_digits\": 2\n },\n \"VED\": {\n \"decimal_digits\": 2\n },\n \"VES\": {\n \"decimal_digits\": 2\n },\n \"VND\": {\n \"decimal_digits\": 0\n },\n \"VUV\": {\n \"decimal_digits\": 0\n },\n \"WST\": {\n \"decimal_digits\": 2\n },\n \"XAD\": {\n \"decimal_digits\": 2\n },\n \"XAF\": {\n \"decimal_digits\": 0\n },\n \"XAG\": {\n \"decimal_digits\": 0\n },\n \"XAU\": {\n \"decimal_digits\": 0\n },\n \"XBA\": {\n \"decimal_digits\": 0\n },\n \"XBB\": {\n \"decimal_digits\": 0\n },\n \"XBC\": {\n \"decimal_digits\": 0\n },\n \"XBD\": {\n \"decimal_digits\": 0\n },\n \"XCD\": {\n \"decimal_digits\": 2\n },\n \"XCG\": {\n \"decimal_digits\": 2\n },\n \"XDR\": {\n \"decimal_digits\": 0\n },\n \"XOF\": {\n \"decimal_digits\": 0\n },\n \"XPD\": {\n \"decimal_digits\": 0\n },\n \"XPF\": {\n \"decimal_digits\": 0\n },\n \"XPT\": {\n \"decimal_digits\": 0\n },\n \"XSU\": {\n \"decimal_digits\": 0\n },\n \"XTS\": {\n \"decimal_digits\": 0\n },\n \"XUA\": {\n \"decimal_digits\": 0\n },\n \"XXX\": {\n \"decimal_digits\": 0\n },\n \"YER\": {\n \"decimal_digits\": 2\n },\n \"ZAR\": {\n \"decimal_digits\": 2\n },\n \"ZMW\": {\n \"decimal_digits\": 2\n },\n \"ZWG\": {\n \"decimal_digits\": 2\n }\n}"],"mappings":"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AAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AACH;;;ANheA,gBAAgB,mBAAyD;","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -108,7 +108,7 @@ var _Money = class _Money {
|
|
|
108
108
|
* Shows the amount and currency instead of just the class name.
|
|
109
109
|
*/
|
|
110
110
|
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
111
|
-
return `Money {
|
|
111
|
+
return `Money { displayAmount: '${this.displayAmount}', currency: '${this.currency}', amount: '${this.amount}' }`;
|
|
112
112
|
}
|
|
113
113
|
// ============ Arithmetic Operations ============
|
|
114
114
|
/**
|
|
@@ -348,9 +348,6 @@ parseAmount_fn = function(amount) {
|
|
|
348
348
|
_Money_static = new WeakSet();
|
|
349
349
|
formatForDisplay_fn = function(fullAmount, currencyDef) {
|
|
350
350
|
const preferredDecimals = currencyDef.displayDecimals ?? currencyDef.decimalDigits;
|
|
351
|
-
if (preferredDecimals === currencyDef.decimalDigits) {
|
|
352
|
-
return fullAmount;
|
|
353
|
-
}
|
|
354
351
|
const [whole, frac = ""] = fullAmount.split(".");
|
|
355
352
|
if (!frac) return whole;
|
|
356
353
|
let trimmedFrac = frac.replace(/0+$/, "");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/errors.ts","../lib/currency.ts","../lib/money.ts","../lib/exchange-rate-service.ts","../lib/money-converter.ts","../currencymap.json","../lib/index.ts"],"sourcesContent":["/**\n * Custom error types for Money operations.\n * All errors extend built-in Error types for proper instanceof checks.\n */\n\n/**\n * Thrown when attempting operations between different currencies.\n * @example\n * new Money('USD', 10).add(new Money('EUR', 5)) // throws CurrencyMismatchError\n */\nexport class CurrencyMismatchError extends TypeError {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`Cannot operate on ${fromCurrency} and ${toCurrency} - currencies must match`)\n this.name = 'CurrencyMismatchError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, CurrencyMismatchError)\n }\n}\n\n/**\n * Thrown when using an unregistered currency code.\n * @example\n * new Money('FAKE', 10) // throws CurrencyUnknownError\n */\nexport class CurrencyUnknownError extends TypeError {\n readonly currency: string\n\n constructor(currency: string) {\n super(`Unknown currency '${currency}' - register it first with Money.registerCurrency()`)\n this.name = 'CurrencyUnknownError'\n this.currency = currency\n Error.captureStackTrace?.(this, CurrencyUnknownError)\n }\n}\n\n/**\n * Thrown when an amount has more decimal places than the currency allows.\n * @example\n * new Money('USD', '1.234') // throws SubunitError (USD only allows 2 decimals)\n */\nexport class SubunitError extends RangeError {\n readonly currency: string\n readonly maxDecimals: number\n\n constructor(currency: string, maxDecimals: number) {\n super(`${currency} only supports ${maxDecimals} decimal place(s)`)\n this.name = 'SubunitError'\n this.currency = currency\n this.maxDecimals = maxDecimals\n Error.captureStackTrace?.(this, SubunitError)\n }\n}\n\n/**\n * Thrown when an amount cannot be parsed as a valid number.\n * @example\n * new Money('USD', 'abc') // throws AmountError\n */\nexport class AmountError extends TypeError {\n readonly amount: unknown\n\n constructor(amount: unknown) {\n super(`Invalid amount: ${JSON.stringify(amount)}`)\n this.name = 'AmountError'\n this.amount = amount\n Error.captureStackTrace?.(this, AmountError)\n }\n}\n\n/**\n * Thrown when an exchange rate is not available.\n * @example\n * converter.convert(usdMoney, 'XYZ') // throws ExchangeRateError if no USD->XYZ rate\n */\nexport class ExchangeRateError extends Error {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`No exchange rate available from ${fromCurrency} to ${toCurrency}`)\n this.name = 'ExchangeRateError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, ExchangeRateError)\n }\n}\n","/**\n * Currency registry and types.\n * Manages ISO 4217 currency definitions and custom currencies.\n */\n\nexport interface CurrencyDefinition {\n code: string\n decimalDigits: number\n displayDecimals?: number\n}\n\n// Internal registry - mutable for registerCurrency()\nconst currencies: Map<string, CurrencyDefinition> = new Map()\n\n/**\n * Register a new currency or update an existing one.\n * @param code - ISO 4217 currency code (e.g., 'USD', 'EUR', 'BTC')\n * @param decimalDigits - Number of decimal places (e.g., 2 for USD, 8 for BTC)\n * @param displayDecimals - Optional number of decimal places to use for display/formatting (defaults to decimalDigits)\n */\nexport function registerCurrency(code: string, decimalDigits: number, displayDecimals?: number): void {\n currencies.set(code, { code, decimalDigits, displayDecimals })\n}\n\n/**\n * Get a currency definition by code.\n * @returns The currency definition, or undefined if not registered\n */\nexport function getCurrency(code: string): CurrencyDefinition | undefined {\n return currencies.get(code)\n}\n\n/**\n * Check if a currency is registered.\n */\nexport function hasCurrency(code: string): boolean {\n return currencies.has(code)\n}\n\n/**\n * Get all registered currencies, sorted by code.\n */\nexport function getAllCurrencies(): CurrencyDefinition[] {\n return Array.from(currencies.values()).sort((a, b) => a.code.localeCompare(b.code))\n}\n\n/**\n * Load currencies from the legacy currencymap.json format.\n * @param map - Object with currency codes as keys and {decimal_digits: number} as values\n */\nexport function loadCurrencyMap(map: Record<string, { decimal_digits: number }>): void {\n for (const [code, data] of Object.entries(map)) {\n registerCurrency(code, data.decimal_digits)\n }\n}\n\n/**\n * Clear all registered currencies. Useful for testing.\n */\nexport function clearCurrencies(): void {\n currencies.clear()\n}\n","/**\n * Money - An immutable value object for monetary amounts.\n *\n * Design principles:\n * - Immutable: all operations return new instances\n * - Type-safe: currency mismatches are caught at compile time (when possible) and runtime\n * - Precise: uses BigInt internally to avoid floating-point errors\n * - String-based API: amounts are strings to preserve precision in JSON/DB round-trips\n */\n\nimport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n} from './errors.js'\nimport { getCurrency, hasCurrency, type CurrencyDefinition } from './currency.js'\n\n/**\n * Serialized form of a Money object, safe for JSON.\n */\nexport interface MoneyObject<C extends string = string> {\n currency: C\n amount: string\n}\n\n/**\n * Money class - represents a monetary amount in a specific currency.\n *\n * @typeParam C - The currency code type (enables compile-time currency checking)\n *\n * @example\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n * console.log(total.amount) // \"21.59\"\n */\nexport class Money<C extends string = string> {\n readonly currency: C\n readonly amount: string\n readonly displayAmount: string\n\n // Private BigInt storage - stores currency native subunits directly\n readonly #subunits: bigint\n readonly #currencyDef: CurrencyDefinition\n\n /**\n * Create a new Money instance.\n *\n * @param currency - ISO 4217 currency code (must be registered)\n * @param amount - The amount as a number or string\n * @throws {CurrencyUnknownError} If the currency is not registered\n * @throws {AmountError} If the amount is not a valid number\n * @throws {SubunitError} If the amount has more decimals than the currency allows\n */\n constructor(currency: C, amount: number | string) {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n this.currency = currency\n this.#currencyDef = currencyDef\n this.#subunits = this.#parseAmount(amount)\n \n // Pre-calculate string representations for better DX and performance\n this.amount = Money.#formatSubunits(this.#subunits, currencyDef)\n this.displayAmount = Money.#formatForDisplay(this.amount, currencyDef)\n }\n\n /**\n * Parse an amount into native subunits.\n */\n #parseAmount(amount: number | string): bigint {\n const str = typeof amount === 'number' ? String(amount) : amount\n\n const match = str.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!match) {\n throw new AmountError(amount)\n }\n\n const [, sign, whole, frac = ''] = match\n\n if (frac.length > this.#currencyDef.decimalDigits) {\n throw new SubunitError(this.currency, this.#currencyDef.decimalDigits)\n }\n\n const paddedFrac = frac.padEnd(this.#currencyDef.decimalDigits, '0')\n const combined = BigInt(whole + paddedFrac)\n\n return sign === '-' ? -combined : combined\n }\n\n /**\n * Custom console inspection for Node.js.\n * Shows the amount and currency instead of just the class name.\n */\n [Symbol.for('nodejs.util.inspect.custom')](): string {\n return `Money { amount: '${this.displayAmount}', currency: '${this.currency}' }`\n }\n\n /**\n * Format the full amount string for display purposes.\n */\n static #formatForDisplay(fullAmount: string, currencyDef: CurrencyDefinition): string {\n const preferredDecimals = currencyDef.displayDecimals ?? currencyDef.decimalDigits\n\n // If we want full precision anyway, just return it\n if (preferredDecimals === currencyDef.decimalDigits) {\n return fullAmount\n }\n\n // Split into whole and fractional parts\n const [whole, frac = ''] = fullAmount.split('.')\n\n if (!frac) return whole\n\n // Trim trailing zeros\n let trimmedFrac = frac.replace(/0+$/, '')\n\n // Pad back to preferred decimals if needed\n if (trimmedFrac.length < preferredDecimals) {\n trimmedFrac = trimmedFrac.padEnd(preferredDecimals, '0')\n }\n\n // If fractional part is empty and we want 0 decimals, return whole\n if (trimmedFrac === '' && preferredDecimals === 0) {\n return whole\n }\n \n return `${whole}.${trimmedFrac}`\n }\n\n\n\n /**\n * Ensure another Money has the same currency.\n */\n #assertSameCurrency(other: Money<string>): void {\n if (this.currency !== other.currency) {\n throw new CurrencyMismatchError(this.currency, other.currency)\n }\n }\n\n /**\n * Get the internal BigInt value (for operations).\n */\n #getInternalValue(): bigint {\n return this.#subunits\n }\n\n // ============ Arithmetic Operations ============\n\n /**\n * Add another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n add(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits + other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Subtract another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n subtract(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits - other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Multiply by a factor.\n *\n * DESIGN: Rounds immediately after multiplication using banker's rounding\n * (round half-to-even). This prevents the \"split penny problem\".\n */\n multiply(factor: number): Money<C> {\n if (typeof factor !== 'number' || !Number.isFinite(factor)) {\n throw new TypeError(`Factor must be a finite number, got: ${factor}`)\n }\n\n const { value: factorValue, scale } = Money.#parseFactor(factor)\n const product = this.#subunits * factorValue\n const divisor = 10n ** scale\n \n const result = Money.#roundedDivide(product, divisor)\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Helper to parse a number factor into a BigInt and a power-of-10 scale.\n * Uses String() conversion to avoid floating-point epsilon noise,\n * ensuring that 0.545 is treated as exactly 0.545, not 0.54500000000000004.\n */\n static #parseFactor(factor: number): { value: bigint, scale: bigint } {\n const str = String(factor)\n const [base, exponent] = str.split('e')\n \n const baseMatch = base.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!baseMatch) {\n // Fallback for unlikely cases, though String(number) should strictly produce valid formats\n throw new TypeError(`Invalid factor format: ${str}`)\n }\n \n const [, sign, whole, frac = ''] = baseMatch\n const baseValue = BigInt((sign || '') + whole + frac)\n const baseDecimals = frac.length\n \n const exp = exponent ? Number(exponent) : 0\n const netExp = exp - baseDecimals\n \n if (netExp >= 0) {\n return { value: baseValue * 10n ** BigInt(netExp), scale: 0n }\n } else {\n return { value: baseValue, scale: BigInt(-netExp) }\n }\n }\n\n /**\n * Divide with banker's rounding (round half-to-even).\n * IEEE 754-2008 recommended default rounding mode for financial calculations.\n */\n static #roundedDivide(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Allocate this amount proportionally.\n * Handles remainder distribution to avoid losing pennies.\n *\n * @param proportions - Array of proportions (e.g., [1, 1, 1] for three-way split)\n * @returns Array of Money objects that sum to the original amount\n */\n allocate(proportions: number[]): Money<C>[] {\n if (!Array.isArray(proportions) || proportions.length === 0) {\n throw new TypeError('Proportions must be a non-empty array')\n }\n\n for (const p of proportions) {\n if (typeof p !== 'number' || !Number.isFinite(p) || p < 0) {\n throw new TypeError('All proportions must be non-negative finite numbers')\n }\n }\n\n const total = proportions.reduce((sum, p) => sum + p, 0)\n if (total <= 0) {\n throw new TypeError('Sum of proportions must be positive')\n }\n\n const totalSubunits = this.#subunits\n\n // Calculate base allocations\n const allocations: bigint[] = proportions.map((p) => {\n return (totalSubunits * BigInt(Math.round(p * 1000000))) / BigInt(Math.round(total * 1000000))\n })\n\n // Distribute remainder\n let remainder = totalSubunits - allocations.reduce((sum, a) => sum + a, 0n)\n let i = 0\n while (remainder > 0n) {\n allocations[i % allocations.length] += 1n\n remainder -= 1n\n i++\n }\n while (remainder < 0n) {\n allocations[i % allocations.length] -= 1n\n remainder += 1n\n i++\n }\n\n // Convert back to Money objects\n return allocations.map((subunits) => {\n return Money.#createFromSubunits(subunits, this.currency, this.#currencyDef)\n })\n }\n\n // ============ Comparison Operations ============\n\n /**\n * Check if this amount equals another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n equalTo(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits === other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits > other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits < other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits >= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits <= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is zero.\n */\n isZero(): boolean {\n return this.#subunits === 0n\n }\n\n /**\n * Check if this amount is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.#subunits > 0n\n }\n\n /**\n * Check if this amount is negative (less than zero).\n */\n isNegative(): boolean {\n return this.#subunits < 0n\n }\n\n // ============ Serialization ============\n\n /**\n * Convert to a plain object (safe for JSON).\n */\n toJSON(): MoneyObject<C> {\n return {\n currency: this.currency,\n amount: this.amount,\n }\n }\n\n /**\n * Convert to string representation.\n */\n toString(): string {\n return `${this.displayAmount} ${this.currency}`\n }\n\n /**\n * Get the amount as a number (may lose precision for large values).\n * Use with caution - prefer string-based operations.\n */\n toNumber(): number {\n return Number(this.amount)\n }\n\n /**\n * Get the amount in subunits (e.g., cents for USD).\n * Useful for database storage (Stripe-style integer storage).\n */\n toSubunits(): bigint {\n return this.#subunits\n }\n\n // ============ Static Factory Methods ============\n\n /**\n * Create a Money instance from a plain object.\n */\n static fromObject<C extends string>(obj: MoneyObject<C>): Money<C> {\n return new Money(obj.currency, obj.amount)\n }\n\n /**\n * Create a Money instance from subunits (e.g., cents).\n * Useful for loading from database (Stripe-style integer storage).\n */\n static fromSubunits<C extends string>(subunits: bigint | number, currency: C): Money<C> {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n const bigintSubunits = typeof subunits === 'number' ? BigInt(subunits) : subunits\n return Money.#createFromSubunits(bigintSubunits, currency, currencyDef)\n }\n\n /**\n * Compare two Money objects (for use with Array.sort).\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n static compare<C extends string>(a: Money<C>, b: Money<C>): -1 | 0 | 1 {\n if (a.currency !== b.currency) {\n throw new CurrencyMismatchError(a.currency, b.currency)\n }\n const aVal = a.#getInternalValue()\n const bVal = b.#getInternalValue()\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n }\n\n /**\n * Create a zero amount in the specified currency.\n */\n static zero<C extends string>(currency: C): Money<C> {\n return new Money(currency, '0')\n }\n\n /**\n * Internal factory that bypasses parsing.\n */\n static #createFromSubunits<C extends string>(\n subunits: bigint,\n currency: C,\n currencyDef: CurrencyDefinition\n ): Money<C> {\n return new Money(currency, Money.#formatSubunits(subunits, currencyDef))\n }\n\n /**\n * Format subunits to string amount.\n */\n static #formatSubunits(subunits: bigint, currencyDef: CurrencyDefinition): string {\n const decimals = currencyDef.decimalDigits\n const abs = subunits < 0n ? -subunits : subunits\n const isNegative = subunits < 0n\n\n if (decimals === 0) {\n return `${isNegative ? '-' : ''}${abs}`\n }\n\n const multiplier = 10n ** BigInt(decimals)\n const wholePart = abs / multiplier\n const fracPart = abs % multiplier\n\n const sign = isNegative ? '-' : ''\n return `${sign}${wholePart}.${fracPart.toString().padStart(decimals, '0')}`\n }\n}\n","/**\n * Exchange Rate Service - Central authority for currency conversion rates.\n *\n * Design principles:\n * - Rates are stored as strings to preserve precision\n * - Timestamps track when rates were set\n * - Optional source tracking for audit trails\n * - Inverse rates can be auto-generated or explicitly set\n */\n\nexport interface ExchangeRate {\n from: string\n to: string\n rate: string\n timestamp: Date\n source?: string\n}\n\nexport interface RatePair {\n forward: ExchangeRate\n reverse: ExchangeRate\n /** Relative discrepancy between forward and 1/reverse rates */\n discrepancy: number\n}\n\n/**\n * Service for managing exchange rates between currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92, 'ECB')\n * rates.getRate('USD', 'EUR') // { from: 'USD', to: 'EUR', rate: '0.92', ... }\n */\nexport class ExchangeRateService {\n readonly #rates: Map<string, ExchangeRate> = new Map()\n\n /**\n * Create a rate key for storage.\n */\n #key(from: string, to: string): string {\n return `${from}:${to}`\n }\n\n /**\n * Set an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @param rate - Exchange rate (1 unit of 'from' = rate units of 'to')\n * @param source - Optional source identifier (e.g., 'ECB', 'Coinbase')\n * @param autoInverse - If true, automatically create inverse rate (default: true)\n */\n setRate(\n from: string,\n to: string,\n rate: number | string,\n source?: string,\n autoInverse: boolean = true\n ): void {\n const rateStr = typeof rate === 'number' ? rate.toPrecision(15) : rate\n\n this.#rates.set(this.#key(from, to), {\n from,\n to,\n rate: rateStr,\n timestamp: new Date(),\n source,\n })\n\n // Auto-create inverse rate if requested and not already explicitly set\n if (autoInverse) {\n const inverseKey = this.#key(to, from)\n if (!this.#rates.has(inverseKey)) {\n const inverseRate = 1 / Number(rateStr)\n this.#rates.set(inverseKey, {\n from: to,\n to: from,\n rate: inverseRate.toPrecision(15),\n timestamp: new Date(),\n source: source ? `${source} (inverse)` : '(inverse)',\n })\n }\n }\n }\n\n /**\n * Get an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @returns The exchange rate, or undefined if not set\n */\n getRate(from: string, to: string): ExchangeRate | undefined {\n // Same currency = rate of 1\n if (from === to) {\n return {\n from,\n to,\n rate: '1',\n timestamp: new Date(),\n source: '(identity)',\n }\n }\n\n return this.#rates.get(this.#key(from, to))\n }\n\n /**\n * Check if a rate exists.\n */\n hasRate(from: string, to: string): boolean {\n return from === to || this.#rates.has(this.#key(from, to))\n }\n\n /**\n * Remove a rate.\n */\n removeRate(from: string, to: string): boolean {\n return this.#rates.delete(this.#key(from, to))\n }\n\n /**\n * Get both forward and reverse rates, with discrepancy analysis.\n * Useful for detecting rate inconsistencies.\n *\n * @param currencyA - First currency\n * @param currencyB - Second currency\n * @returns Rate pair with discrepancy, or undefined if either rate is missing\n */\n getRatePair(currencyA: string, currencyB: string): RatePair | undefined {\n const forward = this.getRate(currencyA, currencyB)\n const reverse = this.getRate(currencyB, currencyA)\n\n if (!forward || !reverse) {\n return undefined\n }\n\n // Calculate discrepancy: how far is forward * reverse from 1.0?\n const product = Number(forward.rate) * Number(reverse.rate)\n const discrepancy = Math.abs(1 - product)\n\n return { forward, reverse, discrepancy }\n }\n\n /**\n * Get all rates for a specific base currency.\n *\n * @param base - The base currency code\n * @returns Array of rates from this currency\n */\n getRatesFrom(base: string): ExchangeRate[] {\n const rates: ExchangeRate[] = []\n for (const rate of this.#rates.values()) {\n if (rate.from === base) {\n rates.push(rate)\n }\n }\n return rates.sort((a, b) => a.to.localeCompare(b.to))\n }\n\n /**\n * Get all registered rates.\n */\n getAllRates(): ExchangeRate[] {\n return Array.from(this.#rates.values()).sort((a, b) => {\n const fromCompare = a.from.localeCompare(b.from)\n return fromCompare !== 0 ? fromCompare : a.to.localeCompare(b.to)\n })\n }\n\n /**\n * Clear all rates.\n */\n clear(): void {\n this.#rates.clear()\n }\n\n /**\n * Load rates from a simple object.\n *\n * @param rates - Object where keys are \"FROM:TO\" and values are rates\n * @param source - Optional source identifier\n *\n * @example\n * service.loadRates({\n * 'USD:EUR': 0.92,\n * 'USD:GBP': 0.79,\n * }, 'daily-update')\n */\n loadRates(rates: Record<string, number | string>, source?: string): void {\n for (const [key, rate] of Object.entries(rates)) {\n const [from, to] = key.split(':')\n if (from && to) {\n this.setRate(from, to, rate, source, false) // Don't auto-inverse when batch loading\n }\n }\n }\n}\n","/**\n * Money Converter - Safe cross-currency operations.\n *\n * Bridges Money objects with ExchangeRateService to enable:\n * - Currency conversion\n * - Multi-currency arithmetic\n * - Percentage calculations across currencies\n */\n\nimport { Money } from './money.js'\nimport { ExchangeRateService } from './exchange-rate-service.js'\nimport { ExchangeRateError, CurrencyUnknownError } from './errors.js'\nimport { getCurrency } from './currency.js'\n\n/**\n * Converter for performing operations between different currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n *\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(new Money('USD', '100'), 'EUR')\n * console.log(euros.toString()) // \"92.00 EUR\"\n */\nexport class MoneyConverter {\n readonly #rateService: ExchangeRateService\n\n constructor(rateService: ExchangeRateService) {\n this.#rateService = rateService\n }\n\n #bankersRound(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Convert a Money amount to another currency.\n *\n * @param money - The amount to convert\n * @param targetCurrency - The target currency code\n * @returns A new Money in the target currency\n * @throws {ExchangeRateError} If no rate is available\n */\n convert<From extends string, To extends string>(\n money: Money<From>,\n targetCurrency: To\n ): Money<To> {\n if ((money.currency as string) === (targetCurrency as string)) {\n return money as unknown as Money<To>\n }\n\n const currencyDef = getCurrency(targetCurrency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(targetCurrency)\n }\n\n const rate = this.#rateService.getRate(money.currency, targetCurrency)\n if (!rate) {\n throw new ExchangeRateError(money.currency, targetCurrency)\n }\n\n const sourceCurrencyDef = getCurrency(money.currency)!\n const sourceSubunits = money.toSubunits()\n const sourceMultiplier = 10n ** BigInt(sourceCurrencyDef.decimalDigits)\n const targetMultiplier = 10n ** BigInt(currencyDef.decimalDigits)\n\n const RATE_PRECISION = 15n\n const rateMultiplier = 10n ** RATE_PRECISION\n const rateValue = Number(rate.rate)\n const rateBigInt = BigInt(Math.round(rateValue * Number(rateMultiplier)))\n\n const product = sourceSubunits * rateBigInt * targetMultiplier\n const divisor = rateMultiplier * sourceMultiplier\n const targetSubunits = this.#bankersRound(product, divisor)\n\n return Money.fromSubunits(targetSubunits, targetCurrency)\n }\n\n /**\n * Add two Money amounts, converting as needed.\n *\n * @param a - First amount\n * @param b - Second amount\n * @param resultCurrency - Currency for the result (must be one of the input currencies)\n * @returns Sum in the result currency\n */\n add<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.add(bConverted) as Money<R>\n }\n\n /**\n * Subtract two Money amounts, converting as needed.\n *\n * @param a - Amount to subtract from\n * @param b - Amount to subtract\n * @param resultCurrency - Currency for the result\n * @returns Difference in the result currency\n */\n subtract<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.subtract(bConverted) as Money<R>\n }\n\n /**\n * Calculate what percentage one amount is of another.\n * Converts both to the same currency before comparison.\n *\n * @param part - The partial amount\n * @param whole - The whole amount\n * @returns Percentage as a number (e.g., 25 for 25%)\n */\n percentageOf<A extends string, B extends string>(\n part: Money<A>,\n whole: Money<B>\n ): number {\n // Convert both to the 'whole' currency for comparison\n const partConverted = this.convert(part, whole.currency)\n return (partConverted.toNumber() / whole.toNumber()) * 100\n }\n\n /**\n * Sum multiple Money amounts, converting all to a target currency.\n *\n * @param amounts - Array of Money objects (can be different currencies)\n * @param targetCurrency - Currency for the result\n * @returns Total in the target currency\n */\n sum<C extends string>(amounts: Money<string>[], targetCurrency: C): Money<C> {\n let total = Money.zero(targetCurrency)\n\n for (const amount of amounts) {\n const converted = this.convert(amount, targetCurrency)\n total = total.add(converted)\n }\n\n return total\n }\n\n /**\n * Compare two Money amounts across currencies.\n * Returns negative if a < b, zero if equal, positive if a > b.\n *\n * @param a - First amount\n * @param b - Second amount\n * @returns Comparison result\n */\n compare<A extends string, B extends string>(a: Money<A>, b: Money<B>): -1 | 0 | 1 {\n // Convert b to a's currency for comparison\n const bConverted = this.convert(b, a.currency)\n return Money.compare(a, bConverted)\n }\n\n /**\n * Get the exchange rate service (for direct rate access).\n */\n get rateService(): ExchangeRateService {\n return this.#rateService\n }\n}\n","{\n \"AED\": {\n \"decimal_digits\": 2\n },\n \"AFN\": {\n \"decimal_digits\": 2\n },\n \"ALL\": {\n \"decimal_digits\": 2\n },\n \"AMD\": {\n \"decimal_digits\": 2\n },\n \"AOA\": {\n \"decimal_digits\": 2\n },\n \"ARS\": {\n \"decimal_digits\": 2\n },\n \"AUD\": {\n \"decimal_digits\": 2\n },\n \"AWG\": {\n \"decimal_digits\": 2\n },\n \"AZN\": {\n \"decimal_digits\": 2\n },\n \"BAM\": {\n \"decimal_digits\": 2\n },\n \"BBD\": {\n \"decimal_digits\": 2\n },\n \"BDT\": {\n \"decimal_digits\": 2\n },\n \"BHD\": {\n \"decimal_digits\": 3\n },\n \"BIF\": {\n \"decimal_digits\": 0\n },\n \"BMD\": {\n \"decimal_digits\": 2\n },\n \"BND\": {\n \"decimal_digits\": 2\n },\n \"BOB\": {\n \"decimal_digits\": 2\n },\n \"BOV\": {\n \"decimal_digits\": 2\n },\n \"BRL\": {\n \"decimal_digits\": 2\n },\n \"BSD\": {\n \"decimal_digits\": 2\n },\n \"BTN\": {\n \"decimal_digits\": 2\n },\n \"BWP\": {\n \"decimal_digits\": 2\n },\n \"BYN\": {\n \"decimal_digits\": 2\n },\n \"BZD\": {\n \"decimal_digits\": 2\n },\n \"CAD\": {\n \"decimal_digits\": 2\n },\n \"CDF\": {\n \"decimal_digits\": 2\n },\n \"CHE\": {\n \"decimal_digits\": 2\n },\n \"CHF\": {\n \"decimal_digits\": 2\n },\n \"CHW\": {\n \"decimal_digits\": 2\n },\n \"CLF\": {\n \"decimal_digits\": 4\n },\n \"CLP\": {\n \"decimal_digits\": 0\n },\n \"CNY\": {\n \"decimal_digits\": 2\n },\n \"COP\": {\n \"decimal_digits\": 2\n },\n \"COU\": {\n \"decimal_digits\": 2\n },\n \"CRC\": {\n \"decimal_digits\": 2\n },\n \"CUP\": {\n \"decimal_digits\": 2\n },\n \"CVE\": {\n \"decimal_digits\": 2\n },\n \"CZK\": {\n \"decimal_digits\": 2\n },\n \"DJF\": {\n \"decimal_digits\": 0\n },\n \"DKK\": {\n \"decimal_digits\": 2\n },\n \"DOP\": {\n \"decimal_digits\": 2\n },\n \"DZD\": {\n \"decimal_digits\": 2\n },\n \"EGP\": {\n \"decimal_digits\": 2\n },\n \"ERN\": {\n \"decimal_digits\": 2\n },\n \"ETB\": {\n \"decimal_digits\": 2\n },\n \"EUR\": {\n \"decimal_digits\": 2\n },\n \"FJD\": {\n \"decimal_digits\": 2\n },\n \"FKP\": {\n \"decimal_digits\": 2\n },\n \"GBP\": {\n \"decimal_digits\": 2\n },\n \"GEL\": {\n \"decimal_digits\": 2\n },\n \"GHS\": {\n \"decimal_digits\": 2\n },\n \"GIP\": {\n \"decimal_digits\": 2\n },\n \"GMD\": {\n \"decimal_digits\": 2\n },\n \"GNF\": {\n \"decimal_digits\": 0\n },\n \"GTQ\": {\n \"decimal_digits\": 2\n },\n \"GYD\": {\n \"decimal_digits\": 2\n },\n \"HKD\": {\n \"decimal_digits\": 2\n },\n \"HNL\": {\n \"decimal_digits\": 2\n },\n \"HTG\": {\n \"decimal_digits\": 2\n },\n \"HUF\": {\n \"decimal_digits\": 2\n },\n \"IDR\": {\n \"decimal_digits\": 2\n },\n \"ILS\": {\n \"decimal_digits\": 2\n },\n \"INR\": {\n \"decimal_digits\": 2\n },\n \"IQD\": {\n \"decimal_digits\": 3\n },\n \"IRR\": {\n \"decimal_digits\": 2\n },\n \"ISK\": {\n \"decimal_digits\": 0\n },\n \"JMD\": {\n \"decimal_digits\": 2\n },\n \"JOD\": {\n \"decimal_digits\": 3\n },\n \"JPY\": {\n \"decimal_digits\": 0\n },\n \"KES\": {\n \"decimal_digits\": 2\n },\n \"KGS\": {\n \"decimal_digits\": 2\n },\n \"KHR\": {\n \"decimal_digits\": 2\n },\n \"KMF\": {\n \"decimal_digits\": 0\n },\n \"KPW\": {\n \"decimal_digits\": 2\n },\n \"KRW\": {\n \"decimal_digits\": 0\n },\n \"KWD\": {\n \"decimal_digits\": 3\n },\n \"KYD\": {\n \"decimal_digits\": 2\n },\n \"KZT\": {\n \"decimal_digits\": 2\n },\n \"LAK\": {\n \"decimal_digits\": 2\n },\n \"LBP\": {\n \"decimal_digits\": 2\n },\n \"LKR\": {\n \"decimal_digits\": 2\n },\n \"LRD\": {\n \"decimal_digits\": 2\n },\n \"LSL\": {\n \"decimal_digits\": 2\n },\n \"LYD\": {\n \"decimal_digits\": 3\n },\n \"MAD\": {\n \"decimal_digits\": 2\n },\n \"MDL\": {\n \"decimal_digits\": 2\n },\n \"MGA\": {\n \"decimal_digits\": 2\n },\n \"MKD\": {\n \"decimal_digits\": 2\n },\n \"MMK\": {\n \"decimal_digits\": 2\n },\n \"MNT\": {\n \"decimal_digits\": 2\n },\n \"MOP\": {\n \"decimal_digits\": 2\n },\n \"MRU\": {\n \"decimal_digits\": 2\n },\n \"MUR\": {\n \"decimal_digits\": 2\n },\n \"MVR\": {\n \"decimal_digits\": 2\n },\n \"MWK\": {\n \"decimal_digits\": 2\n },\n \"MXN\": {\n \"decimal_digits\": 2\n },\n \"MXV\": {\n \"decimal_digits\": 2\n },\n \"MYR\": {\n \"decimal_digits\": 2\n },\n \"MZN\": {\n \"decimal_digits\": 2\n },\n \"NAD\": {\n \"decimal_digits\": 2\n },\n \"NGN\": {\n \"decimal_digits\": 2\n },\n \"NIO\": {\n \"decimal_digits\": 2\n },\n \"NOK\": {\n \"decimal_digits\": 2\n },\n \"NPR\": {\n \"decimal_digits\": 2\n },\n \"NZD\": {\n \"decimal_digits\": 2\n },\n \"OMR\": {\n \"decimal_digits\": 3\n },\n \"PAB\": {\n \"decimal_digits\": 2\n },\n \"PEN\": {\n \"decimal_digits\": 2\n },\n \"PGK\": {\n \"decimal_digits\": 2\n },\n \"PHP\": {\n \"decimal_digits\": 2\n },\n \"PKR\": {\n \"decimal_digits\": 2\n },\n \"PLN\": {\n \"decimal_digits\": 2\n },\n \"PYG\": {\n \"decimal_digits\": 0\n },\n \"QAR\": {\n \"decimal_digits\": 2\n },\n \"RON\": {\n \"decimal_digits\": 2\n },\n \"RSD\": {\n \"decimal_digits\": 2\n },\n \"RUB\": {\n \"decimal_digits\": 2\n },\n \"RWF\": {\n \"decimal_digits\": 0\n },\n \"SAR\": {\n \"decimal_digits\": 2\n },\n \"SBD\": {\n \"decimal_digits\": 2\n },\n \"SCR\": {\n \"decimal_digits\": 2\n },\n \"SDG\": {\n \"decimal_digits\": 2\n },\n \"SEK\": {\n \"decimal_digits\": 2\n },\n \"SGD\": {\n \"decimal_digits\": 2\n },\n \"SHP\": {\n \"decimal_digits\": 2\n },\n \"SLE\": {\n \"decimal_digits\": 2\n },\n \"SOS\": {\n \"decimal_digits\": 2\n },\n \"SRD\": {\n \"decimal_digits\": 2\n },\n \"SSP\": {\n \"decimal_digits\": 2\n },\n \"STN\": {\n \"decimal_digits\": 2\n },\n \"SVC\": {\n \"decimal_digits\": 2\n },\n \"SYP\": {\n \"decimal_digits\": 2\n },\n \"SZL\": {\n \"decimal_digits\": 2\n },\n \"THB\": {\n \"decimal_digits\": 2\n },\n \"TJS\": {\n \"decimal_digits\": 2\n },\n \"TMT\": {\n \"decimal_digits\": 2\n },\n \"TND\": {\n \"decimal_digits\": 3\n },\n \"TOP\": {\n \"decimal_digits\": 2\n },\n \"TRY\": {\n \"decimal_digits\": 2\n },\n \"TTD\": {\n \"decimal_digits\": 2\n },\n \"TWD\": {\n \"decimal_digits\": 2\n },\n \"TZS\": {\n \"decimal_digits\": 2\n },\n \"UAH\": {\n \"decimal_digits\": 2\n },\n \"UGX\": {\n \"decimal_digits\": 0\n },\n \"USD\": {\n \"decimal_digits\": 2\n },\n \"USN\": {\n \"decimal_digits\": 2\n },\n \"UYI\": {\n \"decimal_digits\": 0\n },\n \"UYU\": {\n \"decimal_digits\": 2\n },\n \"UYW\": {\n \"decimal_digits\": 4\n },\n \"UZS\": {\n \"decimal_digits\": 2\n },\n \"VED\": {\n \"decimal_digits\": 2\n },\n \"VES\": {\n \"decimal_digits\": 2\n },\n \"VND\": {\n \"decimal_digits\": 0\n },\n \"VUV\": {\n \"decimal_digits\": 0\n },\n \"WST\": {\n \"decimal_digits\": 2\n },\n \"XAD\": {\n \"decimal_digits\": 2\n },\n \"XAF\": {\n \"decimal_digits\": 0\n },\n \"XAG\": {\n \"decimal_digits\": 0\n },\n \"XAU\": {\n \"decimal_digits\": 0\n },\n \"XBA\": {\n \"decimal_digits\": 0\n },\n \"XBB\": {\n \"decimal_digits\": 0\n },\n \"XBC\": {\n \"decimal_digits\": 0\n },\n \"XBD\": {\n \"decimal_digits\": 0\n },\n \"XCD\": {\n \"decimal_digits\": 2\n },\n \"XCG\": {\n \"decimal_digits\": 2\n },\n \"XDR\": {\n \"decimal_digits\": 0\n },\n \"XOF\": {\n \"decimal_digits\": 0\n },\n \"XPD\": {\n \"decimal_digits\": 0\n },\n \"XPF\": {\n \"decimal_digits\": 0\n },\n \"XPT\": {\n \"decimal_digits\": 0\n },\n \"XSU\": {\n \"decimal_digits\": 0\n },\n \"XTS\": {\n \"decimal_digits\": 0\n },\n \"XUA\": {\n \"decimal_digits\": 0\n },\n \"XXX\": {\n \"decimal_digits\": 0\n },\n \"YER\": {\n \"decimal_digits\": 2\n },\n \"ZAR\": {\n \"decimal_digits\": 2\n },\n \"ZMW\": {\n \"decimal_digits\": 2\n },\n \"ZWG\": {\n \"decimal_digits\": 2\n }\n}","/**\n * subunit-money - A type-safe value object for monetary amounts\n *\n * @example\n * import { Money, ExchangeRateService, MoneyConverter } from '@cbrunnkvist/subunit-money'\n *\n * // Basic usage\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n *\n * // Currency conversion\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(total, 'EUR')\n */\n\n// Core classes\nexport { Money, type MoneyObject } from './money.js'\nexport { ExchangeRateService, type ExchangeRate, type RatePair } from './exchange-rate-service.js'\nexport { MoneyConverter } from './money-converter.js'\n\n// Error types\nexport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n ExchangeRateError,\n} from './errors.js'\n\n// Currency utilities\nexport {\n registerCurrency,\n getCurrency,\n hasCurrency,\n getAllCurrencies,\n loadCurrencyMap,\n clearCurrencies,\n type CurrencyDefinition,\n} from './currency.js'\n\n// Auto-load default currencies\n// The currencymap.json file is the official ISO 4217 currency list (List One) as of 2026-01-01,\n// sourced from SIX Financial Information AG (the ISO 4217 Maintenance Agency).\n//\n// To regenerate:\n// 1. Download list-one.xml from https://www.six-group.com/en/products-services/financial-information/data-standards.html\n// 2. Convert with: yq -p xml -o json '.' list-one.xml | jq '.ISO_4217.CcyTbl.CcyNtry | map(select(.Ccy) | {(.Ccy): {decimal_digits: (if (.CcyMnrUnts == \"N.A.\" or .CcyMnrUnts == null) then 0 else (.CcyMnrUnts | tonumber) end)}}) | add | to_entries | sort_by(.key) | from_entries' > currencymap.json\n//\n// Note: This excludes historical currencies, supranational funds, and precious metals,\n// keeping only active national and regional currencies for practical use.\nimport { loadCurrencyMap } from './currency.js'\nimport currencyMap from '../currencymap.json'\nloadCurrencyMap(currencyMap as Record<string, { decimal_digits: number }>)\n"],"mappings":"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,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AACH;;;ACheA,gBAAgB,mBAAyD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../lib/errors.ts","../lib/currency.ts","../lib/money.ts","../lib/exchange-rate-service.ts","../lib/money-converter.ts","../currencymap.json","../lib/index.ts"],"sourcesContent":["/**\n * Custom error types for Money operations.\n * All errors extend built-in Error types for proper instanceof checks.\n */\n\n/**\n * Thrown when attempting operations between different currencies.\n * @example\n * new Money('USD', 10).add(new Money('EUR', 5)) // throws CurrencyMismatchError\n */\nexport class CurrencyMismatchError extends TypeError {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`Cannot operate on ${fromCurrency} and ${toCurrency} - currencies must match`)\n this.name = 'CurrencyMismatchError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, CurrencyMismatchError)\n }\n}\n\n/**\n * Thrown when using an unregistered currency code.\n * @example\n * new Money('FAKE', 10) // throws CurrencyUnknownError\n */\nexport class CurrencyUnknownError extends TypeError {\n readonly currency: string\n\n constructor(currency: string) {\n super(`Unknown currency '${currency}' - register it first with Money.registerCurrency()`)\n this.name = 'CurrencyUnknownError'\n this.currency = currency\n Error.captureStackTrace?.(this, CurrencyUnknownError)\n }\n}\n\n/**\n * Thrown when an amount has more decimal places than the currency allows.\n * @example\n * new Money('USD', '1.234') // throws SubunitError (USD only allows 2 decimals)\n */\nexport class SubunitError extends RangeError {\n readonly currency: string\n readonly maxDecimals: number\n\n constructor(currency: string, maxDecimals: number) {\n super(`${currency} only supports ${maxDecimals} decimal place(s)`)\n this.name = 'SubunitError'\n this.currency = currency\n this.maxDecimals = maxDecimals\n Error.captureStackTrace?.(this, SubunitError)\n }\n}\n\n/**\n * Thrown when an amount cannot be parsed as a valid number.\n * @example\n * new Money('USD', 'abc') // throws AmountError\n */\nexport class AmountError extends TypeError {\n readonly amount: unknown\n\n constructor(amount: unknown) {\n super(`Invalid amount: ${JSON.stringify(amount)}`)\n this.name = 'AmountError'\n this.amount = amount\n Error.captureStackTrace?.(this, AmountError)\n }\n}\n\n/**\n * Thrown when an exchange rate is not available.\n * @example\n * converter.convert(usdMoney, 'XYZ') // throws ExchangeRateError if no USD->XYZ rate\n */\nexport class ExchangeRateError extends Error {\n readonly fromCurrency: string\n readonly toCurrency: string\n\n constructor(fromCurrency: string, toCurrency: string) {\n super(`No exchange rate available from ${fromCurrency} to ${toCurrency}`)\n this.name = 'ExchangeRateError'\n this.fromCurrency = fromCurrency\n this.toCurrency = toCurrency\n Error.captureStackTrace?.(this, ExchangeRateError)\n }\n}\n","/**\n * Currency registry and types.\n * Manages ISO 4217 currency definitions and custom currencies.\n */\n\nexport interface CurrencyDefinition {\n code: string\n decimalDigits: number\n displayDecimals?: number\n}\n\n// Internal registry - mutable for registerCurrency()\nconst currencies: Map<string, CurrencyDefinition> = new Map()\n\n/**\n * Register a new currency or update an existing one.\n * @param code - ISO 4217 currency code (e.g., 'USD', 'EUR', 'BTC')\n * @param decimalDigits - Number of decimal places (e.g., 2 for USD, 8 for BTC)\n * @param displayDecimals - Optional number of decimal places to use for display/formatting (defaults to decimalDigits)\n */\nexport function registerCurrency(code: string, decimalDigits: number, displayDecimals?: number): void {\n currencies.set(code, { code, decimalDigits, displayDecimals })\n}\n\n/**\n * Get a currency definition by code.\n * @returns The currency definition, or undefined if not registered\n */\nexport function getCurrency(code: string): CurrencyDefinition | undefined {\n return currencies.get(code)\n}\n\n/**\n * Check if a currency is registered.\n */\nexport function hasCurrency(code: string): boolean {\n return currencies.has(code)\n}\n\n/**\n * Get all registered currencies, sorted by code.\n */\nexport function getAllCurrencies(): CurrencyDefinition[] {\n return Array.from(currencies.values()).sort((a, b) => a.code.localeCompare(b.code))\n}\n\n/**\n * Load currencies from the legacy currencymap.json format.\n * @param map - Object with currency codes as keys and {decimal_digits: number} as values\n */\nexport function loadCurrencyMap(map: Record<string, { decimal_digits: number }>): void {\n for (const [code, data] of Object.entries(map)) {\n registerCurrency(code, data.decimal_digits)\n }\n}\n\n/**\n * Clear all registered currencies. Useful for testing.\n */\nexport function clearCurrencies(): void {\n currencies.clear()\n}\n","/**\n * Money - An immutable value object for monetary amounts.\n *\n * Design principles:\n * - Immutable: all operations return new instances\n * - Type-safe: currency mismatches are caught at compile time (when possible) and runtime\n * - Precise: uses BigInt internally to avoid floating-point errors\n * - String-based API: amounts are strings to preserve precision in JSON/DB round-trips\n */\n\nimport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n} from './errors.js'\nimport { getCurrency, hasCurrency, type CurrencyDefinition } from './currency.js'\n\n/**\n * Serialized form of a Money object, safe for JSON.\n */\nexport interface MoneyObject<C extends string = string> {\n currency: C\n amount: string\n}\n\n/**\n * Money class - represents a monetary amount in a specific currency.\n *\n * @typeParam C - The currency code type (enables compile-time currency checking)\n *\n * @example\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n * console.log(total.amount) // \"21.59\"\n */\nexport class Money<C extends string = string> {\n readonly currency: C\n readonly amount: string\n readonly displayAmount: string\n\n // Private BigInt storage - stores currency native subunits directly\n readonly #subunits: bigint\n readonly #currencyDef: CurrencyDefinition\n\n /**\n * Create a new Money instance.\n *\n * @param currency - ISO 4217 currency code (must be registered)\n * @param amount - The amount as a number or string\n * @throws {CurrencyUnknownError} If the currency is not registered\n * @throws {AmountError} If the amount is not a valid number\n * @throws {SubunitError} If the amount has more decimals than the currency allows\n */\n constructor(currency: C, amount: number | string) {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n this.currency = currency\n this.#currencyDef = currencyDef\n this.#subunits = this.#parseAmount(amount)\n \n // Pre-calculate string representations for better DX and performance\n this.amount = Money.#formatSubunits(this.#subunits, currencyDef)\n this.displayAmount = Money.#formatForDisplay(this.amount, currencyDef)\n }\n\n /**\n * Parse an amount into native subunits.\n */\n #parseAmount(amount: number | string): bigint {\n const str = typeof amount === 'number' ? String(amount) : amount\n\n const match = str.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!match) {\n throw new AmountError(amount)\n }\n\n const [, sign, whole, frac = ''] = match\n\n if (frac.length > this.#currencyDef.decimalDigits) {\n throw new SubunitError(this.currency, this.#currencyDef.decimalDigits)\n }\n\n const paddedFrac = frac.padEnd(this.#currencyDef.decimalDigits, '0')\n const combined = BigInt(whole + paddedFrac)\n\n return sign === '-' ? -combined : combined\n }\n\n /**\n * Custom console inspection for Node.js.\n * Shows the amount and currency instead of just the class name.\n */\n [Symbol.for('nodejs.util.inspect.custom')](): string {\n return `Money { displayAmount: '${this.displayAmount}', currency: '${this.currency}', amount: '${this.amount}' }`\n }\n\n /**\n * Format the full amount string for display purposes.\n */\n static #formatForDisplay(fullAmount: string, currencyDef: CurrencyDefinition): string {\n const preferredDecimals = currencyDef.displayDecimals ?? currencyDef.decimalDigits\n\n // Split into whole and fractional parts\n const [whole, frac = ''] = fullAmount.split('.')\n\n if (!frac) return whole\n\n // Trim trailing zeros\n let trimmedFrac = frac.replace(/0+$/, '')\n\n // Pad back to preferred decimals if needed\n if (trimmedFrac.length < preferredDecimals) {\n trimmedFrac = trimmedFrac.padEnd(preferredDecimals, '0')\n }\n\n // If fractional part is empty and we want 0 decimals, return whole\n if (trimmedFrac === '' && preferredDecimals === 0) {\n return whole\n }\n \n return `${whole}.${trimmedFrac}`\n }\n\n\n\n /**\n * Ensure another Money has the same currency.\n */\n #assertSameCurrency(other: Money<string>): void {\n if (this.currency !== other.currency) {\n throw new CurrencyMismatchError(this.currency, other.currency)\n }\n }\n\n /**\n * Get the internal BigInt value (for operations).\n */\n #getInternalValue(): bigint {\n return this.#subunits\n }\n\n // ============ Arithmetic Operations ============\n\n /**\n * Add another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n add(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits + other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Subtract another Money amount.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n subtract(other: Money<C>): Money<C> {\n this.#assertSameCurrency(other)\n const result = this.#subunits - other.#getInternalValue()\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Multiply by a factor.\n *\n * DESIGN: Rounds immediately after multiplication using banker's rounding\n * (round half-to-even). This prevents the \"split penny problem\".\n */\n multiply(factor: number): Money<C> {\n if (typeof factor !== 'number' || !Number.isFinite(factor)) {\n throw new TypeError(`Factor must be a finite number, got: ${factor}`)\n }\n\n const { value: factorValue, scale } = Money.#parseFactor(factor)\n const product = this.#subunits * factorValue\n const divisor = 10n ** scale\n \n const result = Money.#roundedDivide(product, divisor)\n return Money.#createFromSubunits(result, this.currency, this.#currencyDef)\n }\n\n /**\n * Helper to parse a number factor into a BigInt and a power-of-10 scale.\n * Uses String() conversion to avoid floating-point epsilon noise,\n * ensuring that 0.545 is treated as exactly 0.545, not 0.54500000000000004.\n */\n static #parseFactor(factor: number): { value: bigint, scale: bigint } {\n const str = String(factor)\n const [base, exponent] = str.split('e')\n \n const baseMatch = base.match(/^(-)?(\\d+)(?:\\.(\\d+))?$/)\n if (!baseMatch) {\n // Fallback for unlikely cases, though String(number) should strictly produce valid formats\n throw new TypeError(`Invalid factor format: ${str}`)\n }\n \n const [, sign, whole, frac = ''] = baseMatch\n const baseValue = BigInt((sign || '') + whole + frac)\n const baseDecimals = frac.length\n \n const exp = exponent ? Number(exponent) : 0\n const netExp = exp - baseDecimals\n \n if (netExp >= 0) {\n return { value: baseValue * 10n ** BigInt(netExp), scale: 0n }\n } else {\n return { value: baseValue, scale: BigInt(-netExp) }\n }\n }\n\n /**\n * Divide with banker's rounding (round half-to-even).\n * IEEE 754-2008 recommended default rounding mode for financial calculations.\n */\n static #roundedDivide(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Allocate this amount proportionally.\n * Handles remainder distribution to avoid losing pennies.\n *\n * @param proportions - Array of proportions (e.g., [1, 1, 1] for three-way split)\n * @returns Array of Money objects that sum to the original amount\n */\n allocate(proportions: number[]): Money<C>[] {\n if (!Array.isArray(proportions) || proportions.length === 0) {\n throw new TypeError('Proportions must be a non-empty array')\n }\n\n for (const p of proportions) {\n if (typeof p !== 'number' || !Number.isFinite(p) || p < 0) {\n throw new TypeError('All proportions must be non-negative finite numbers')\n }\n }\n\n const total = proportions.reduce((sum, p) => sum + p, 0)\n if (total <= 0) {\n throw new TypeError('Sum of proportions must be positive')\n }\n\n const totalSubunits = this.#subunits\n\n // Calculate base allocations\n const allocations: bigint[] = proportions.map((p) => {\n return (totalSubunits * BigInt(Math.round(p * 1000000))) / BigInt(Math.round(total * 1000000))\n })\n\n // Distribute remainder\n let remainder = totalSubunits - allocations.reduce((sum, a) => sum + a, 0n)\n let i = 0\n while (remainder > 0n) {\n allocations[i % allocations.length] += 1n\n remainder -= 1n\n i++\n }\n while (remainder < 0n) {\n allocations[i % allocations.length] -= 1n\n remainder += 1n\n i++\n }\n\n // Convert back to Money objects\n return allocations.map((subunits) => {\n return Money.#createFromSubunits(subunits, this.currency, this.#currencyDef)\n })\n }\n\n // ============ Comparison Operations ============\n\n /**\n * Check if this amount equals another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n equalTo(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits === other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits > other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThan(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits < other.#getInternalValue()\n }\n\n /**\n * Check if this amount is greater than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n greaterThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits >= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is less than or equal to another.\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n lessThanOrEqual(other: Money<C>): boolean {\n this.#assertSameCurrency(other)\n return this.#subunits <= other.#getInternalValue()\n }\n\n /**\n * Check if this amount is zero.\n */\n isZero(): boolean {\n return this.#subunits === 0n\n }\n\n /**\n * Check if this amount is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.#subunits > 0n\n }\n\n /**\n * Check if this amount is negative (less than zero).\n */\n isNegative(): boolean {\n return this.#subunits < 0n\n }\n\n // ============ Serialization ============\n\n /**\n * Convert to a plain object (safe for JSON).\n */\n toJSON(): MoneyObject<C> {\n return {\n currency: this.currency,\n amount: this.amount,\n }\n }\n\n /**\n * Convert to string representation.\n */\n toString(): string {\n return `${this.displayAmount} ${this.currency}`\n }\n\n /**\n * Get the amount as a number (may lose precision for large values).\n * Use with caution - prefer string-based operations.\n */\n toNumber(): number {\n return Number(this.amount)\n }\n\n /**\n * Get the amount in subunits (e.g., cents for USD).\n * Useful for database storage (Stripe-style integer storage).\n */\n toSubunits(): bigint {\n return this.#subunits\n }\n\n // ============ Static Factory Methods ============\n\n /**\n * Create a Money instance from a plain object.\n */\n static fromObject<C extends string>(obj: MoneyObject<C>): Money<C> {\n return new Money(obj.currency, obj.amount)\n }\n\n /**\n * Create a Money instance from subunits (e.g., cents).\n * Useful for loading from database (Stripe-style integer storage).\n */\n static fromSubunits<C extends string>(subunits: bigint | number, currency: C): Money<C> {\n const currencyDef = getCurrency(currency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(currency)\n }\n\n const bigintSubunits = typeof subunits === 'number' ? BigInt(subunits) : subunits\n return Money.#createFromSubunits(bigintSubunits, currency, currencyDef)\n }\n\n /**\n * Compare two Money objects (for use with Array.sort).\n * @throws {CurrencyMismatchError} If currencies don't match\n */\n static compare<C extends string>(a: Money<C>, b: Money<C>): -1 | 0 | 1 {\n if (a.currency !== b.currency) {\n throw new CurrencyMismatchError(a.currency, b.currency)\n }\n const aVal = a.#getInternalValue()\n const bVal = b.#getInternalValue()\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n }\n\n /**\n * Create a zero amount in the specified currency.\n */\n static zero<C extends string>(currency: C): Money<C> {\n return new Money(currency, '0')\n }\n\n /**\n * Internal factory that bypasses parsing.\n */\n static #createFromSubunits<C extends string>(\n subunits: bigint,\n currency: C,\n currencyDef: CurrencyDefinition\n ): Money<C> {\n return new Money(currency, Money.#formatSubunits(subunits, currencyDef))\n }\n\n /**\n * Format subunits to string amount.\n */\n static #formatSubunits(subunits: bigint, currencyDef: CurrencyDefinition): string {\n const decimals = currencyDef.decimalDigits\n const abs = subunits < 0n ? -subunits : subunits\n const isNegative = subunits < 0n\n\n if (decimals === 0) {\n return `${isNegative ? '-' : ''}${abs}`\n }\n\n const multiplier = 10n ** BigInt(decimals)\n const wholePart = abs / multiplier\n const fracPart = abs % multiplier\n\n const sign = isNegative ? '-' : ''\n return `${sign}${wholePart}.${fracPart.toString().padStart(decimals, '0')}`\n }\n}\n","/**\n * Exchange Rate Service - Central authority for currency conversion rates.\n *\n * Design principles:\n * - Rates are stored as strings to preserve precision\n * - Timestamps track when rates were set\n * - Optional source tracking for audit trails\n * - Inverse rates can be auto-generated or explicitly set\n */\n\nexport interface ExchangeRate {\n from: string\n to: string\n rate: string\n timestamp: Date\n source?: string\n}\n\nexport interface RatePair {\n forward: ExchangeRate\n reverse: ExchangeRate\n /** Relative discrepancy between forward and 1/reverse rates */\n discrepancy: number\n}\n\n/**\n * Service for managing exchange rates between currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92, 'ECB')\n * rates.getRate('USD', 'EUR') // { from: 'USD', to: 'EUR', rate: '0.92', ... }\n */\nexport class ExchangeRateService {\n readonly #rates: Map<string, ExchangeRate> = new Map()\n\n /**\n * Create a rate key for storage.\n */\n #key(from: string, to: string): string {\n return `${from}:${to}`\n }\n\n /**\n * Set an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @param rate - Exchange rate (1 unit of 'from' = rate units of 'to')\n * @param source - Optional source identifier (e.g., 'ECB', 'Coinbase')\n * @param autoInverse - If true, automatically create inverse rate (default: true)\n */\n setRate(\n from: string,\n to: string,\n rate: number | string,\n source?: string,\n autoInverse: boolean = true\n ): void {\n const rateStr = typeof rate === 'number' ? rate.toPrecision(15) : rate\n\n this.#rates.set(this.#key(from, to), {\n from,\n to,\n rate: rateStr,\n timestamp: new Date(),\n source,\n })\n\n // Auto-create inverse rate if requested and not already explicitly set\n if (autoInverse) {\n const inverseKey = this.#key(to, from)\n if (!this.#rates.has(inverseKey)) {\n const inverseRate = 1 / Number(rateStr)\n this.#rates.set(inverseKey, {\n from: to,\n to: from,\n rate: inverseRate.toPrecision(15),\n timestamp: new Date(),\n source: source ? `${source} (inverse)` : '(inverse)',\n })\n }\n }\n }\n\n /**\n * Get an exchange rate.\n *\n * @param from - Source currency code\n * @param to - Target currency code\n * @returns The exchange rate, or undefined if not set\n */\n getRate(from: string, to: string): ExchangeRate | undefined {\n // Same currency = rate of 1\n if (from === to) {\n return {\n from,\n to,\n rate: '1',\n timestamp: new Date(),\n source: '(identity)',\n }\n }\n\n return this.#rates.get(this.#key(from, to))\n }\n\n /**\n * Check if a rate exists.\n */\n hasRate(from: string, to: string): boolean {\n return from === to || this.#rates.has(this.#key(from, to))\n }\n\n /**\n * Remove a rate.\n */\n removeRate(from: string, to: string): boolean {\n return this.#rates.delete(this.#key(from, to))\n }\n\n /**\n * Get both forward and reverse rates, with discrepancy analysis.\n * Useful for detecting rate inconsistencies.\n *\n * @param currencyA - First currency\n * @param currencyB - Second currency\n * @returns Rate pair with discrepancy, or undefined if either rate is missing\n */\n getRatePair(currencyA: string, currencyB: string): RatePair | undefined {\n const forward = this.getRate(currencyA, currencyB)\n const reverse = this.getRate(currencyB, currencyA)\n\n if (!forward || !reverse) {\n return undefined\n }\n\n // Calculate discrepancy: how far is forward * reverse from 1.0?\n const product = Number(forward.rate) * Number(reverse.rate)\n const discrepancy = Math.abs(1 - product)\n\n return { forward, reverse, discrepancy }\n }\n\n /**\n * Get all rates for a specific base currency.\n *\n * @param base - The base currency code\n * @returns Array of rates from this currency\n */\n getRatesFrom(base: string): ExchangeRate[] {\n const rates: ExchangeRate[] = []\n for (const rate of this.#rates.values()) {\n if (rate.from === base) {\n rates.push(rate)\n }\n }\n return rates.sort((a, b) => a.to.localeCompare(b.to))\n }\n\n /**\n * Get all registered rates.\n */\n getAllRates(): ExchangeRate[] {\n return Array.from(this.#rates.values()).sort((a, b) => {\n const fromCompare = a.from.localeCompare(b.from)\n return fromCompare !== 0 ? fromCompare : a.to.localeCompare(b.to)\n })\n }\n\n /**\n * Clear all rates.\n */\n clear(): void {\n this.#rates.clear()\n }\n\n /**\n * Load rates from a simple object.\n *\n * @param rates - Object where keys are \"FROM:TO\" and values are rates\n * @param source - Optional source identifier\n *\n * @example\n * service.loadRates({\n * 'USD:EUR': 0.92,\n * 'USD:GBP': 0.79,\n * }, 'daily-update')\n */\n loadRates(rates: Record<string, number | string>, source?: string): void {\n for (const [key, rate] of Object.entries(rates)) {\n const [from, to] = key.split(':')\n if (from && to) {\n this.setRate(from, to, rate, source, false) // Don't auto-inverse when batch loading\n }\n }\n }\n}\n","/**\n * Money Converter - Safe cross-currency operations.\n *\n * Bridges Money objects with ExchangeRateService to enable:\n * - Currency conversion\n * - Multi-currency arithmetic\n * - Percentage calculations across currencies\n */\n\nimport { Money } from './money.js'\nimport { ExchangeRateService } from './exchange-rate-service.js'\nimport { ExchangeRateError, CurrencyUnknownError } from './errors.js'\nimport { getCurrency } from './currency.js'\n\n/**\n * Converter for performing operations between different currencies.\n *\n * @example\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n *\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(new Money('USD', '100'), 'EUR')\n * console.log(euros.toString()) // \"92.00 EUR\"\n */\nexport class MoneyConverter {\n readonly #rateService: ExchangeRateService\n\n constructor(rateService: ExchangeRateService) {\n this.#rateService = rateService\n }\n\n #bankersRound(numerator: bigint, denominator: bigint): bigint {\n if (denominator === 1n) return numerator\n\n const quotient = numerator / denominator\n const remainder = numerator % denominator\n if (remainder === 0n) return quotient\n\n const halfDenominator = denominator / 2n\n const absRemainder = remainder < 0n ? -remainder : remainder\n\n if (absRemainder > halfDenominator) {\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n if (absRemainder === halfDenominator) {\n const isQuotientEven = quotient % 2n === 0n\n if (isQuotientEven) {\n return quotient\n }\n return numerator < 0n ? quotient - 1n : quotient + 1n\n }\n\n return quotient\n }\n\n /**\n * Convert a Money amount to another currency.\n *\n * @param money - The amount to convert\n * @param targetCurrency - The target currency code\n * @returns A new Money in the target currency\n * @throws {ExchangeRateError} If no rate is available\n */\n convert<From extends string, To extends string>(\n money: Money<From>,\n targetCurrency: To\n ): Money<To> {\n if ((money.currency as string) === (targetCurrency as string)) {\n return money as unknown as Money<To>\n }\n\n const currencyDef = getCurrency(targetCurrency)\n if (!currencyDef) {\n throw new CurrencyUnknownError(targetCurrency)\n }\n\n const rate = this.#rateService.getRate(money.currency, targetCurrency)\n if (!rate) {\n throw new ExchangeRateError(money.currency, targetCurrency)\n }\n\n const sourceCurrencyDef = getCurrency(money.currency)!\n const sourceSubunits = money.toSubunits()\n const sourceMultiplier = 10n ** BigInt(sourceCurrencyDef.decimalDigits)\n const targetMultiplier = 10n ** BigInt(currencyDef.decimalDigits)\n\n const RATE_PRECISION = 15n\n const rateMultiplier = 10n ** RATE_PRECISION\n const rateValue = Number(rate.rate)\n const rateBigInt = BigInt(Math.round(rateValue * Number(rateMultiplier)))\n\n const product = sourceSubunits * rateBigInt * targetMultiplier\n const divisor = rateMultiplier * sourceMultiplier\n const targetSubunits = this.#bankersRound(product, divisor)\n\n return Money.fromSubunits(targetSubunits, targetCurrency)\n }\n\n /**\n * Add two Money amounts, converting as needed.\n *\n * @param a - First amount\n * @param b - Second amount\n * @param resultCurrency - Currency for the result (must be one of the input currencies)\n * @returns Sum in the result currency\n */\n add<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.add(bConverted) as Money<R>\n }\n\n /**\n * Subtract two Money amounts, converting as needed.\n *\n * @param a - Amount to subtract from\n * @param b - Amount to subtract\n * @param resultCurrency - Currency for the result\n * @returns Difference in the result currency\n */\n subtract<A extends string, B extends string, R extends A | B>(\n a: Money<A>,\n b: Money<B>,\n resultCurrency: R\n ): Money<R> {\n const aConverted = this.convert(a, resultCurrency)\n const bConverted = this.convert(b, resultCurrency)\n return aConverted.subtract(bConverted) as Money<R>\n }\n\n /**\n * Calculate what percentage one amount is of another.\n * Converts both to the same currency before comparison.\n *\n * @param part - The partial amount\n * @param whole - The whole amount\n * @returns Percentage as a number (e.g., 25 for 25%)\n */\n percentageOf<A extends string, B extends string>(\n part: Money<A>,\n whole: Money<B>\n ): number {\n // Convert both to the 'whole' currency for comparison\n const partConverted = this.convert(part, whole.currency)\n return (partConverted.toNumber() / whole.toNumber()) * 100\n }\n\n /**\n * Sum multiple Money amounts, converting all to a target currency.\n *\n * @param amounts - Array of Money objects (can be different currencies)\n * @param targetCurrency - Currency for the result\n * @returns Total in the target currency\n */\n sum<C extends string>(amounts: Money<string>[], targetCurrency: C): Money<C> {\n let total = Money.zero(targetCurrency)\n\n for (const amount of amounts) {\n const converted = this.convert(amount, targetCurrency)\n total = total.add(converted)\n }\n\n return total\n }\n\n /**\n * Compare two Money amounts across currencies.\n * Returns negative if a < b, zero if equal, positive if a > b.\n *\n * @param a - First amount\n * @param b - Second amount\n * @returns Comparison result\n */\n compare<A extends string, B extends string>(a: Money<A>, b: Money<B>): -1 | 0 | 1 {\n // Convert b to a's currency for comparison\n const bConverted = this.convert(b, a.currency)\n return Money.compare(a, bConverted)\n }\n\n /**\n * Get the exchange rate service (for direct rate access).\n */\n get rateService(): ExchangeRateService {\n return this.#rateService\n }\n}\n","{\n \"AED\": {\n \"decimal_digits\": 2\n },\n \"AFN\": {\n \"decimal_digits\": 2\n },\n \"ALL\": {\n \"decimal_digits\": 2\n },\n \"AMD\": {\n \"decimal_digits\": 2\n },\n \"AOA\": {\n \"decimal_digits\": 2\n },\n \"ARS\": {\n \"decimal_digits\": 2\n },\n \"AUD\": {\n \"decimal_digits\": 2\n },\n \"AWG\": {\n \"decimal_digits\": 2\n },\n \"AZN\": {\n \"decimal_digits\": 2\n },\n \"BAM\": {\n \"decimal_digits\": 2\n },\n \"BBD\": {\n \"decimal_digits\": 2\n },\n \"BDT\": {\n \"decimal_digits\": 2\n },\n \"BHD\": {\n \"decimal_digits\": 3\n },\n \"BIF\": {\n \"decimal_digits\": 0\n },\n \"BMD\": {\n \"decimal_digits\": 2\n },\n \"BND\": {\n \"decimal_digits\": 2\n },\n \"BOB\": {\n \"decimal_digits\": 2\n },\n \"BOV\": {\n \"decimal_digits\": 2\n },\n \"BRL\": {\n \"decimal_digits\": 2\n },\n \"BSD\": {\n \"decimal_digits\": 2\n },\n \"BTN\": {\n \"decimal_digits\": 2\n },\n \"BWP\": {\n \"decimal_digits\": 2\n },\n \"BYN\": {\n \"decimal_digits\": 2\n },\n \"BZD\": {\n \"decimal_digits\": 2\n },\n \"CAD\": {\n \"decimal_digits\": 2\n },\n \"CDF\": {\n \"decimal_digits\": 2\n },\n \"CHE\": {\n \"decimal_digits\": 2\n },\n \"CHF\": {\n \"decimal_digits\": 2\n },\n \"CHW\": {\n \"decimal_digits\": 2\n },\n \"CLF\": {\n \"decimal_digits\": 4\n },\n \"CLP\": {\n \"decimal_digits\": 0\n },\n \"CNY\": {\n \"decimal_digits\": 2\n },\n \"COP\": {\n \"decimal_digits\": 2\n },\n \"COU\": {\n \"decimal_digits\": 2\n },\n \"CRC\": {\n \"decimal_digits\": 2\n },\n \"CUP\": {\n \"decimal_digits\": 2\n },\n \"CVE\": {\n \"decimal_digits\": 2\n },\n \"CZK\": {\n \"decimal_digits\": 2\n },\n \"DJF\": {\n \"decimal_digits\": 0\n },\n \"DKK\": {\n \"decimal_digits\": 2\n },\n \"DOP\": {\n \"decimal_digits\": 2\n },\n \"DZD\": {\n \"decimal_digits\": 2\n },\n \"EGP\": {\n \"decimal_digits\": 2\n },\n \"ERN\": {\n \"decimal_digits\": 2\n },\n \"ETB\": {\n \"decimal_digits\": 2\n },\n \"EUR\": {\n \"decimal_digits\": 2\n },\n \"FJD\": {\n \"decimal_digits\": 2\n },\n \"FKP\": {\n \"decimal_digits\": 2\n },\n \"GBP\": {\n \"decimal_digits\": 2\n },\n \"GEL\": {\n \"decimal_digits\": 2\n },\n \"GHS\": {\n \"decimal_digits\": 2\n },\n \"GIP\": {\n \"decimal_digits\": 2\n },\n \"GMD\": {\n \"decimal_digits\": 2\n },\n \"GNF\": {\n \"decimal_digits\": 0\n },\n \"GTQ\": {\n \"decimal_digits\": 2\n },\n \"GYD\": {\n \"decimal_digits\": 2\n },\n \"HKD\": {\n \"decimal_digits\": 2\n },\n \"HNL\": {\n \"decimal_digits\": 2\n },\n \"HTG\": {\n \"decimal_digits\": 2\n },\n \"HUF\": {\n \"decimal_digits\": 2\n },\n \"IDR\": {\n \"decimal_digits\": 2\n },\n \"ILS\": {\n \"decimal_digits\": 2\n },\n \"INR\": {\n \"decimal_digits\": 2\n },\n \"IQD\": {\n \"decimal_digits\": 3\n },\n \"IRR\": {\n \"decimal_digits\": 2\n },\n \"ISK\": {\n \"decimal_digits\": 0\n },\n \"JMD\": {\n \"decimal_digits\": 2\n },\n \"JOD\": {\n \"decimal_digits\": 3\n },\n \"JPY\": {\n \"decimal_digits\": 0\n },\n \"KES\": {\n \"decimal_digits\": 2\n },\n \"KGS\": {\n \"decimal_digits\": 2\n },\n \"KHR\": {\n \"decimal_digits\": 2\n },\n \"KMF\": {\n \"decimal_digits\": 0\n },\n \"KPW\": {\n \"decimal_digits\": 2\n },\n \"KRW\": {\n \"decimal_digits\": 0\n },\n \"KWD\": {\n \"decimal_digits\": 3\n },\n \"KYD\": {\n \"decimal_digits\": 2\n },\n \"KZT\": {\n \"decimal_digits\": 2\n },\n \"LAK\": {\n \"decimal_digits\": 2\n },\n \"LBP\": {\n \"decimal_digits\": 2\n },\n \"LKR\": {\n \"decimal_digits\": 2\n },\n \"LRD\": {\n \"decimal_digits\": 2\n },\n \"LSL\": {\n \"decimal_digits\": 2\n },\n \"LYD\": {\n \"decimal_digits\": 3\n },\n \"MAD\": {\n \"decimal_digits\": 2\n },\n \"MDL\": {\n \"decimal_digits\": 2\n },\n \"MGA\": {\n \"decimal_digits\": 2\n },\n \"MKD\": {\n \"decimal_digits\": 2\n },\n \"MMK\": {\n \"decimal_digits\": 2\n },\n \"MNT\": {\n \"decimal_digits\": 2\n },\n \"MOP\": {\n \"decimal_digits\": 2\n },\n \"MRU\": {\n \"decimal_digits\": 2\n },\n \"MUR\": {\n \"decimal_digits\": 2\n },\n \"MVR\": {\n \"decimal_digits\": 2\n },\n \"MWK\": {\n \"decimal_digits\": 2\n },\n \"MXN\": {\n \"decimal_digits\": 2\n },\n \"MXV\": {\n \"decimal_digits\": 2\n },\n \"MYR\": {\n \"decimal_digits\": 2\n },\n \"MZN\": {\n \"decimal_digits\": 2\n },\n \"NAD\": {\n \"decimal_digits\": 2\n },\n \"NGN\": {\n \"decimal_digits\": 2\n },\n \"NIO\": {\n \"decimal_digits\": 2\n },\n \"NOK\": {\n \"decimal_digits\": 2\n },\n \"NPR\": {\n \"decimal_digits\": 2\n },\n \"NZD\": {\n \"decimal_digits\": 2\n },\n \"OMR\": {\n \"decimal_digits\": 3\n },\n \"PAB\": {\n \"decimal_digits\": 2\n },\n \"PEN\": {\n \"decimal_digits\": 2\n },\n \"PGK\": {\n \"decimal_digits\": 2\n },\n \"PHP\": {\n \"decimal_digits\": 2\n },\n \"PKR\": {\n \"decimal_digits\": 2\n },\n \"PLN\": {\n \"decimal_digits\": 2\n },\n \"PYG\": {\n \"decimal_digits\": 0\n },\n \"QAR\": {\n \"decimal_digits\": 2\n },\n \"RON\": {\n \"decimal_digits\": 2\n },\n \"RSD\": {\n \"decimal_digits\": 2\n },\n \"RUB\": {\n \"decimal_digits\": 2\n },\n \"RWF\": {\n \"decimal_digits\": 0\n },\n \"SAR\": {\n \"decimal_digits\": 2\n },\n \"SBD\": {\n \"decimal_digits\": 2\n },\n \"SCR\": {\n \"decimal_digits\": 2\n },\n \"SDG\": {\n \"decimal_digits\": 2\n },\n \"SEK\": {\n \"decimal_digits\": 2\n },\n \"SGD\": {\n \"decimal_digits\": 2\n },\n \"SHP\": {\n \"decimal_digits\": 2\n },\n \"SLE\": {\n \"decimal_digits\": 2\n },\n \"SOS\": {\n \"decimal_digits\": 2\n },\n \"SRD\": {\n \"decimal_digits\": 2\n },\n \"SSP\": {\n \"decimal_digits\": 2\n },\n \"STN\": {\n \"decimal_digits\": 2\n },\n \"SVC\": {\n \"decimal_digits\": 2\n },\n \"SYP\": {\n \"decimal_digits\": 2\n },\n \"SZL\": {\n \"decimal_digits\": 2\n },\n \"THB\": {\n \"decimal_digits\": 2\n },\n \"TJS\": {\n \"decimal_digits\": 2\n },\n \"TMT\": {\n \"decimal_digits\": 2\n },\n \"TND\": {\n \"decimal_digits\": 3\n },\n \"TOP\": {\n \"decimal_digits\": 2\n },\n \"TRY\": {\n \"decimal_digits\": 2\n },\n \"TTD\": {\n \"decimal_digits\": 2\n },\n \"TWD\": {\n \"decimal_digits\": 2\n },\n \"TZS\": {\n \"decimal_digits\": 2\n },\n \"UAH\": {\n \"decimal_digits\": 2\n },\n \"UGX\": {\n \"decimal_digits\": 0\n },\n \"USD\": {\n \"decimal_digits\": 2\n },\n \"USN\": {\n \"decimal_digits\": 2\n },\n \"UYI\": {\n \"decimal_digits\": 0\n },\n \"UYU\": {\n \"decimal_digits\": 2\n },\n \"UYW\": {\n \"decimal_digits\": 4\n },\n \"UZS\": {\n \"decimal_digits\": 2\n },\n \"VED\": {\n \"decimal_digits\": 2\n },\n \"VES\": {\n \"decimal_digits\": 2\n },\n \"VND\": {\n \"decimal_digits\": 0\n },\n \"VUV\": {\n \"decimal_digits\": 0\n },\n \"WST\": {\n \"decimal_digits\": 2\n },\n \"XAD\": {\n \"decimal_digits\": 2\n },\n \"XAF\": {\n \"decimal_digits\": 0\n },\n \"XAG\": {\n \"decimal_digits\": 0\n },\n \"XAU\": {\n \"decimal_digits\": 0\n },\n \"XBA\": {\n \"decimal_digits\": 0\n },\n \"XBB\": {\n \"decimal_digits\": 0\n },\n \"XBC\": {\n \"decimal_digits\": 0\n },\n \"XBD\": {\n \"decimal_digits\": 0\n },\n \"XCD\": {\n \"decimal_digits\": 2\n },\n \"XCG\": {\n \"decimal_digits\": 2\n },\n \"XDR\": {\n \"decimal_digits\": 0\n },\n \"XOF\": {\n \"decimal_digits\": 0\n },\n \"XPD\": {\n \"decimal_digits\": 0\n },\n \"XPF\": {\n \"decimal_digits\": 0\n },\n \"XPT\": {\n \"decimal_digits\": 0\n },\n \"XSU\": {\n \"decimal_digits\": 0\n },\n \"XTS\": {\n \"decimal_digits\": 0\n },\n \"XUA\": {\n \"decimal_digits\": 0\n },\n \"XXX\": {\n \"decimal_digits\": 0\n },\n \"YER\": {\n \"decimal_digits\": 2\n },\n \"ZAR\": {\n \"decimal_digits\": 2\n },\n \"ZMW\": {\n \"decimal_digits\": 2\n },\n \"ZWG\": {\n \"decimal_digits\": 2\n }\n}","/**\n * subunit-money - A type-safe value object for monetary amounts\n *\n * @example\n * import { Money, ExchangeRateService, MoneyConverter } from '@cbrunnkvist/subunit-money'\n *\n * // Basic usage\n * const price = new Money('USD', '19.99')\n * const tax = price.multiply(0.08)\n * const total = price.add(tax)\n *\n * // Currency conversion\n * const rates = new ExchangeRateService()\n * rates.setRate('USD', 'EUR', 0.92)\n * const converter = new MoneyConverter(rates)\n * const euros = converter.convert(total, 'EUR')\n */\n\n// Core classes\nexport { Money, type MoneyObject } from './money.js'\nexport { ExchangeRateService, type ExchangeRate, type RatePair } from './exchange-rate-service.js'\nexport { MoneyConverter } from './money-converter.js'\n\n// Error types\nexport {\n CurrencyMismatchError,\n CurrencyUnknownError,\n SubunitError,\n AmountError,\n ExchangeRateError,\n} from './errors.js'\n\n// Currency utilities\nexport {\n registerCurrency,\n getCurrency,\n hasCurrency,\n getAllCurrencies,\n loadCurrencyMap,\n clearCurrencies,\n type CurrencyDefinition,\n} from './currency.js'\n\n// Auto-load default currencies\n// The currencymap.json file is the official ISO 4217 currency list (List One) as of 2026-01-01,\n// sourced from SIX Financial Information AG (the ISO 4217 Maintenance Agency).\n//\n// To regenerate:\n// 1. Download list-one.xml from https://www.six-group.com/en/products-services/financial-information/data-standards.html\n// 2. Convert with: yq -p xml -o json '.' list-one.xml | jq '.ISO_4217.CcyTbl.CcyNtry | map(select(.Ccy) | {(.Ccy): {decimal_digits: (if (.CcyMnrUnts == \"N.A.\" or .CcyMnrUnts == null) then 0 else (.CcyMnrUnts | tonumber) end)}}) | add | to_entries | sort_by(.key) | from_entries' > currencymap.json\n//\n// Note: This excludes historical currencies, supranational funds, and precious metals,\n// keeping only active national and regional currencies for practical use.\nimport { loadCurrencyMap } from './currency.js'\nimport currencyMap from '../currencymap.json'\nloadCurrencyMap(currencyMap as Record<string, { decimal_digits: number }>)\n"],"mappings":"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;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AAAA,EACA,KAAO;AAAA,IACJ,gBAAkB;AAAA,EACrB;AACH;;;ACheA,gBAAgB,mBAAyD;","names":[]}
|