monetra 2.0.0 → 2.2.0

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.
Files changed (59) hide show
  1. package/README.md +177 -160
  2. package/dist/currency/Currency.d.ts +27 -0
  3. package/dist/currency/index.d.ts +4 -0
  4. package/dist/currency/iso4217.d.ts +245 -0
  5. package/dist/currency/precision.d.ts +2 -0
  6. package/dist/currency/registry.d.ts +22 -0
  7. package/dist/errors/BaseError.d.ts +22 -0
  8. package/dist/errors/CurrencyMismatchError.d.ts +12 -0
  9. package/dist/errors/InsufficientFundsError.d.ts +4 -0
  10. package/dist/errors/InvalidArgumentError.d.ts +4 -0
  11. package/dist/errors/InvalidPrecisionError.d.ts +4 -0
  12. package/dist/errors/OverflowError.d.ts +4 -0
  13. package/dist/errors/RoundingRequiredError.d.ts +4 -0
  14. package/dist/errors/index.d.ts +7 -0
  15. package/dist/financial/compound.d.ts +20 -0
  16. package/dist/financial/depreciation.d.ts +30 -0
  17. package/dist/financial/index.d.ts +7 -0
  18. package/dist/financial/index.js +1323 -0
  19. package/dist/financial/index.js.map +1 -0
  20. package/dist/financial/index.mjs +1275 -0
  21. package/dist/financial/index.mjs.map +1 -0
  22. package/dist/financial/investment.d.ts +31 -0
  23. package/dist/financial/leverage.d.ts +66 -0
  24. package/dist/financial/loan.d.ts +67 -0
  25. package/dist/financial/rate.d.ts +169 -0
  26. package/dist/financial/simple.d.ts +60 -0
  27. package/dist/format/formatter.d.ts +42 -0
  28. package/dist/format/parser.d.ts +53 -0
  29. package/dist/index.d.ts +11 -1202
  30. package/dist/index.js +263 -41
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +248 -41
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/ledger/Ledger.d.ts +65 -0
  35. package/dist/ledger/index.d.ts +3 -0
  36. package/dist/ledger/index.js +1054 -0
  37. package/dist/ledger/index.js.map +1 -0
  38. package/dist/ledger/index.mjs +1029 -0
  39. package/dist/ledger/index.mjs.map +1 -0
  40. package/dist/ledger/types.d.ts +30 -0
  41. package/dist/ledger/verification.d.ts +36 -0
  42. package/dist/money/Converter.d.ts +26 -0
  43. package/dist/money/Money.d.ts +299 -0
  44. package/dist/money/MoneyBag.d.ts +46 -0
  45. package/dist/money/allocation.d.ts +13 -0
  46. package/dist/money/arithmetic.d.ts +32 -0
  47. package/dist/money/guards.d.ts +3 -0
  48. package/dist/money/index.d.ts +4 -0
  49. package/dist/rounding/index.d.ts +3 -0
  50. package/dist/rounding/strategies.d.ts +36 -0
  51. package/dist/tokens/defineToken.d.ts +30 -0
  52. package/dist/tokens/index.d.ts +2 -0
  53. package/dist/tokens/index.js +100 -0
  54. package/dist/tokens/index.js.map +1 -0
  55. package/dist/tokens/index.mjs +69 -0
  56. package/dist/tokens/index.mjs.map +1 -0
  57. package/dist/tokens/types.d.ts +13 -0
  58. package/package.json +34 -14
  59. package/dist/index.d.mts +0 -1211
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/currency/registry.ts","../src/rounding/strategies.ts","../src/errors/BaseError.ts","../src/errors/CurrencyMismatchError.ts","../src/errors/InvalidPrecisionError.ts","../src/errors/RoundingRequiredError.ts","../src/errors/InsufficientFundsError.ts","../src/errors/OverflowError.ts","../src/money/guards.ts","../src/rounding/index.ts","../src/money/arithmetic.ts","../src/money/allocation.ts","../src/format/parser.ts","../src/format/formatter.ts","../src/money/Money.ts","../src/money/Converter.ts","../src/money/MoneyBag.ts","../src/currency/iso4217.ts","../src/currency/precision.ts","../src/financial/loan.ts","../src/financial/compound.ts","../src/financial/investment.ts","../src/financial/rate.ts","../src/ledger/verification.ts","../src/ledger/Ledger.ts","../src/index.ts"],"sourcesContent":["import { Currency } from \"./Currency\";\n\nconst registry: Map<string, Currency> = new Map();\n\n/**\n * Registers a currency in the global registry.\n * @param currency The currency to register.\n */\nexport function registerCurrency(currency: Currency): void {\n registry.set(currency.code, currency);\n}\n\n/**\n * Retrieves a currency by its code.\n * @param code The currency code (e.g., \"USD\").\n * @returns The Currency object.\n * @throws Error if the currency is not found.\n */\nexport function getCurrency(code: string): Currency {\n const currency = registry.get(code);\n if (!currency) {\n throw new Error(`Currency '${code}' not found in registry.`);\n }\n return currency;\n}\n\n/**\n * Checks if a currency is registered.\n */\nexport function isCurrencyRegistered(code: string): boolean {\n return registry.has(code);\n}\n","/**\n * Enumeration of rounding modes for handling fractional minor units.\n */\nexport enum RoundingMode {\n /**\n * Rounds towards the nearest neighbor. If equidistant, rounds away from zero.\n * Example: 2.5 -> 3, -2.5 -> -3\n */\n HALF_UP = \"HALF_UP\",\n\n /**\n * Rounds towards the nearest neighbor. If equidistant, rounds towards zero.\n * Example: 2.5 -> 2, -2.5 -> -2\n */\n HALF_DOWN = \"HALF_DOWN\",\n\n /**\n * Rounds towards the nearest neighbor. If equidistant, rounds towards the nearest even integer.\n * Also known as Banker's Rounding.\n * Example: 2.5 -> 2, 3.5 -> 4\n */\n HALF_EVEN = \"HALF_EVEN\",\n\n /**\n * Rounds towards negative infinity.\n * Example: 2.9 -> 2, -2.1 -> -3\n */\n FLOOR = \"FLOOR\",\n\n /**\n * Rounds towards positive infinity.\n * Example: 2.1 -> 3, -2.9 -> -2\n */\n CEIL = \"CEIL\",\n\n /**\n * Truncates towards zero (removes fractional part).\n * Example: 2.9 -> 2, -2.9 -> -2\n */\n TRUNCATE = \"TRUNCATE\",\n}\n","/**\n * Error codes for programmatic handling of Monetra errors.\n */\nexport enum MonetraErrorCode {\n CURRENCY_MISMATCH = \"MONETRA_CURRENCY_MISMATCH\",\n INSUFFICIENT_FUNDS = \"MONETRA_INSUFFICIENT_FUNDS\",\n INVALID_PRECISION = \"MONETRA_INVALID_PRECISION\",\n OVERFLOW = \"MONETRA_OVERFLOW\",\n ROUNDING_REQUIRED = \"MONETRA_ROUNDING_REQUIRED\",\n}\n\n/**\n * Base error class for all Monetra errors.\n * All Monetra errors include an error code for programmatic handling.\n */\nexport class MonetraError extends Error {\n /**\n * A unique error code for programmatic handling.\n */\n readonly code: MonetraErrorCode;\n\n constructor(message: string, code: MonetraErrorCode) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class CurrencyMismatchError extends MonetraError {\n /**\n * The expected currency code.\n */\n readonly expected: string;\n\n /**\n * The received currency code.\n */\n readonly received: string;\n\n constructor(expected: string, received: string) {\n super(\n `Currency mismatch: expected ${expected}, received ${received}.\\n` +\n `💡 Tip: Use a Converter to convert between currencies:\\n` +\n ` const converter = new Converter('USD', { ${received}: rate });\\n` +\n ` const converted = converter.convert(money, '${expected}');`,\n MonetraErrorCode.CURRENCY_MISMATCH\n );\n this.expected = expected;\n this.received = received;\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InvalidPrecisionError extends MonetraError {\n constructor(message: string) {\n super(message, MonetraErrorCode.INVALID_PRECISION);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class RoundingRequiredError extends MonetraError {\n constructor(operation?: string, result?: number) {\n let message = \"Rounding is required for this operation but was not provided.\";\n if (operation && result !== undefined) {\n message =\n `Rounding required for ${operation}: result ${result} is not an integer.\\n` +\n `💡 Tip: Provide a rounding mode:\\n` +\n ` money.${operation}(value, { rounding: RoundingMode.HALF_UP })\\n` +\n ` Available modes: HALF_UP, HALF_DOWN, HALF_EVEN, FLOOR, CEIL, TRUNCATE`;\n }\n super(message, MonetraErrorCode.ROUNDING_REQUIRED);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InsufficientFundsError extends MonetraError {\n constructor(message?: string) {\n super(\n message || \"Insufficient funds for this operation.\",\n MonetraErrorCode.INSUFFICIENT_FUNDS\n );\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class OverflowError extends MonetraError {\n constructor(message: string = \"Arithmetic overflow\") {\n super(message, MonetraErrorCode.OVERFLOW);\n }\n}\n","import { Money } from \"./Money\";\nimport { CurrencyMismatchError, InsufficientFundsError } from \"../errors\";\n\nexport function assertSameCurrency(a: Money, b: Money): void {\n if (a.currency.code !== b.currency.code) {\n throw new CurrencyMismatchError(a.currency.code, b.currency.code);\n }\n}\n\nexport function assertNonNegative(money: Money): void {\n if (money.isNegative()) {\n // Spec doesn't explicitly name a NegativeError, but InsufficientFundsError might fit or just a generic error.\n // Spec lists \"InsufficientFundsError\" in 4.7.\n // But \"assertNonNegative\" is a guard.\n // Let's throw an Error or a specific one if defined.\n // \"Any violation is considered a bug\" -> maybe just Error?\n // But for \"InsufficientFunds\", that's usually when subtracting.\n // Let's use a generic Error for now or create a specific one if needed.\n throw new Error(\"Money value must be non-negative\");\n }\n}\n","import { RoundingMode } from \"./strategies\";\n\nexport * from \"./strategies\";\n\nexport function divideWithRounding(\n numerator: bigint,\n denominator: bigint,\n mode: RoundingMode\n): bigint {\n if (denominator === 0n) {\n throw new Error(\"Division by zero\");\n }\n\n const quotient = numerator / denominator;\n const remainder = numerator % denominator;\n\n if (remainder === 0n) {\n return quotient;\n }\n\n const sign = (numerator >= 0n ? 1n : -1n) * (denominator >= 0n ? 1n : -1n);\n const absRemainder = remainder < 0n ? -remainder : remainder;\n const absDenominator = denominator < 0n ? -denominator : denominator;\n\n // Check for exact half\n const isHalf = absRemainder * 2n === absDenominator;\n const isMoreThanHalf = absRemainder * 2n > absDenominator;\n\n switch (mode) {\n case RoundingMode.FLOOR:\n // If positive, quotient is already floor (truncation).\n // If negative, quotient is ceil (truncation towards zero), so we need to subtract 1.\n return sign > 0n ? quotient : quotient - 1n;\n case RoundingMode.CEIL:\n // If positive, quotient is floor, so add 1.\n // If negative, quotient is ceil, so keep it.\n return sign > 0n ? quotient + 1n : quotient;\n case RoundingMode.HALF_UP:\n if (isMoreThanHalf || isHalf) {\n return sign > 0n ? quotient + 1n : quotient - 1n;\n }\n return quotient;\n case RoundingMode.HALF_DOWN:\n if (isMoreThanHalf) {\n return sign > 0n ? quotient + 1n : quotient - 1n;\n }\n return quotient;\n case RoundingMode.HALF_EVEN:\n if (isMoreThanHalf) {\n return sign > 0n ? quotient + 1n : quotient - 1n;\n }\n if (isHalf) {\n // If quotient is odd, round up (away from zero? no, to nearest even).\n // If quotient is even, keep it.\n if (quotient % 2n !== 0n) {\n return sign > 0n ? quotient + 1n : quotient - 1n;\n }\n }\n return quotient;\n case RoundingMode.TRUNCATE:\n // Truncate towards zero (simply return the quotient without adjustment)\n return quotient;\n default:\n throw new Error(`Unsupported rounding mode: ${mode}`);\n }\n}\n","import { RoundingMode, divideWithRounding } from \"../rounding\";\nimport { RoundingRequiredError } from \"../errors\";\n\n/**\n * Adds two BigInt values.\n */\nexport function add(a: bigint, b: bigint): bigint {\n return a + b;\n}\n\n/**\n * Subtracts two BigInt values.\n */\nexport function subtract(a: bigint, b: bigint): bigint {\n return a - b;\n}\n\n/**\n * Multiplies a BigInt amount by a multiplier.\n *\n * Handles fractional multipliers by converting them to a rational number (numerator/denominator).\n * If the result is not an integer, a rounding mode must be provided.\n *\n * @param amount - The amount to multiply.\n * @param multiplier - The multiplier (number or string).\n * @param rounding - Optional rounding mode.\n * @returns The result as a BigInt.\n * @throws {RoundingRequiredError} If rounding is needed but not provided.\n */\nexport function multiply(\n amount: bigint,\n multiplier: string | number,\n rounding?: RoundingMode\n): bigint {\n const { numerator, denominator } = parseMultiplier(multiplier);\n\n // result = amount * (numerator / denominator)\n // result = (amount * numerator) / denominator\n\n const product = amount * numerator;\n\n if (product % denominator === 0n) {\n return product / denominator;\n }\n\n if (!rounding) {\n throw new RoundingRequiredError(\n \"multiply\",\n Number(product) / Number(denominator)\n );\n }\n\n return divideWithRounding(product, denominator, rounding);\n}\n\n/**\n * Divides a BigInt amount by a divisor.\n *\n * @param amount - The amount to divide.\n * @param divisor - The divisor (number or string).\n * @param rounding - Optional rounding mode.\n * @returns The result as a BigInt.\n * @throws {RoundingRequiredError} If rounding is needed but not provided.\n */\nexport function divide(\n amount: bigint,\n divisor: string | number,\n rounding?: RoundingMode\n): bigint {\n const { numerator, denominator } = parseMultiplier(divisor);\n\n // result = amount / (numerator / denominator)\n // result = (amount * denominator) / numerator\n\n const product = amount * denominator;\n\n if (product % numerator === 0n) {\n return product / numerator;\n }\n\n if (!rounding) {\n throw new RoundingRequiredError(\"divide\", Number(product) / Number(numerator));\n }\n\n return divideWithRounding(product, numerator, rounding);\n}\n\nfunction parseMultiplier(multiplier: string | number): {\n numerator: bigint;\n denominator: bigint;\n} {\n const s = multiplier.toString();\n\n // Check for scientific notation\n if (/[eE]/.test(s)) {\n throw new Error(\"Scientific notation not supported\");\n }\n\n const parts = s.split(\".\");\n if (parts.length > 2) {\n throw new Error(\"Invalid number format\");\n }\n\n const integerPart = parts[0];\n const fractionalPart = parts[1] || \"\";\n\n const denominator = 10n ** BigInt(fractionalPart.length);\n const numerator = BigInt(integerPart + fractionalPart);\n\n return { numerator, denominator };\n}\n","/**\n * Allocates a monetary amount according to a list of ratios.\n *\n * Uses the \"Largest Remainder Method\" to ensure that the sum of the allocated\n * parts equals the original amount. Remainders are distributed to the parts\n * that had the largest fractional remainders during the division.\n *\n * @param amount - The total amount to allocate (in minor units).\n * @param ratios - An array of ratios (e.g., [1, 1] for 50/50 split).\n * @returns An array of allocated amounts (in minor units).\n * @throws {Error} If ratios are empty or total ratio is zero.\n */\nexport function allocate(amount: bigint, ratios: number[]): bigint[] {\n if (ratios.length === 0) {\n throw new Error(\"Cannot allocate to empty ratios\");\n }\n\n // Scale ratios to integers\n const scaledRatios = ratios.map((r) => {\n const s = r.toString();\n if (/[eE]/.test(s)) throw new Error(\"Scientific notation not supported\");\n const parts = s.split(\".\");\n const decimals = parts[1] ? parts[1].length : 0;\n const value = BigInt(parts[0] + (parts[1] || \"\"));\n return { value, decimals };\n });\n\n const maxDecimals = Math.max(...scaledRatios.map((r) => r.decimals));\n\n const normalizedRatios = scaledRatios.map((r) => {\n const factor = 10n ** BigInt(maxDecimals - r.decimals);\n return r.value * factor;\n });\n\n const total = normalizedRatios.reduce((sum, r) => sum + r, 0n);\n\n if (total === 0n) {\n throw new Error(\"Total ratio must be greater than zero\");\n }\n\n const results: { share: bigint; remainder: bigint; index: number }[] = [];\n let allocatedTotal = 0n;\n\n for (let i = 0; i < normalizedRatios.length; i++) {\n const ratio = normalizedRatios[i];\n const share = (amount * ratio) / total;\n const remainder = (amount * ratio) % total;\n\n results.push({ share, remainder, index: i });\n allocatedTotal += share;\n }\n\n let leftOver = amount - allocatedTotal;\n\n // Distribute leftover to those with largest remainder\n // Sort by remainder desc\n results.sort((a, b) => {\n if (b.remainder > a.remainder) return 1;\n if (b.remainder < a.remainder) return -1;\n return 0;\n });\n\n for (let i = 0; i < Number(leftOver); i++) {\n results[i].share += 1n;\n }\n\n // Sort back by index\n results.sort((a, b) => a.index - b.index);\n\n return results.map((r) => r.share);\n}\n","import { Currency } from \"../currency/Currency\";\nimport { InvalidPrecisionError } from \"../errors\";\n\n/**\n * Options for locale-aware parsing.\n */\nexport interface LocaleParseOptions {\n /**\n * The locale to use for parsing (e.g., \"en-US\", \"de-DE\").\n * Used to detect decimal and grouping separators.\n */\n locale: string;\n}\n\n/**\n * Parses a locale-formatted string into a normalized decimal string.\n *\n * Handles locale-specific decimal separators (e.g., comma in German \"1.234,56\")\n * and grouping separators (e.g., period in German \"1.234\").\n *\n * @param amount - The locale-formatted amount string (e.g., \"1,234.56\" or \"1.234,56\").\n * @param options - The locale options.\n * @returns A normalized decimal string (e.g., \"1234.56\").\n * @example\n * parseLocaleString(\"1.234,56\", { locale: \"de-DE\" }); // \"1234.56\"\n * parseLocaleString(\"1,234.56\", { locale: \"en-US\" }); // \"1234.56\"\n */\nexport function parseLocaleString(\n amount: string,\n options: LocaleParseOptions\n): string {\n // Use Intl.NumberFormat to determine the locale's separators\n const parts = new Intl.NumberFormat(options.locale, {\n style: \"decimal\",\n minimumFractionDigits: 1,\n useGrouping: true,\n }).formatToParts(1234.5);\n\n let decimalSeparator = \".\";\n let groupSeparator = \",\";\n\n for (const part of parts) {\n if (part.type === \"decimal\") {\n decimalSeparator = part.value;\n } else if (part.type === \"group\") {\n groupSeparator = part.value;\n }\n }\n\n // Handle the case where group and decimal separators are the same\n // (shouldn't happen, but be defensive)\n if (groupSeparator === decimalSeparator) {\n throw new Error(\n `Invalid locale configuration: group and decimal separators are the same for locale ${options.locale}`\n );\n }\n\n // Remove currency symbols and whitespace\n let normalized = amount.replace(/[^\\d.,\\-\\s]/g, \"\").trim();\n\n // Handle negative sign\n const isNegative = normalized.startsWith(\"-\") || amount.includes(\"(\");\n normalized = normalized.replace(/[-()]/g, \"\");\n\n // Remove all grouping separators\n const groupRegex = new RegExp(`\\\\${groupSeparator}`, \"g\");\n normalized = normalized.replace(groupRegex, \"\");\n\n // Replace locale decimal separator with standard period\n if (decimalSeparator !== \".\") {\n normalized = normalized.replace(decimalSeparator, \".\");\n }\n\n return isNegative ? `-${normalized}` : normalized;\n}\n\n/**\n * Parses a locale-formatted amount string and converts it to Money minor units.\n *\n * This is a convenience function that combines locale parsing with currency validation.\n *\n * @param amount - The locale-formatted amount string.\n * @param currency - The currency to validate against.\n * @param options - The locale options.\n * @returns The amount in minor units as a BigInt.\n * @throws {InvalidPrecisionError} If the precision exceeds the currency's decimals.\n * @example\n * parseLocaleToMinor(\"1.234,56\", EUR, { locale: \"de-DE\" }); // 123456n\n */\nexport function parseLocaleToMinor(\n amount: string,\n currency: Currency,\n options: LocaleParseOptions\n): bigint {\n const normalized = parseLocaleString(amount, options);\n return parseToMinor(normalized, currency);\n}\n\n/**\n * Parses a string representation of a major unit amount into minor units.\n *\n * Validates the input format to ensure it is a valid decimal number without\n * scientific notation or ambiguous characters. Checks that the precision\n * does not exceed the currency's allowed decimals.\n *\n * @param amount - The amount string (e.g., \"10.50\").\n * @param currency - The currency to validate against.\n * @returns The amount in minor units as a BigInt.\n * @throws {Error} If the format is invalid (scientific notation, non-numeric chars).\n * @throws {InvalidPrecisionError} If the precision exceeds the currency's decimals.\n */\nexport function parseToMinor(amount: string, currency: Currency): bigint {\n // Validate format\n if (/[eE]/.test(amount)) {\n throw new Error(\"Scientific notation not supported\");\n }\n\n // Reject ambiguous separators (commas, spaces, etc.)\n if (/[^0-9.-]/.test(amount)) {\n throw new Error(\"Invalid characters in amount\");\n }\n\n const parts = amount.split(\".\");\n if (parts.length > 2) {\n throw new Error(\"Invalid format: multiple decimal points\");\n }\n\n const integerPart = parts[0];\n const fractionalPart = parts[1] || \"\";\n\n if (fractionalPart.length > currency.decimals) {\n throw new InvalidPrecisionError(\n `Precision ${fractionalPart.length} exceeds currency decimals ${currency.decimals}`\n );\n }\n\n // Pad fractional part\n const paddedFractional = fractionalPart.padEnd(currency.decimals, \"0\");\n\n const combined = integerPart + paddedFractional;\n\n // Handle edge case where integer part is just \"-\"\n if (combined === \"-\" || combined === \"\") {\n throw new Error(\"Invalid format\");\n }\n\n return BigInt(combined);\n}\n","import { Money } from \"../money/Money\";\n\n/**\n * Options for formatting Money values.\n */\nexport interface FormatOptions {\n /**\n * The locale to use for formatting (e.g., \"en-US\", \"de-DE\").\n * If not provided, defaults to the currency's default locale or \"en-US\".\n */\n locale?: string;\n\n /**\n * Whether to include the currency symbol in the output.\n * Defaults to true.\n */\n symbol?: boolean;\n\n /**\n * How to display the currency.\n * 'symbol' (default): \"$1.00\"\n * 'code': \"USD 1.00\"\n * 'name': \"1.00 US dollars\"\n */\n display?: \"symbol\" | \"code\" | \"name\";\n\n /**\n * Whether to use accounting format for negative numbers.\n * When true, negative values are wrapped in parentheses instead of using a minus sign.\n * Defaults to false.\n * @example\n * // accounting: false (default): \"-$1.00\"\n * // accounting: true: \"($1.00)\"\n */\n accounting?: boolean;\n}\n\n/**\n * Formats a Money object into a string representation.\n *\n * Uses `Intl.NumberFormat` for locale-aware formatting of numbers and currency symbols.\n *\n * @param money - The Money object to format.\n * @param options - Formatting options.\n * @returns The formatted string.\n */\nexport function format(money: Money, options?: FormatOptions): string {\n const locale = options?.locale || money.currency.locale || \"en-US\";\n const showSymbol = options?.symbol ?? true;\n const display = options?.display || \"symbol\";\n const useAccounting = options?.accounting ?? false;\n\n const decimals = money.currency.decimals;\n const minor = money.minor;\n const isNegative = minor < 0n;\n const absMinor = isNegative ? -minor : minor;\n\n const divisor = 10n ** BigInt(decimals);\n const integerPart = absMinor / divisor;\n const fractionalPart = absMinor % divisor;\n\n // Pad fractional\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n\n // Get separators\n // We use a dummy format to extract the decimal separator for the locale\n const parts = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n minimumFractionDigits: 1,\n }).formatToParts(1.1);\n\n const decimalSeparator =\n parts.find((p) => p.type === \"decimal\")?.value || \".\";\n\n // Format integer part with grouping using Intl (supports BigInt)\n const integerFormatted = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n useGrouping: true,\n }).format(integerPart);\n\n const absString =\n decimals > 0\n ? `${integerFormatted}${decimalSeparator}${fractionalStr}`\n : integerFormatted;\n\n if (!showSymbol) {\n if (isNegative) {\n return useAccounting ? `(${absString})` : `-${absString}`;\n }\n return absString;\n }\n\n // Use formatToParts to get the template (sign position, currency position)\n let templateParts: Intl.NumberFormatPart[];\n try {\n templateParts = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: money.currency.code,\n currencyDisplay: display,\n }).formatToParts(isNegative ? -1 : 1);\n } catch (e) {\n // Fallback for custom currencies or invalid codes\n const symbol =\n display === \"symbol\" ? money.currency.symbol : money.currency.code;\n if (isNegative) {\n return useAccounting\n ? `(${symbol}${absString})`\n : `-${symbol}${absString}`;\n }\n return `${symbol}${absString}`;\n }\n\n let result = \"\";\n let numberInserted = false;\n let hasMinusSign = false;\n\n for (const part of templateParts) {\n if (part.type === \"minusSign\") {\n hasMinusSign = true;\n // Skip the minus sign, we'll handle it later for accounting format\n if (!useAccounting) {\n result += part.value;\n }\n continue;\n }\n if ([\"integer\", \"group\", \"decimal\", \"fraction\"].includes(part.type)) {\n if (!numberInserted) {\n result += absString;\n numberInserted = true;\n }\n } else if (part.type === \"currency\") {\n if (display === \"symbol\" && money.currency.symbol) {\n result += money.currency.symbol;\n } else {\n result += part.value;\n }\n } else {\n result += part.value; // literals, parentheses, etc.\n }\n }\n\n // Apply accounting format if negative\n if (useAccounting && isNegative) {\n return `(${result.trim()})`;\n }\n\n return result;\n}\n","import { Currency } from \"../currency/Currency\";\nimport { getCurrency } from \"../currency/registry\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nimport { assertSameCurrency } from \"./guards\";\nimport { add, subtract, multiply, divide } from \"./arithmetic\";\nimport { allocate } from \"./allocation\";\nimport { parseToMinor } from \"../format/parser\";\nimport { format } from \"../format/formatter\";\n\n/**\n * Represents a monetary value in a specific currency.\n *\n * Money objects are immutable and store values in minor units (e.g., cents) using BigInt\n * to avoid floating-point precision errors.\n */\nexport class Money {\n /**\n * The amount in minor units (e.g., cents).\n */\n readonly minor: bigint;\n\n /**\n * The currency of this money value.\n */\n readonly currency: Currency;\n\n private constructor(minor: bigint, currency: Currency) {\n this.minor = minor;\n this.currency = currency;\n }\n\n private static resolveCurrency(currency: Currency | string): Currency {\n if (typeof currency === \"string\") {\n return getCurrency(currency);\n }\n return currency;\n }\n\n /**\n * Creates a Money instance from minor units (e.g., cents).\n *\n * @param minor - The amount in minor units. Can be a number or BigInt.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @example\n * const m = Money.fromMinor(100, USD); // $1.00\n * const m2 = Money.fromMinor(100, 'USD'); // $1.00\n */\n static fromMinor(minor: bigint | number, currency: Currency | string): Money {\n return new Money(BigInt(minor), Money.resolveCurrency(currency));\n }\n\n /**\n * Alias for `fromMinor`. Creates a Money instance from cents/minor units.\n *\n * @param cents - The amount in minor units.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @example\n * const m = Money.fromCents(100, 'USD'); // $1.00\n */\n static fromCents(cents: bigint | number, currency: Currency | string): Money {\n return Money.fromMinor(cents, currency);\n }\n\n /**\n * Creates a Money instance from major units (e.g., \"10.50\").\n *\n * @param amount - The amount as a string. Must be a valid decimal number.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.\n * @example\n * const m = Money.fromMajor(\"10.50\", USD); // $10.50\n */\n static fromMajor(amount: string, currency: Currency | string): Money {\n const resolvedCurrency = Money.resolveCurrency(currency);\n const minor = parseToMinor(amount, resolvedCurrency);\n return new Money(minor, resolvedCurrency);\n }\n\n /**\n * Alias for `fromMajor`. Creates a Money instance from a decimal string.\n *\n * @param amount - The amount as a string (e.g., \"10.50\").\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.\n * @example\n * const m = Money.fromDecimal(\"10.50\", 'USD'); // $10.50\n */\n static fromDecimal(amount: string, currency: Currency | string): Money {\n return Money.fromMajor(amount, currency);\n }\n\n /**\n * Creates a Money instance from a floating-point number.\n *\n * ⚠️ WARNING: Floating-point numbers can have precision issues.\n * Prefer `Money.fromMajor(\"10.50\", currency)` for exact values.\n *\n * @param amount - The float amount in major units.\n * @param currency - The currency.\n * @param options - Options for handling precision.\n * @returns A new Money instance.\n */\n static fromFloat(\n amount: number,\n currency: Currency | string,\n options?: {\n rounding?: RoundingMode;\n suppressWarning?: boolean;\n }\n ): Money {\n if (!options?.suppressWarning && process.env.NODE_ENV !== \"production\") {\n console.warn(\n '[monetra] Money.fromFloat() may lose precision. ' +\n 'Consider using Money.fromMajor(\"' +\n amount +\n '\", currency) instead.'\n );\n }\n const resolvedCurrency = Money.resolveCurrency(currency);\n const factor = 10 ** resolvedCurrency.decimals;\n const minorUnits = Math.round(amount * factor);\n return new Money(BigInt(minorUnits), resolvedCurrency);\n }\n\n /**\n * Returns the minimum of the provided Money values.\n * @param values - Money values to compare (must all be same currency).\n * @returns The Money with the smallest amount.\n * @throws {CurrencyMismatchError} If currencies don't match.\n */\n static min(...values: Money[]): Money {\n if (values.length === 0)\n throw new Error(\"At least one Money value required\");\n return values.reduce((min, current) => {\n assertSameCurrency(min, current);\n return current.lessThan(min) ? current : min;\n });\n }\n\n /**\n * Returns the maximum of the provided Money values.\n * @param values - Money values to compare (must all be same currency).\n * @returns The Money with the largest amount.\n * @throws {CurrencyMismatchError} If currencies don't match.\n */\n static max(...values: Money[]): Money {\n if (values.length === 0)\n throw new Error(\"At least one Money value required\");\n return values.reduce((max, current) => {\n assertSameCurrency(max, current);\n return current.greaterThan(max) ? current : max;\n });\n }\n\n /**\n * Creates a Money instance representing zero in the given currency.\n *\n * @param currency - The currency.\n * @returns A new Money instance with value 0.\n */\n static zero(currency: Currency | string): Money {\n return new Money(0n, Money.resolveCurrency(currency));\n }\n\n private resolveOther(other: Money | number | bigint | string): Money {\n if (other instanceof Money) {\n return other;\n }\n if (typeof other === \"string\") {\n return Money.fromMajor(other, this.currency);\n }\n return Money.fromMinor(other, this.currency);\n }\n\n /**\n * Adds another Money value to this one.\n *\n * @param other - The value to add (Money, minor units as number/bigint, or major units as string).\n * @returns A new Money instance representing the sum.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n add(other: Money | number | bigint | string): Money {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return new Money(add(this.minor, otherMoney.minor), this.currency);\n }\n\n /**\n * Subtracts another Money value from this one.\n *\n * @param other - The value to subtract (Money, minor units as number/bigint, or major units as string).\n * @returns A new Money instance representing the difference.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n subtract(other: Money | number | bigint | string): Money {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return new Money(subtract(this.minor, otherMoney.minor), this.currency);\n }\n\n /**\n * Multiplies this Money value by a scalar.\n *\n * @param multiplier - The number to multiply by.\n * @param options - Options for rounding if the result is not an integer.\n * @returns A new Money instance representing the product.\n * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.\n */\n multiply(\n multiplier: string | number,\n options?: { rounding?: RoundingMode }\n ): Money {\n const result = multiply(this.minor, multiplier, options?.rounding);\n return new Money(result, this.currency);\n }\n\n /**\n * Divides this Money value by a divisor.\n *\n * @param divisor - The number to divide by.\n * @param options - Options for rounding if the result is not an integer.\n * @returns A new Money instance representing the quotient.\n * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.\n * @throws {Error} If divisor is zero.\n */\n divide(\n divisor: number | string,\n options?: { rounding?: RoundingMode }\n ): Money {\n if (divisor === 0 || divisor === \"0\") {\n throw new Error(\"Division by zero\");\n }\n const result = divide(this.minor, divisor, options?.rounding);\n return new Money(result, this.currency);\n }\n\n /**\n * Returns the absolute value of this Money.\n * @returns A new Money instance with the absolute value.\n */\n abs(): Money {\n return new Money(\n this.minor < 0n ? -this.minor : this.minor,\n this.currency\n );\n }\n\n /**\n * Returns the negated value of this Money.\n * @returns A new Money instance with the negated value.\n */\n negate(): Money {\n return new Money(-this.minor, this.currency);\n }\n\n /**\n * Allocates (splits) this Money value according to a list of ratios.\n *\n * The sum of the parts will always equal the original amount.\n * Remainders are distributed to the parts with the largest fractional remainders.\n *\n * @param ratios - A list of numbers representing the ratios to split by.\n * @returns An array of Money instances.\n */\n allocate(ratios: number[]): Money[] {\n const shares = allocate(this.minor, ratios);\n return shares.map((share) => new Money(share, this.currency));\n }\n\n /**\n * Formats this Money value as a string.\n *\n * @param options - Formatting options.\n * @returns The formatted string.\n */\n format(options?: {\n locale?: string;\n symbol?: boolean;\n display?: \"symbol\" | \"code\" | \"name\";\n }): string {\n return format(this, options);\n }\n\n /**\n * Checks if this Money value is equal to another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if amounts and currencies are equal.\n */\n equals(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n return (\n this.currency.code === otherMoney.currency.code &&\n this.minor === otherMoney.minor\n );\n }\n\n /**\n * Checks if this Money value is greater than another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if this value is greater.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n greaterThan(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor > otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is less than another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if this value is less.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n lessThan(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor < otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is greater than or equal to another.\n */\n greaterThanOrEqual(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor >= otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is less than or equal to another.\n */\n lessThanOrEqual(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor <= otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.minor > 0n;\n }\n\n /**\n * Compares this Money to another, returning -1, 0, or 1.\n * Useful for sorting.\n */\n compare(other: Money | number | bigint | string): -1 | 0 | 1 {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n if (this.minor < otherMoney.minor) return -1;\n if (this.minor > otherMoney.minor) return 1;\n return 0;\n }\n\n /**\n * Calculates a percentage of the money.\n * @param percent - The percentage (e.g., 50 for 50%).\n * @param rounding - Rounding mode (defaults to HALF_EVEN).\n */\n percentage(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN\n ): Money {\n return this.multiply(percent / 100, { rounding });\n }\n\n /**\n * Adds a percentage to the money.\n * @param percent - The percentage to add.\n * @param rounding - Rounding mode.\n */\n addPercent(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN\n ): Money {\n return this.add(this.percentage(percent, rounding));\n }\n\n /**\n * Subtracts a percentage from the money.\n * @param percent - The percentage to subtract.\n * @param rounding - Rounding mode.\n */\n subtractPercent(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN\n ): Money {\n return this.subtract(this.percentage(percent, rounding));\n }\n\n /**\n * Splits the money into equal parts.\n * @param parts - Number of parts.\n */\n split(parts: number): Money[] {\n const ratios = Array(parts).fill(1);\n return this.allocate(ratios);\n }\n\n /**\n * Checks if this Money value is zero.\n *\n * @returns True if the amount is zero.\n */\n isZero(): boolean {\n return this.minor === 0n;\n }\n\n /**\n * Checks if this Money value is negative.\n *\n * @returns True if the amount is negative.\n */\n isNegative(): boolean {\n return this.minor < 0n;\n }\n\n /**\n * Clamps this Money value between a minimum and maximum.\n *\n * @param min - The minimum Money value.\n * @param max - The maximum Money value.\n * @returns A new Money instance clamped between min and max.\n * @throws {CurrencyMismatchError} If currencies don't match.\n * @throws {Error} If min is greater than max.\n * @example\n * const price = Money.fromMajor(\"150\", 'USD');\n * const clamped = price.clamp(Money.fromMajor(\"50\", 'USD'), Money.fromMajor(\"100\", 'USD'));\n * // clamped is $100.00\n */\n clamp(min: Money, max: Money): Money {\n assertSameCurrency(this, min);\n assertSameCurrency(this, max);\n\n if (min.greaterThan(max)) {\n throw new Error(\"Clamp min cannot be greater than max\");\n }\n\n if (this.lessThan(min)) {\n return new Money(min.minor, this.currency);\n }\n if (this.greaterThan(max)) {\n return new Money(max.minor, this.currency);\n }\n return this;\n }\n\n /**\n * Returns the value as a decimal string without locale formatting.\n *\n * This returns a raw decimal representation suitable for storage or calculations,\n * without any currency symbols, grouping separators, or locale-specific formatting.\n *\n * @returns The decimal string representation (e.g., \"10.50\", \"-5.25\").\n * @example\n * const m = Money.fromMajor(\"1234.56\", 'USD');\n * m.toDecimalString(); // \"1234.56\"\n */\n toDecimalString(): string {\n const decimals = this.currency.decimals;\n const isNegative = this.minor < 0n;\n const absMinor = isNegative ? -this.minor : this.minor;\n\n if (decimals === 0) {\n return isNegative ? `-${absMinor.toString()}` : absMinor.toString();\n }\n\n const divisor = 10n ** BigInt(decimals);\n const integerPart = absMinor / divisor;\n const fractionalPart = absMinor % divisor;\n\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n const result = `${integerPart}.${fractionalStr}`;\n\n return isNegative ? `-${result}` : result;\n }\n\n /**\n * Returns a JSON representation of the Money object.\n *\n * @returns An object with amount (string), currency (code), and precision.\n */\n toJSON(): { amount: string; currency: string; precision: number } {\n return {\n amount: this.minor.toString(),\n currency: this.currency.code,\n precision: this.currency.decimals,\n };\n }\n\n /**\n * JSON reviver function for deserializing Money objects.\n *\n * Use with `JSON.parse()` to automatically reconstruct Money instances:\n *\n * @param key - The JSON key (unused).\n * @param value - The parsed JSON value.\n * @returns A Money instance if value is a serialized Money object, otherwise the original value.\n * @example\n * const json = '{\"amount\": \"1050\", \"currency\": \"USD\", \"precision\": 2}';\n * const money = JSON.parse(json, Money.reviver);\n * // money is Money instance: $10.50\n */\n static reviver(key: string, value: unknown): unknown {\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"amount\" in value &&\n \"currency\" in value &&\n \"precision\" in value &&\n typeof (value as Record<string, unknown>).amount === \"string\" &&\n typeof (value as Record<string, unknown>).currency === \"string\" &&\n typeof (value as Record<string, unknown>).precision === \"number\"\n ) {\n const obj = value as { amount: string; currency: string; precision: number };\n return Money.fromMinor(BigInt(obj.amount), obj.currency);\n }\n return value;\n }\n\n /**\n * Returns a string representation of the Money object (formatted).\n */\n toString(): string {\n return this.format();\n }\n}\n","import { Money } from \"./Money\";\nimport { Currency } from \"../currency/Currency\";\nimport { getCurrency } from \"../currency/registry\";\nimport { RoundingMode } from \"../rounding\";\n\n/**\n * Handles currency conversion using exchange rates.\n */\nexport class Converter {\n private rates: Record<string, number>;\n private base: string;\n\n /**\n * Creates a new Converter.\n *\n * @param base - The base currency code (e.g., \"USD\").\n * @param rates - A map of currency codes to exchange rates relative to the base.\n * Example: { \"EUR\": 0.85, \"GBP\": 0.75 } (where 1 Base = 0.85 EUR).\n */\n constructor(base: string, rates: Record<string, number>) {\n this.base = base;\n this.rates = { ...rates };\n\n // Ensure base rate is 1\n if (this.rates[base] === undefined) {\n this.rates[base] = 1;\n }\n }\n\n /**\n * Converts a Money object to a target currency.\n *\n * @param money - The Money object to convert.\n * @param toCurrency - The target currency (code or object).\n * @returns A new Money object in the target currency.\n * @throws {Error} If exchange rates are missing.\n */\n convert(money: Money, toCurrency: Currency | string): Money {\n const targetCurrency =\n typeof toCurrency === \"string\" ? getCurrency(toCurrency) : toCurrency;\n\n if (money.currency.code === targetCurrency.code) {\n return money;\n }\n\n const fromRate = this.rates[money.currency.code];\n const toRate = this.rates[targetCurrency.code];\n\n if (fromRate === undefined || toRate === undefined) {\n throw new Error(\n `Exchange rate missing for conversion from ${money.currency.code} to ${targetCurrency.code}`\n );\n }\n\n // Calculate the exchange rate ratio\n const ratio = toRate / fromRate;\n\n // Adjust for difference in decimal places\n // targetMinor = sourceMinor * ratio * 10^(targetDecimals - sourceDecimals)\n const decimalAdjustment =\n 10 ** (targetCurrency.decimals - money.currency.decimals);\n\n // We use the multiply method of Money which handles rounding.\n // Default rounding is usually needed for conversion.\n // We'll use the default rounding (HALF_EVEN is common for money, but Money.multiply requires explicit if fractional).\n // Let's assume standard rounding (HALF_UP) or require options?\n // For ease of use, we should probably default to HALF_UP or similar.\n // But Money.multiply throws if rounding is needed and not provided.\n\n // Let's pass a default rounding mode.\n // We need to import RoundingMode.\n\n const multiplier = ratio * decimalAdjustment;\n\n // We need to access the internal multiply or use the public one.\n // Public one: money.multiply(multiplier, { rounding: 'HALF_EVEN' })\n\n const convertedAmount = money.multiply(multiplier, {\n rounding: RoundingMode.HALF_EVEN,\n });\n return Money.fromMinor(convertedAmount.minor, targetCurrency);\n }\n}\n","import { Money } from \"./Money\";\nimport { Currency } from \"../currency/Currency\";\nimport { Converter } from \"./Converter\";\nimport { getCurrency } from \"../currency/registry\";\n\n/**\n * A collection of Money objects in different currencies.\n * Useful for representing a wallet or portfolio.\n */\nexport class MoneyBag {\n private contents: Map<string, Money> = new Map();\n\n /**\n * Adds a Money amount to the bag.\n * @param money The money to add.\n */\n add(money: Money): void {\n const code = money.currency.code;\n const existing = this.contents.get(code);\n if (existing) {\n this.contents.set(code, existing.add(money));\n } else {\n this.contents.set(code, money);\n }\n }\n\n /**\n * Subtracts a Money amount from the bag.\n * @param money The money to subtract.\n */\n subtract(money: Money): void {\n const code = money.currency.code;\n const existing = this.contents.get(code);\n if (existing) {\n this.contents.set(code, existing.subtract(money));\n } else {\n // If not present, we assume 0 - amount\n const zero = Money.zero(money.currency);\n this.contents.set(code, zero.subtract(money));\n }\n }\n\n /**\n * Gets the amount for a specific currency.\n * @param currency The currency to retrieve.\n * @returns The Money amount in that currency (or zero if not present).\n */\n get(currency: Currency | string): Money {\n const code = typeof currency === \"string\" ? currency : currency.code;\n return (\n this.contents.get(code) ||\n Money.zero(\n typeof currency === \"string\" ? getCurrency(currency) : currency\n )\n );\n }\n\n /**\n * Calculates the total value of the bag in a specific currency.\n *\n * @param targetCurrency The currency to convert everything to.\n * @param converter The converter instance with exchange rates.\n * @returns The total amount in the target currency.\n */\n total(targetCurrency: Currency | string, converter: Converter): Money {\n const target =\n typeof targetCurrency === \"string\"\n ? getCurrency(targetCurrency)\n : targetCurrency;\n let total = Money.zero(target);\n\n for (const money of this.contents.values()) {\n const converted = converter.convert(money, target);\n total = total.add(converted);\n }\n\n return total;\n }\n\n /**\n * Returns a list of all Money objects in the bag.\n */\n getAll(): Money[] {\n return Array.from(this.contents.values());\n }\n\n /**\n * Returns a JSON representation of the bag.\n */\n toJSON(): { amount: string; currency: string; precision: number }[] {\n return this.getAll().map((m) => m.toJSON());\n }\n}\n","import { Currency } from \"./Currency\";\nimport { registerCurrency } from \"./registry\";\n\n// ============================================================================\n// MAJOR WORLD CURRENCIES\n// ============================================================================\n\n/**\n * United States Dollar (USD).\n */\nexport const USD: Currency = {\n code: \"USD\",\n decimals: 2,\n symbol: \"$\",\n locale: \"en-US\",\n};\nregisterCurrency(USD);\n\n/**\n * Euro (EUR).\n */\nexport const EUR: Currency = {\n code: \"EUR\",\n decimals: 2,\n symbol: \"€\",\n locale: \"de-DE\",\n};\nregisterCurrency(EUR);\n\n/**\n * British Pound Sterling (GBP).\n */\nexport const GBP: Currency = {\n code: \"GBP\",\n decimals: 2,\n symbol: \"£\",\n locale: \"en-GB\",\n};\nregisterCurrency(GBP);\n\n/**\n * Japanese Yen (JPY).\n */\nexport const JPY: Currency = {\n code: \"JPY\",\n decimals: 0,\n symbol: \"¥\",\n locale: \"ja-JP\",\n};\nregisterCurrency(JPY);\n\n/**\n * Swiss Franc (CHF).\n */\nexport const CHF: Currency = {\n code: \"CHF\",\n decimals: 2,\n symbol: \"CHF\",\n locale: \"de-CH\",\n};\nregisterCurrency(CHF);\n\n/**\n * Canadian Dollar (CAD).\n */\nexport const CAD: Currency = {\n code: \"CAD\",\n decimals: 2,\n symbol: \"CA$\",\n locale: \"en-CA\",\n};\nregisterCurrency(CAD);\n\n/**\n * Australian Dollar (AUD).\n */\nexport const AUD: Currency = {\n code: \"AUD\",\n decimals: 2,\n symbol: \"A$\",\n locale: \"en-AU\",\n};\nregisterCurrency(AUD);\n\n/**\n * New Zealand Dollar (NZD).\n */\nexport const NZD: Currency = {\n code: \"NZD\",\n decimals: 2,\n symbol: \"NZ$\",\n locale: \"en-NZ\",\n};\nregisterCurrency(NZD);\n\n/**\n * Chinese Yuan Renminbi (CNY).\n */\nexport const CNY: Currency = {\n code: \"CNY\",\n decimals: 2,\n symbol: \"¥\",\n locale: \"zh-CN\",\n};\nregisterCurrency(CNY);\n\n/**\n * Hong Kong Dollar (HKD).\n */\nexport const HKD: Currency = {\n code: \"HKD\",\n decimals: 2,\n symbol: \"HK$\",\n locale: \"zh-HK\",\n};\nregisterCurrency(HKD);\n\n/**\n * Singapore Dollar (SGD).\n */\nexport const SGD: Currency = {\n code: \"SGD\",\n decimals: 2,\n symbol: \"S$\",\n locale: \"en-SG\",\n};\nregisterCurrency(SGD);\n\n/**\n * South Korean Won (KRW).\n */\nexport const KRW: Currency = {\n code: \"KRW\",\n decimals: 0,\n symbol: \"₩\",\n locale: \"ko-KR\",\n};\nregisterCurrency(KRW);\n\n/**\n * Indian Rupee (INR).\n */\nexport const INR: Currency = {\n code: \"INR\",\n decimals: 2,\n symbol: \"₹\",\n locale: \"en-IN\",\n};\nregisterCurrency(INR);\n\n// ============================================================================\n// EUROPEAN CURRENCIES\n// ============================================================================\n\n/**\n * Swedish Krona (SEK).\n */\nexport const SEK: Currency = {\n code: \"SEK\",\n decimals: 2,\n symbol: \"kr\",\n locale: \"sv-SE\",\n};\nregisterCurrency(SEK);\n\n/**\n * Norwegian Krone (NOK).\n */\nexport const NOK: Currency = {\n code: \"NOK\",\n decimals: 2,\n symbol: \"kr\",\n locale: \"nb-NO\",\n};\nregisterCurrency(NOK);\n\n/**\n * Danish Krone (DKK).\n */\nexport const DKK: Currency = {\n code: \"DKK\",\n decimals: 2,\n symbol: \"kr\",\n locale: \"da-DK\",\n};\nregisterCurrency(DKK);\n\n/**\n * Polish Zloty (PLN).\n */\nexport const PLN: Currency = {\n code: \"PLN\",\n decimals: 2,\n symbol: \"zł\",\n locale: \"pl-PL\",\n};\nregisterCurrency(PLN);\n\n/**\n * Czech Koruna (CZK).\n */\nexport const CZK: Currency = {\n code: \"CZK\",\n decimals: 2,\n symbol: \"Kč\",\n locale: \"cs-CZ\",\n};\nregisterCurrency(CZK);\n\n/**\n * Hungarian Forint (HUF).\n */\nexport const HUF: Currency = {\n code: \"HUF\",\n decimals: 2,\n symbol: \"Ft\",\n locale: \"hu-HU\",\n};\nregisterCurrency(HUF);\n\n/**\n * Romanian Leu (RON).\n */\nexport const RON: Currency = {\n code: \"RON\",\n decimals: 2,\n symbol: \"lei\",\n locale: \"ro-RO\",\n};\nregisterCurrency(RON);\n\n/**\n * Bulgarian Lev (BGN).\n */\nexport const BGN: Currency = {\n code: \"BGN\",\n decimals: 2,\n symbol: \"лв\",\n locale: \"bg-BG\",\n};\nregisterCurrency(BGN);\n\n/**\n * Croatian Kuna (HRK).\n * Note: Croatia adopted EUR on Jan 1, 2023, but HRK may still be needed for historical data.\n */\nexport const HRK: Currency = {\n code: \"HRK\",\n decimals: 2,\n symbol: \"kn\",\n locale: \"hr-HR\",\n};\nregisterCurrency(HRK);\n\n/**\n * Turkish Lira (TRY).\n */\nexport const TRY: Currency = {\n code: \"TRY\",\n decimals: 2,\n symbol: \"₺\",\n locale: \"tr-TR\",\n};\nregisterCurrency(TRY);\n\n/**\n * Russian Ruble (RUB).\n */\nexport const RUB: Currency = {\n code: \"RUB\",\n decimals: 2,\n symbol: \"₽\",\n locale: \"ru-RU\",\n};\nregisterCurrency(RUB);\n\n/**\n * Ukrainian Hryvnia (UAH).\n */\nexport const UAH: Currency = {\n code: \"UAH\",\n decimals: 2,\n symbol: \"₴\",\n locale: \"uk-UA\",\n};\nregisterCurrency(UAH);\n\n/**\n * Israeli New Shekel (ILS).\n */\nexport const ILS: Currency = {\n code: \"ILS\",\n decimals: 2,\n symbol: \"₪\",\n locale: \"he-IL\",\n};\nregisterCurrency(ILS);\n\n// ============================================================================\n// AMERICAS\n// ============================================================================\n\n/**\n * Mexican Peso (MXN).\n */\nexport const MXN: Currency = {\n code: \"MXN\",\n decimals: 2,\n symbol: \"MX$\",\n locale: \"es-MX\",\n};\nregisterCurrency(MXN);\n\n/**\n * Brazilian Real (BRL).\n */\nexport const BRL: Currency = {\n code: \"BRL\",\n decimals: 2,\n symbol: \"R$\",\n locale: \"pt-BR\",\n};\nregisterCurrency(BRL);\n\n/**\n * Argentine Peso (ARS).\n */\nexport const ARS: Currency = {\n code: \"ARS\",\n decimals: 2,\n symbol: \"AR$\",\n locale: \"es-AR\",\n};\nregisterCurrency(ARS);\n\n/**\n * Chilean Peso (CLP).\n */\nexport const CLP: Currency = {\n code: \"CLP\",\n decimals: 0,\n symbol: \"CL$\",\n locale: \"es-CL\",\n};\nregisterCurrency(CLP);\n\n/**\n * Colombian Peso (COP).\n */\nexport const COP: Currency = {\n code: \"COP\",\n decimals: 2,\n symbol: \"CO$\",\n locale: \"es-CO\",\n};\nregisterCurrency(COP);\n\n/**\n * Peruvian Sol (PEN).\n */\nexport const PEN: Currency = {\n code: \"PEN\",\n decimals: 2,\n symbol: \"S/\",\n locale: \"es-PE\",\n};\nregisterCurrency(PEN);\n\n// ============================================================================\n// AFRICA\n// ============================================================================\n\n/**\n * South African Rand (ZAR).\n */\nexport const ZAR: Currency = {\n code: \"ZAR\",\n decimals: 2,\n symbol: \"R\",\n locale: \"en-ZA\",\n};\nregisterCurrency(ZAR);\n\n/**\n * Nigerian Naira (NGN).\n */\nexport const NGN: Currency = {\n code: \"NGN\",\n decimals: 2,\n symbol: \"₦\",\n locale: \"en-NG\",\n};\nregisterCurrency(NGN);\n\n/**\n * Kenyan Shilling (KES).\n */\nexport const KES: Currency = {\n code: \"KES\",\n decimals: 2,\n symbol: \"KSh\",\n locale: \"en-KE\",\n};\nregisterCurrency(KES);\n\n/**\n * Egyptian Pound (EGP).\n */\nexport const EGP: Currency = {\n code: \"EGP\",\n decimals: 2,\n symbol: \"E£\",\n locale: \"ar-EG\",\n};\nregisterCurrency(EGP);\n\n/**\n * Moroccan Dirham (MAD).\n */\nexport const MAD: Currency = {\n code: \"MAD\",\n decimals: 2,\n symbol: \"د.م.\",\n locale: \"ar-MA\",\n};\nregisterCurrency(MAD);\n\n/**\n * Ghanaian Cedi (GHS).\n */\nexport const GHS: Currency = {\n code: \"GHS\",\n decimals: 2,\n symbol: \"GH₵\",\n locale: \"en-GH\",\n};\nregisterCurrency(GHS);\n\n/**\n * Tanzanian Shilling (TZS).\n */\nexport const TZS: Currency = {\n code: \"TZS\",\n decimals: 2,\n symbol: \"TSh\",\n locale: \"sw-TZ\",\n};\nregisterCurrency(TZS);\n\n/**\n * Ugandan Shilling (UGX).\n */\nexport const UGX: Currency = {\n code: \"UGX\",\n decimals: 0,\n symbol: \"USh\",\n locale: \"en-UG\",\n};\nregisterCurrency(UGX);\n\n// ============================================================================\n// ASIA-PACIFIC\n// ============================================================================\n\n/**\n * Thai Baht (THB).\n */\nexport const THB: Currency = {\n code: \"THB\",\n decimals: 2,\n symbol: \"฿\",\n locale: \"th-TH\",\n};\nregisterCurrency(THB);\n\n/**\n * Malaysian Ringgit (MYR).\n */\nexport const MYR: Currency = {\n code: \"MYR\",\n decimals: 2,\n symbol: \"RM\",\n locale: \"ms-MY\",\n};\nregisterCurrency(MYR);\n\n/**\n * Indonesian Rupiah (IDR).\n */\nexport const IDR: Currency = {\n code: \"IDR\",\n decimals: 2,\n symbol: \"Rp\",\n locale: \"id-ID\",\n};\nregisterCurrency(IDR);\n\n/**\n * Philippine Peso (PHP).\n */\nexport const PHP: Currency = {\n code: \"PHP\",\n decimals: 2,\n symbol: \"₱\",\n locale: \"en-PH\",\n};\nregisterCurrency(PHP);\n\n/**\n * Vietnamese Dong (VND).\n */\nexport const VND: Currency = {\n code: \"VND\",\n decimals: 0,\n symbol: \"₫\",\n locale: \"vi-VN\",\n};\nregisterCurrency(VND);\n\n/**\n * Taiwan Dollar (TWD).\n */\nexport const TWD: Currency = {\n code: \"TWD\",\n decimals: 2,\n symbol: \"NT$\",\n locale: \"zh-TW\",\n};\nregisterCurrency(TWD);\n\n/**\n * Pakistani Rupee (PKR).\n */\nexport const PKR: Currency = {\n code: \"PKR\",\n decimals: 2,\n symbol: \"₨\",\n locale: \"ur-PK\",\n};\nregisterCurrency(PKR);\n\n/**\n * Bangladeshi Taka (BDT).\n */\nexport const BDT: Currency = {\n code: \"BDT\",\n decimals: 2,\n symbol: \"৳\",\n locale: \"bn-BD\",\n};\nregisterCurrency(BDT);\n\n/**\n * Sri Lankan Rupee (LKR).\n */\nexport const LKR: Currency = {\n code: \"LKR\",\n decimals: 2,\n symbol: \"Rs\",\n locale: \"si-LK\",\n};\nregisterCurrency(LKR);\n\n// ============================================================================\n// MIDDLE EAST\n// ============================================================================\n\n/**\n * United Arab Emirates Dirham (AED).\n */\nexport const AED: Currency = {\n code: \"AED\",\n decimals: 2,\n symbol: \"د.إ\",\n locale: \"ar-AE\",\n};\nregisterCurrency(AED);\n\n/**\n * Saudi Riyal (SAR).\n */\nexport const SAR: Currency = {\n code: \"SAR\",\n decimals: 2,\n symbol: \"﷼\",\n locale: \"ar-SA\",\n};\nregisterCurrency(SAR);\n\n/**\n * Qatari Riyal (QAR).\n */\nexport const QAR: Currency = {\n code: \"QAR\",\n decimals: 2,\n symbol: \"﷼\",\n locale: \"ar-QA\",\n};\nregisterCurrency(QAR);\n\n/**\n * Kuwaiti Dinar (KWD).\n * Note: 3 decimal places (fils).\n */\nexport const KWD: Currency = {\n code: \"KWD\",\n decimals: 3,\n symbol: \"د.ك\",\n locale: \"ar-KW\",\n};\nregisterCurrency(KWD);\n\n/**\n * Bahraini Dinar (BHD).\n * Note: 3 decimal places (fils).\n */\nexport const BHD: Currency = {\n code: \"BHD\",\n decimals: 3,\n symbol: \"د.ب\",\n locale: \"ar-BH\",\n};\nregisterCurrency(BHD);\n\n/**\n * Omani Rial (OMR).\n * Note: 3 decimal places (baisa).\n */\nexport const OMR: Currency = {\n code: \"OMR\",\n decimals: 3,\n symbol: \"﷼\",\n locale: \"ar-OM\",\n};\nregisterCurrency(OMR);\n\n/**\n * Jordanian Dinar (JOD).\n * Note: 3 decimal places (fils).\n */\nexport const JOD: Currency = {\n code: \"JOD\",\n decimals: 3,\n symbol: \"د.ا\",\n locale: \"ar-JO\",\n};\nregisterCurrency(JOD);\n\n// ============================================================================\n// SPECIAL CURRENCIES\n// ============================================================================\n\n/**\n * Icelandic Króna (ISK).\n * Note: 0 decimal places.\n */\nexport const ISK: Currency = {\n code: \"ISK\",\n decimals: 0,\n symbol: \"kr\",\n locale: \"is-IS\",\n};\nregisterCurrency(ISK);\n\n/**\n * Mauritanian Ouguiya (MRU).\n * Note: Uses 2 decimals (khoums), but often displayed without.\n */\nexport const MRU: Currency = {\n code: \"MRU\",\n decimals: 2,\n symbol: \"UM\",\n locale: \"ar-MR\",\n};\nregisterCurrency(MRU);\n\n/**\n * A collection of common currencies.\n * @deprecated Use registry instead. Import individual currencies or use getCurrency().\n */\nexport const CURRENCIES: Record<string, Currency> = {\n // Major world currencies\n USD,\n EUR,\n GBP,\n JPY,\n CHF,\n CAD,\n AUD,\n NZD,\n CNY,\n HKD,\n SGD,\n KRW,\n INR,\n // European\n SEK,\n NOK,\n DKK,\n PLN,\n CZK,\n HUF,\n RON,\n BGN,\n HRK,\n TRY,\n RUB,\n UAH,\n ILS,\n // Americas\n MXN,\n BRL,\n ARS,\n CLP,\n COP,\n PEN,\n // Africa\n ZAR,\n NGN,\n KES,\n EGP,\n MAD,\n GHS,\n TZS,\n UGX,\n // Asia-Pacific\n THB,\n MYR,\n IDR,\n PHP,\n VND,\n TWD,\n PKR,\n BDT,\n LKR,\n // Middle East\n AED,\n SAR,\n QAR,\n KWD,\n BHD,\n OMR,\n JOD,\n // Special\n ISK,\n MRU,\n};\n\n\n","import { Currency } from \"./Currency\";\n\nexport function getMinorUnitExponent(currency: Currency): bigint {\n return 10n ** BigInt(currency.decimals);\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface LoanScheduleEntry {\n period: number;\n payment: Money;\n principal: Money;\n interest: Money;\n balance: Money;\n}\n\nexport interface LoanOptions {\n principal: Money;\n annualRate: number; // e.g., 0.05 for 5%\n periods: number; // Total number of payments\n periodsPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates loan amortization schedule.\n */\nexport function loan(options: LoanOptions): LoanScheduleEntry[] {\n const {\n principal,\n annualRate,\n periods,\n periodsPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const periodicRate = annualRate / periodsPerYear;\n let payment: Money;\n\n if (annualRate === 0) {\n payment = principal.divide(periods, { rounding });\n } else {\n // PMT formula: P * (r(1+r)^n) / ((1+r)^n - 1)\n const r = periodicRate;\n const n = periods;\n const numerator = r * Math.pow(1 + r, n);\n const denominator = Math.pow(1 + r, n) - 1;\n const pmtMultiplier = numerator / denominator;\n payment = principal.multiply(pmtMultiplier, { rounding });\n }\n\n const schedule: LoanScheduleEntry[] = [];\n let balance = principal;\n\n for (let period = 1; period <= periods; period++) {\n const interest =\n annualRate === 0\n ? Money.zero(principal.currency)\n : balance.multiply(periodicRate, { rounding });\n \n let principalPayment = payment.subtract(interest);\n \n // If payment < interest (negative amortization), principal payment is negative.\n // This implementation assumes standard amortization.\n\n balance = balance.subtract(principalPayment);\n\n // Handle final period rounding adjustment\n if (period === periods && !balance.isZero()) {\n const adjustedPrincipal = principalPayment.add(balance);\n schedule.push({\n period,\n payment: interest.add(adjustedPrincipal),\n principal: adjustedPrincipal,\n interest,\n balance: Money.zero(principal.currency),\n });\n } else {\n schedule.push({\n period,\n payment,\n principal: principalPayment,\n interest,\n balance: balance.isNegative()\n ? Money.zero(principal.currency)\n : balance,\n });\n }\n }\n\n return schedule;\n}\n\n/**\n * Calculates monthly payment amount.\n */\nexport function pmt(\n options: Omit<LoanOptions, \"rounding\"> & { rounding?: RoundingMode }\n): Money {\n const schedule = loan(options);\n return schedule[0].payment;\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface CompoundOptions {\n rate: number; // Annual rate (e.g., 0.07 for 7%)\n years: number;\n compoundingPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates future value with compound interest.\n * FV = PV * (1 + r/n)^(n*t)\n */\nexport function futureValue(\n presentValue: Money,\n options: CompoundOptions\n): Money {\n const {\n rate,\n years,\n compoundingPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const n = compoundingPerYear;\n const t = years;\n const multiplier = Math.pow(1 + rate / n, n * t);\n\n return presentValue.multiply(multiplier, { rounding });\n}\n\n/**\n * Calculates present value (discounting).\n * PV = FV / (1 + r/n)^(n*t)\n */\nexport function presentValue(\n futureVal: Money,\n options: CompoundOptions\n): Money {\n const {\n rate,\n years,\n compoundingPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const n = compoundingPerYear;\n const t = years;\n const divisor = Math.pow(1 + rate / n, n * t);\n\n return futureVal.divide(divisor, { rounding });\n}\n\n// Alias for familiarity\nexport const compound = futureValue;\nexport const discount = presentValue;\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\n/**\n * Calculates Net Present Value of cash flows.\n */\nexport function npv(\n discountRate: number,\n cashFlows: Money[] // First is initial investment (usually negative)\n): Money {\n if (cashFlows.length === 0) {\n throw new Error(\"At least one cash flow required\");\n }\n\n const currency = cashFlows[0].currency;\n\n let total = Money.zero(currency);\n\n for (let i = 0; i < cashFlows.length; i++) {\n const discountFactor = Math.pow(1 + discountRate, i);\n const discounted = cashFlows[i].divide(discountFactor, {\n rounding: RoundingMode.HALF_EVEN,\n });\n total = total.add(discounted);\n }\n\n return total;\n}\n\n/**\n * Calculates Internal Rate of Return using Newton-Raphson method.\n * @returns The IRR as a decimal (e.g., 0.12 for 12%)\n */\nexport function irr(cashFlows: Money[], guess: number = 0.1): number {\n const values = cashFlows.map((cf) => Number(cf.minor));\n\n const maxIterations = 100;\n const tolerance = 1e-7;\n let rate = guess;\n\n for (let i = 0; i < maxIterations; i++) {\n let npvValue = 0;\n let derivative = 0;\n\n for (let j = 0; j < values.length; j++) {\n const denominator = Math.pow(1 + rate, j);\n npvValue += values[j] / denominator;\n if (j > 0) {\n derivative -= (j * values[j]) / Math.pow(1 + rate, j + 1);\n }\n }\n\n const newRate = rate - npvValue / derivative;\n\n if (Math.abs(newRate - rate) < tolerance) {\n return newRate;\n }\n\n rate = newRate;\n }\n\n throw new Error(\"IRR calculation did not converge\");\n}\n","/**\n * Represents an interest rate or percentage rate with explicit handling\n * to avoid confusion between percentage and decimal forms.\n *\n * @example\n * const rate = Rate.percent(5); // 5% interest rate\n * const rate2 = Rate.decimal(0.05); // Same as 5%\n *\n * rate.toPercent(); // 5\n * rate.toDecimal(); // 0.05\n *\n * // Safe operations\n * rate.add(Rate.percent(2)); // 7%\n * rate.multiply(2); // 10%\n */\nexport class Rate {\n /**\n * Internal storage as a decimal (e.g., 0.05 for 5%).\n * Uses a scaled BigInt internally for precision.\n */\n private readonly decimalValue: bigint;\n\n /**\n * Scale factor for internal precision (1e18 for 18 decimal places).\n */\n private static readonly SCALE = 10n ** 18n;\n\n private constructor(decimalValue: bigint) {\n this.decimalValue = decimalValue;\n }\n\n /**\n * Creates a Rate from a percentage value (e.g., 5 for 5%).\n *\n * @param percent - The percentage value.\n * @returns A new Rate instance.\n * @example\n * const rate = Rate.percent(5.5); // 5.5%\n */\n static percent(percent: number | string): Rate {\n const decimal = typeof percent === \"string\" ? parseFloat(percent) : percent;\n const scaled = BigInt(Math.round((decimal / 100) * Number(Rate.SCALE)));\n return new Rate(scaled);\n }\n\n /**\n * Creates a Rate from a decimal value (e.g., 0.05 for 5%).\n *\n * @param decimal - The decimal value.\n * @returns A new Rate instance.\n * @example\n * const rate = Rate.decimal(0.055); // 5.5%\n */\n static decimal(decimal: number | string): Rate {\n const value = typeof decimal === \"string\" ? parseFloat(decimal) : decimal;\n const scaled = BigInt(Math.round(value * Number(Rate.SCALE)));\n return new Rate(scaled);\n }\n\n /**\n * Creates a Rate representing zero.\n *\n * @returns A Rate of 0%.\n */\n static zero(): Rate {\n return new Rate(0n);\n }\n\n /**\n * Returns the rate as a percentage (e.g., 5 for 5%).\n *\n * @returns The percentage value as a number.\n */\n toPercent(): number {\n return (Number(this.decimalValue) / Number(Rate.SCALE)) * 100;\n }\n\n /**\n * Returns the rate as a decimal (e.g., 0.05 for 5%).\n *\n * @returns The decimal value as a number.\n */\n toDecimal(): number {\n return Number(this.decimalValue) / Number(Rate.SCALE);\n }\n\n /**\n * Adds another rate to this one.\n *\n * @param other - The rate to add.\n * @returns A new Rate representing the sum.\n */\n add(other: Rate): Rate {\n return new Rate(this.decimalValue + other.decimalValue);\n }\n\n /**\n * Subtracts another rate from this one.\n *\n * @param other - The rate to subtract.\n * @returns A new Rate representing the difference.\n */\n subtract(other: Rate): Rate {\n return new Rate(this.decimalValue - other.decimalValue);\n }\n\n /**\n * Multiplies this rate by a scalar.\n *\n * @param multiplier - The number to multiply by.\n * @returns A new Rate representing the product.\n */\n multiply(multiplier: number): Rate {\n const scaled = BigInt(Math.round(multiplier * Number(Rate.SCALE)));\n return new Rate((this.decimalValue * scaled) / Rate.SCALE);\n }\n\n /**\n * Divides this rate by a divisor.\n *\n * @param divisor - The number to divide by.\n * @returns A new Rate representing the quotient.\n */\n divide(divisor: number): Rate {\n const scaled = BigInt(Math.round(divisor * Number(Rate.SCALE)));\n return new Rate((this.decimalValue * Rate.SCALE) / scaled);\n }\n\n /**\n * Checks if this rate equals another.\n *\n * @param other - The rate to compare.\n * @returns True if the rates are equal.\n */\n equals(other: Rate): boolean {\n return this.decimalValue === other.decimalValue;\n }\n\n /**\n * Checks if this rate is greater than another.\n *\n * @param other - The rate to compare.\n * @returns True if this rate is greater.\n */\n greaterThan(other: Rate): boolean {\n return this.decimalValue > other.decimalValue;\n }\n\n /**\n * Checks if this rate is less than another.\n *\n * @param other - The rate to compare.\n * @returns True if this rate is less.\n */\n lessThan(other: Rate): boolean {\n return this.decimalValue < other.decimalValue;\n }\n\n /**\n * Checks if this rate is zero.\n *\n * @returns True if the rate is 0%.\n */\n isZero(): boolean {\n return this.decimalValue === 0n;\n }\n\n /**\n * Checks if this rate is negative.\n *\n * @returns True if the rate is negative.\n */\n isNegative(): boolean {\n return this.decimalValue < 0n;\n }\n\n /**\n * Returns a string representation of the rate as a percentage.\n *\n * @returns The rate as a percentage string (e.g., \"5.5%\").\n */\n toString(): string {\n return `${this.toPercent()}%`;\n }\n\n /**\n * Computes compound factor: (1 + rate)^periods.\n *\n * @param periods - The number of compounding periods.\n * @returns The compound factor as a number.\n * @example\n * Rate.percent(10).compoundFactor(3); // (1.10)^3 = 1.331\n */\n compoundFactor(periods: number): number {\n return Math.pow(1 + this.toDecimal(), periods);\n }\n\n /**\n * Returns the periodic rate for a given frequency.\n *\n * @param periodsPerYear - Number of periods per year (e.g., 12 for monthly).\n * @returns A new Rate representing the periodic rate.\n * @example\n * Rate.percent(12).periodic(12); // 1% monthly\n */\n periodic(periodsPerYear: number): Rate {\n return this.divide(periodsPerYear);\n }\n\n /**\n * Converts an effective rate to a nominal rate.\n *\n * @param periodsPerYear - Number of compounding periods per year.\n * @returns The nominal annual rate.\n */\n toNominal(periodsPerYear: number): Rate {\n const effectiveDecimal = this.toDecimal();\n const nominalDecimal =\n periodsPerYear * (Math.pow(1 + effectiveDecimal, 1 / periodsPerYear) - 1);\n return Rate.decimal(nominalDecimal);\n }\n\n /**\n * Converts a nominal rate to an effective annual rate.\n *\n * @param periodsPerYear - Number of compounding periods per year.\n * @returns The effective annual rate.\n */\n toEffective(periodsPerYear: number): Rate {\n const nominalDecimal = this.toDecimal();\n const effectiveDecimal =\n Math.pow(1 + nominalDecimal / periodsPerYear, periodsPerYear) - 1;\n return Rate.decimal(effectiveDecimal);\n }\n\n /**\n * Returns a JSON representation.\n */\n toJSON(): { percent: number; decimal: number } {\n return {\n percent: this.toPercent(),\n decimal: this.toDecimal(),\n };\n }\n}\n","import { Entry } from \"./types\";\n\n/**\n * SHA-256 hash function that works in both Node.js and browsers.\n */\nlet hashFunction: ((data: string) => string | Promise<string>) | null = null;\n\n/**\n * Initializes the hash function based on the environment.\n * Uses Node.js crypto if available, falls back to SubtleCrypto for browsers.\n */\nfunction getHashFunction(): (data: string) => string | Promise<string> {\n if (hashFunction) return hashFunction;\n\n // Try Node.js crypto first\n if (typeof globalThis !== \"undefined\") {\n try {\n // Dynamic import to avoid bundler issues\n const nodeCrypto = require(\"crypto\");\n if (nodeCrypto && nodeCrypto.createHash) {\n hashFunction = (data: string): string => {\n return nodeCrypto.createHash(\"sha256\").update(data).digest(\"hex\");\n };\n return hashFunction;\n }\n } catch {\n // Node crypto not available\n }\n }\n\n // Fall back to SubtleCrypto (browser)\n if (\n typeof globalThis !== \"undefined\" &&\n globalThis.crypto &&\n globalThis.crypto.subtle\n ) {\n hashFunction = async (data: string): Promise<string> => {\n const encoder = new TextEncoder();\n const dataBuffer = encoder.encode(data);\n const hashBuffer = await globalThis.crypto.subtle.digest(\n \"SHA-256\",\n dataBuffer\n );\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n };\n return hashFunction;\n }\n\n // No crypto available\n throw new Error(\n \"No cryptographic hash function available. \" +\n \"Ensure you are running in Node.js or a browser with SubtleCrypto support.\"\n );\n}\n\n/**\n * Allows injecting a custom hash function for testing or special environments.\n */\nexport function setHashFunction(\n fn: (data: string) => string | Promise<string>\n): void {\n hashFunction = fn;\n}\n\nfunction serialize(data: unknown): string {\n return JSON.stringify(data, (_key, value) => {\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n // Handle Money objects if they are passed directly and not via toJSON\n if (\n value &&\n typeof value === \"object\" &&\n \"minor\" in value &&\n \"currency\" in value\n ) {\n return {\n minor: (value as { minor: bigint }).minor.toString(),\n currency: (value as { currency: { code: string } }).currency.code,\n };\n }\n return value;\n });\n}\n\n/**\n * Generates a SHA-256 hash of the provided data.\n * Works in both Node.js and browser environments.\n *\n * @param data - The data to hash.\n * @returns The hash as a hex string (sync in Node.js, may be async in browser).\n */\nexport function generateHash(data: unknown): string | Promise<string> {\n const serialized = serialize(data);\n const fn = getHashFunction();\n return fn(serialized);\n}\n\n/**\n * Synchronous version of generateHash for environments that support it.\n * Throws if only async hashing is available (browser without await).\n *\n * @param data - The data to hash.\n * @returns The hash as a hex string.\n */\nexport function generateHashSync(data: unknown): string {\n const result = generateHash(data);\n if (result instanceof Promise) {\n throw new Error(\n \"Synchronous hashing not available in this environment. \" +\n \"Use generateHash() with await instead.\"\n );\n }\n return result;\n}\n\n/**\n * Verifies the integrity of a chain of ledger entries.\n * Checks that each entry's hash is correct and that previousHash pointers form a valid chain.\n *\n * @param entries - The entries to verify.\n * @returns True if the chain is valid, false if tampered.\n */\nexport async function verifyChain(entries: Entry[]): Promise<boolean> {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const previousEntry = i > 0 ? entries[i - 1] : null;\n\n // Check previous hash pointer\n if (previousEntry) {\n if (entry.previousHash !== previousEntry.hash) return false;\n } else {\n if (entry.previousHash !== null) return false;\n }\n\n // Check integrity of current entry\n const { hash, ...content } = entry;\n const calculatedHash = await generateHash(content);\n\n if (hash !== calculatedHash) return false;\n }\n return true;\n}\n\n/**\n * Synchronous version of verifyChain for Node.js environments.\n *\n * @param entries - The entries to verify.\n * @returns True if the chain is valid.\n */\nexport function verifyChainSync(entries: Entry[]): boolean {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const previousEntry = i > 0 ? entries[i - 1] : null;\n\n if (previousEntry) {\n if (entry.previousHash !== previousEntry.hash) return false;\n } else {\n if (entry.previousHash !== null) return false;\n }\n\n const { hash, ...content } = entry;\n const calculatedHash = generateHashSync(content);\n\n if (hash !== calculatedHash) return false;\n }\n return true;\n}\n","import { Money } from \"../money/Money\";\nimport { Currency } from \"../currency/Currency\";\nimport { CurrencyMismatchError } from \"../errors/CurrencyMismatchError\";\nimport {\n Entry,\n TransactionMetadata,\n LedgerSnapshot,\n TransactionType,\n} from \"./types\";\nimport {\n generateHash,\n generateHashSync,\n verifyChain,\n verifyChainSync,\n} from \"./verification\";\nimport { randomUUID } from \"crypto\";\n\n/**\n * Current snapshot format version.\n */\nconst SNAPSHOT_VERSION = 2;\n\nexport class Ledger {\n private entries: Entry[] = [];\n private currency: string;\n\n constructor(currency: string | Currency) {\n this.currency = typeof currency === \"string\" ? currency : currency.code;\n }\n\n /**\n * Records a transaction in the ledger.\n * Returns the created entry for reference.\n * Note: This is the synchronous version for Node.js. Use recordAsync for browser support.\n */\n record(money: Money, metadata: TransactionMetadata): Entry {\n if (money.currency.code !== this.currency) {\n throw new CurrencyMismatchError(this.currency, money.currency.code);\n }\n\n const previousHash =\n this.entries.length > 0\n ? this.entries[this.entries.length - 1].hash\n : null;\n\n // Construct the entry content first\n const content = {\n id: randomUUID(),\n money,\n metadata: Object.freeze({\n ...metadata,\n timestamp: metadata.timestamp ?? new Date(),\n }),\n createdAt: new Date(),\n previousHash,\n };\n\n // Calculate hash (sync)\n const hash = generateHashSync(content);\n\n // Create full entry\n const entry: Entry = {\n ...content,\n hash,\n };\n\n this.entries.push(Object.freeze(entry)); // Immutable\n\n return entry;\n }\n\n /**\n * Records a transaction in the ledger (async version for browser support).\n * Returns the created entry for reference.\n */\n async recordAsync(money: Money, metadata: TransactionMetadata): Promise<Entry> {\n if (money.currency.code !== this.currency) {\n throw new CurrencyMismatchError(this.currency, money.currency.code);\n }\n\n const previousHash =\n this.entries.length > 0\n ? this.entries[this.entries.length - 1].hash\n : null;\n\n const content = {\n id: randomUUID(),\n money,\n metadata: Object.freeze({\n ...metadata,\n timestamp: metadata.timestamp ?? new Date(),\n }),\n createdAt: new Date(),\n previousHash,\n };\n\n const hash = await generateHash(content);\n\n const entry: Entry = {\n ...content,\n hash: typeof hash === \"string\" ? hash : await hash,\n };\n\n this.entries.push(Object.freeze(entry));\n\n return entry;\n }\n\n /**\n * Gets the current balance.\n */\n getBalance(): Money {\n return this.entries.reduce(\n (balance, entry) => balance.add(entry.money),\n Money.zero(this.currency)\n );\n }\n\n /**\n * Returns the complete transaction history.\n */\n getHistory(): ReadonlyArray<Entry> {\n return Object.freeze([...this.entries]);\n }\n\n /**\n * Filters entries by criteria.\n */\n query(filter: {\n type?: TransactionType | TransactionType[];\n from?: Date;\n to?: Date;\n reference?: string;\n minAmount?: Money;\n maxAmount?: Money;\n tags?: string[];\n }): Entry[] {\n return this.entries.filter((entry) => {\n if (filter.type) {\n const types = Array.isArray(filter.type) ? filter.type : [filter.type];\n if (!types.includes(entry.metadata.type)) return false;\n }\n if (filter.from && entry.createdAt < filter.from) return false;\n if (filter.to && entry.createdAt > filter.to) return false;\n if (filter.reference && entry.metadata.reference !== filter.reference)\n return false;\n if (filter.minAmount && entry.money.lessThan(filter.minAmount))\n return false;\n if (filter.maxAmount && entry.money.greaterThan(filter.maxAmount))\n return false;\n if (filter.tags && entry.metadata.tags) {\n const hasTag = filter.tags.some((tag) =>\n entry.metadata.tags?.includes(tag)\n );\n if (!hasTag) return false;\n }\n return true;\n });\n }\n\n /**\n * Verifies the integrity of the ledger using hash chain (sync version).\n * @returns true if all hashes are valid and chain is unbroken.\n */\n verify(): boolean {\n return verifyChainSync(this.entries);\n }\n\n /**\n * Verifies the integrity of the ledger using hash chain (async version for browsers).\n * @returns Promise resolving to true if all hashes are valid and chain is unbroken.\n */\n async verifyAsync(): Promise<boolean> {\n return verifyChain(this.entries);\n }\n\n /**\n * Exports a snapshot for backup/audit purposes (sync version).\n */\n snapshot(): LedgerSnapshot {\n return {\n version: SNAPSHOT_VERSION,\n entries: [...this.entries],\n balance: this.getBalance(),\n currency: this.currency,\n createdAt: new Date(),\n checksum: generateHashSync({ entries: this.entries }),\n };\n }\n\n /**\n * Exports a snapshot for backup/audit purposes (async version for browsers).\n */\n async snapshotAsync(): Promise<LedgerSnapshot> {\n const checksum = await generateHash({ entries: this.entries });\n return {\n version: SNAPSHOT_VERSION,\n entries: [...this.entries],\n balance: this.getBalance(),\n currency: this.currency,\n createdAt: new Date(),\n checksum: typeof checksum === \"string\" ? checksum : await checksum,\n };\n }\n\n /**\n * Restores from a snapshot (sync version).\n */\n static fromSnapshot(snapshot: LedgerSnapshot): Ledger {\n const ledger = new Ledger(snapshot.currency);\n // Verify integrity before restoring\n if (!verifyChainSync(snapshot.entries)) {\n throw new Error(\"Ledger snapshot integrity check failed\");\n }\n ledger.entries = [...snapshot.entries];\n return ledger;\n }\n\n /**\n * Restores from a snapshot (async version for browsers).\n */\n static async fromSnapshotAsync(snapshot: LedgerSnapshot): Promise<Ledger> {\n const ledger = new Ledger(snapshot.currency);\n // Verify integrity before restoring\n const isValid = await verifyChain(snapshot.entries);\n if (!isValid) {\n throw new Error(\"Ledger snapshot integrity check failed\");\n }\n ledger.entries = [...snapshot.entries];\n return ledger;\n }\n}\n","import { Money } from \"./money\";\nimport { Currency } from \"./currency\";\n\nexport * from \"./money\";\nexport * from \"./currency\";\nexport * from \"./rounding\";\nexport * from \"./errors\";\nexport * from \"./financial\";\nexport * from \"./ledger\";\nexport * from \"./format/formatter\";\nexport * from \"./format/parser\";\n\n/**\n * Helper function to create Money instances.\n *\n * If amount is a number or BigInt, it is treated as minor units.\n * If amount is a string, it is treated as major units.\n *\n * @param amount - The amount (minor units if number/bigint, major units if string).\n * @param currency - The currency code or object.\n */\nexport function money(\n amount: number | bigint | string,\n currency: string | Currency\n): Money {\n if (typeof amount === \"string\") {\n return Money.fromMajor(amount, currency);\n }\n return Money.fromMinor(amount, currency);\n}\n"],"mappings":"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","names":["RoundingMode","MonetraErrorCode","money","money","money","money","presentValue","money"]}
1
+ {"version":3,"sources":["../src/currency/registry.ts","../src/rounding/strategies.ts","../src/errors/BaseError.ts","../src/errors/CurrencyMismatchError.ts","../src/errors/InvalidPrecisionError.ts","../src/errors/RoundingRequiredError.ts","../src/errors/InsufficientFundsError.ts","../src/errors/InvalidArgumentError.ts","../src/errors/OverflowError.ts","../src/money/guards.ts","../src/rounding/index.ts","../src/money/arithmetic.ts","../src/money/allocation.ts","../src/format/parser.ts","../src/format/formatter.ts","../src/money/Money.ts","../src/money/Converter.ts","../src/money/MoneyBag.ts","../src/currency/iso4217.ts","../src/currency/precision.ts","../src/financial/loan.ts","../src/financial/compound.ts","../src/financial/investment.ts","../src/financial/rate.ts","../src/financial/simple.ts","../src/financial/leverage.ts","../src/financial/depreciation.ts","../src/ledger/verification.ts","../src/ledger/Ledger.ts","../src/index.ts"],"sourcesContent":["import { Currency } from \"./Currency\";\n\nconst registry: Map<string, Currency> = new Map();\n\n/**\n * Registers a currency in the global registry.\n * @param currency The currency to register.\n */\nexport function registerCurrency(currency: Currency): void {\n registry.set(currency.code, currency);\n}\n\n/**\n * Retrieves a currency by its code.\n * @param code The currency code (e.g., \"USD\").\n * @returns The Currency object.\n * @throws Error if the currency is not found.\n */\nexport function getCurrency(code: string): Currency {\n const currency = registry.get(code);\n if (!currency) {\n throw new Error(`Currency '${code}' not found in registry.`);\n }\n return currency;\n}\n\n/**\n * Checks if a currency is registered.\n */\nexport function isCurrencyRegistered(code: string): boolean {\n return registry.has(code);\n}\n\n/**\n * Returns all registered currencies as a map.\n * @internal Use for testing only.\n */\nexport function getAllCurrencies(): Record<string, Currency> {\n return Object.fromEntries(registry);\n}\n","/**\n * Enumeration of rounding modes for handling fractional minor units.\n */\nexport enum RoundingMode {\n /**\n * Rounds towards the nearest neighbor. If equidistant, rounds away from zero.\n * Example: 2.5 -> 3, -2.5 -> -3\n */\n HALF_UP = \"HALF_UP\",\n\n /**\n * Rounds towards the nearest neighbor. If equidistant, rounds towards zero.\n * Example: 2.5 -> 2, -2.5 -> -2\n */\n HALF_DOWN = \"HALF_DOWN\",\n\n /**\n * Rounds towards the nearest neighbor. If equidistant, rounds towards the nearest even integer.\n * Also known as Banker's Rounding.\n * Example: 2.5 -> 2, 3.5 -> 4\n */\n HALF_EVEN = \"HALF_EVEN\",\n\n /**\n * Rounds towards negative infinity.\n * Example: 2.9 -> 2, -2.1 -> -3\n */\n FLOOR = \"FLOOR\",\n\n /**\n * Rounds towards positive infinity.\n * Example: 2.1 -> 3, -2.9 -> -2\n */\n CEIL = \"CEIL\",\n\n /**\n * Truncates towards zero (removes fractional part).\n * Example: 2.9 -> 2, -2.9 -> -2\n */\n TRUNCATE = \"TRUNCATE\",\n}\n","/**\n * Error codes for programmatic handling of Monetra errors.\n */\nexport enum MonetraErrorCode {\n CURRENCY_MISMATCH = \"MONETRA_CURRENCY_MISMATCH\",\n INSUFFICIENT_FUNDS = \"MONETRA_INSUFFICIENT_FUNDS\",\n INVALID_ARGUMENT = \"MONETRA_INVALID_ARGUMENT\",\n INVALID_PRECISION = \"MONETRA_INVALID_PRECISION\",\n OVERFLOW = \"MONETRA_OVERFLOW\",\n ROUNDING_REQUIRED = \"MONETRA_ROUNDING_REQUIRED\",\n}\n\n/**\n * Base error class for all Monetra errors.\n * All Monetra errors include an error code for programmatic handling.\n */\nexport class MonetraError extends Error {\n /**\n * A unique error code for programmatic handling.\n */\n readonly code: MonetraErrorCode;\n\n constructor(message: string, code: MonetraErrorCode) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class CurrencyMismatchError extends MonetraError {\n /**\n * The expected currency code.\n */\n readonly expected: string;\n\n /**\n * The received currency code.\n */\n readonly received: string;\n\n constructor(expected: string, received: string) {\n super(\n `Currency mismatch: expected ${expected}, received ${received}.\\n` +\n `💡 Tip: Use a Converter to convert between currencies:\\n` +\n ` const converter = new Converter('USD', { ${received}: rate });\\n` +\n ` const converted = converter.convert(money, '${expected}');`,\n MonetraErrorCode.CURRENCY_MISMATCH,\n );\n this.expected = expected;\n this.received = received;\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InvalidPrecisionError extends MonetraError {\n constructor(message: string) {\n super(message, MonetraErrorCode.INVALID_PRECISION);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class RoundingRequiredError extends MonetraError {\n constructor(operation?: string, result?: number) {\n let message =\n \"Rounding is required for this operation but was not provided.\";\n if (operation && result !== undefined) {\n message =\n `Rounding required for ${operation}: result ${result} is not an integer.\\n` +\n `💡 Tip: Provide a rounding mode:\\n` +\n ` money.${operation}(value, { rounding: RoundingMode.HALF_UP })\\n` +\n ` Available modes: HALF_UP, HALF_DOWN, HALF_EVEN, FLOOR, CEIL, TRUNCATE`;\n }\n super(message, MonetraErrorCode.ROUNDING_REQUIRED);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InsufficientFundsError extends MonetraError {\n constructor(message?: string) {\n super(\n message || \"Insufficient funds for this operation.\",\n MonetraErrorCode.INSUFFICIENT_FUNDS,\n );\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class InvalidArgumentError extends MonetraError {\n constructor(message: string) {\n super(message, MonetraErrorCode.INVALID_ARGUMENT);\n }\n}\n","import { MonetraError, MonetraErrorCode } from \"./BaseError\";\n\nexport class OverflowError extends MonetraError {\n constructor(message: string = \"Arithmetic overflow\") {\n super(message, MonetraErrorCode.OVERFLOW);\n }\n}\n","import { Money } from \"./Money\";\nimport { CurrencyMismatchError, InsufficientFundsError } from \"../errors\";\n\nexport function assertSameCurrency(a: Money, b: Money): void {\n if (a.currency.code !== b.currency.code) {\n throw new CurrencyMismatchError(a.currency.code, b.currency.code);\n }\n}\n\nexport function assertNonNegative(money: Money): void {\n if (money.isNegative()) {\n // Spec doesn't explicitly name a NegativeError, but InsufficientFundsError might fit or just a generic error.\n // Spec lists \"InsufficientFundsError\" in 4.7.\n // But \"assertNonNegative\" is a guard.\n // Let's throw an Error or a specific one if defined.\n // \"Any violation is considered a bug\" -> maybe just Error?\n // But for \"InsufficientFunds\", that's usually when subtracting.\n // Let's use a generic Error for now or create a specific one if needed.\n throw new Error(\"Money value must be non-negative\");\n }\n}\n","import { RoundingMode } from \"./strategies\";\n\nexport * from \"./strategies\";\n\nexport function divideWithRounding(\n numerator: bigint,\n denominator: bigint,\n mode: RoundingMode,\n): bigint {\n if (denominator === 0n) {\n throw new Error(\"Division by zero\");\n }\n\n const quotient = numerator / denominator;\n const remainder = numerator % denominator;\n\n if (remainder === 0n) {\n return quotient;\n }\n\n const isNegativeResult = numerator < 0n !== denominator < 0n;\n const isPositiveResult = !isNegativeResult;\n\n const absRemainder = remainder < 0n ? -remainder : remainder;\n const absDenominator = denominator < 0n ? -denominator : denominator;\n\n // Check for exact half\n const isHalf = absRemainder * 2n === absDenominator;\n const isMoreThanHalf = absRemainder * 2n > absDenominator;\n\n switch (mode) {\n case RoundingMode.FLOOR:\n // If positive, quotient is already floor (truncation).\n // If negative, quotient is ceil (truncation towards zero), so we need to subtract 1.\n return isPositiveResult ? quotient : quotient - 1n;\n case RoundingMode.CEIL:\n // If positive, quotient is floor, so add 1.\n // If negative, quotient is ceil, so keep it.\n return isPositiveResult ? quotient + 1n : quotient;\n case RoundingMode.HALF_UP:\n if (isMoreThanHalf || isHalf) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n return quotient;\n case RoundingMode.HALF_DOWN:\n if (isMoreThanHalf) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n return quotient;\n case RoundingMode.HALF_EVEN:\n if (isMoreThanHalf) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n if (isHalf) {\n // If quotient is odd, round up (away from zero? no, to nearest even).\n // If quotient is even, keep it.\n if (quotient % 2n !== 0n) {\n return isPositiveResult ? quotient + 1n : quotient - 1n;\n }\n }\n return quotient;\n case RoundingMode.TRUNCATE:\n // Truncate towards zero (simply return the quotient without adjustment)\n return quotient;\n default:\n throw new Error(`Unsupported rounding mode: ${mode}`);\n }\n}\n","import { RoundingMode, divideWithRounding } from \"../rounding\";\nimport { RoundingRequiredError } from \"../errors\";\n\n/**\n * Adds two BigInt values.\n */\nexport function add(a: bigint, b: bigint): bigint {\n return a + b;\n}\n\n/**\n * Subtracts two BigInt values.\n */\nexport function subtract(a: bigint, b: bigint): bigint {\n return a - b;\n}\n\n/**\n * Multiplies a BigInt amount by a multiplier.\n *\n * Handles fractional multipliers by converting them to a rational number (numerator/denominator).\n * If the result is not an integer, a rounding mode must be provided.\n *\n * @param amount - The amount to multiply.\n * @param multiplier - The multiplier (number or string).\n * @param rounding - Optional rounding mode.\n * @returns The result as a BigInt.\n * @throws {RoundingRequiredError} If rounding is needed but not provided.\n */\nexport function multiply(\n amount: bigint,\n multiplier: string | number,\n rounding?: RoundingMode,\n): bigint {\n const { numerator, denominator } = parseMultiplier(multiplier);\n\n // result = amount * (numerator / denominator)\n // result = (amount * numerator) / denominator\n\n const product = amount * numerator;\n\n if (product % denominator === 0n) {\n return product / denominator;\n }\n\n if (!rounding) {\n throw new RoundingRequiredError(\n \"multiply\",\n Number(product) / Number(denominator),\n );\n }\n\n return divideWithRounding(product, denominator, rounding);\n}\n\n/**\n * Divides a BigInt amount by a divisor.\n *\n * @param amount - The amount to divide.\n * @param divisor - The divisor (number or string).\n * @param rounding - Optional rounding mode.\n * @returns The result as a BigInt.\n * @throws {RoundingRequiredError} If rounding is needed but not provided.\n */\nexport function divide(\n amount: bigint,\n divisor: string | number,\n rounding?: RoundingMode,\n): bigint {\n const { numerator, denominator } = parseMultiplier(divisor);\n\n // result = amount / (numerator / denominator)\n // result = (amount * denominator) / numerator\n\n const product = amount * denominator;\n\n if (product % numerator === 0n) {\n return product / numerator;\n }\n\n if (!rounding) {\n throw new RoundingRequiredError(\n \"divide\",\n Number(product) / Number(numerator),\n );\n }\n\n return divideWithRounding(product, numerator, rounding);\n}\n\nfunction parseMultiplier(multiplier: string | number): {\n numerator: bigint;\n denominator: bigint;\n} {\n const s = multiplier.toString();\n\n // Check for scientific notation\n if (/[eE]/.test(s)) {\n throw new Error(\"Scientific notation not supported\");\n }\n\n const parts = s.split(\".\");\n if (parts.length > 2) {\n throw new Error(\"Invalid number format\");\n }\n\n const integerPart = parts[0];\n const fractionalPart = parts[1] || \"\";\n\n const denominator = 10n ** BigInt(fractionalPart.length);\n const numerator = BigInt(integerPart + fractionalPart);\n\n return { numerator, denominator };\n}\n","/**\n * Allocates a monetary amount according to a list of ratios.\n *\n * Uses the \"Largest Remainder Method\" to ensure that the sum of the allocated\n * parts equals the original amount. Remainders are distributed to the parts\n * that had the largest fractional remainders during the division.\n *\n * @param amount - The total amount to allocate (in minor units).\n * @param ratios - An array of ratios (e.g., [1, 1] for 50/50 split).\n * @returns An array of allocated amounts (in minor units).\n * @throws {Error} If ratios are empty or total ratio is zero.\n */\nexport function allocate(amount: bigint, ratios: number[]): bigint[] {\n if (ratios.length === 0) {\n throw new Error(\"Cannot allocate to empty ratios\");\n }\n\n // Scale ratios to integers\n const scaledRatios = ratios.map((r) => {\n const s = r.toString();\n if (/[eE]/.test(s)) throw new Error(\"Scientific notation not supported\");\n const parts = s.split(\".\");\n const decimals = parts[1] ? parts[1].length : 0;\n const value = BigInt(parts[0] + (parts[1] || \"\"));\n return { value, decimals };\n });\n\n const maxDecimals = Math.max(...scaledRatios.map((r) => r.decimals));\n\n const normalizedRatios = scaledRatios.map((r) => {\n const factor = 10n ** BigInt(maxDecimals - r.decimals);\n return r.value * factor;\n });\n\n const total = normalizedRatios.reduce((sum, r) => sum + r, 0n);\n\n if (total === 0n) {\n throw new Error(\"Total ratio must be greater than zero\");\n }\n\n const results: { share: bigint; remainder: bigint; index: number }[] = [];\n let allocatedTotal = 0n;\n\n for (let i = 0; i < normalizedRatios.length; i++) {\n const ratio = normalizedRatios[i];\n const share = (amount * ratio) / total;\n const remainder = (amount * ratio) % total;\n\n results.push({ share, remainder, index: i });\n allocatedTotal += share;\n }\n\n let leftOver = amount - allocatedTotal;\n\n // Distribute leftover to those with largest remainder\n // Sort by remainder desc\n results.sort((a, b) => {\n if (b.remainder > a.remainder) return 1;\n if (b.remainder < a.remainder) return -1;\n return 0;\n });\n\n for (let i = 0; i < Number(leftOver); i++) {\n results[i].share += 1n;\n }\n\n // Sort back by index\n results.sort((a, b) => a.index - b.index);\n\n return results.map((r) => r.share);\n}\n","import { Currency } from \"../currency/Currency\";\nimport { InvalidPrecisionError } from \"../errors\";\n\n/**\n * Options for locale-aware parsing.\n */\nexport interface LocaleParseOptions {\n /**\n * The locale to use for parsing (e.g., \"en-US\", \"de-DE\").\n * Used to detect decimal and grouping separators.\n */\n locale: string;\n}\n\n/**\n * Parses a locale-formatted string into a normalized decimal string.\n *\n * Handles locale-specific decimal separators (e.g., comma in German \"1.234,56\")\n * and grouping separators (e.g., period in German \"1.234\").\n *\n * @param amount - The locale-formatted amount string (e.g., \"1,234.56\" or \"1.234,56\").\n * @param options - The locale options.\n * @returns A normalized decimal string (e.g., \"1234.56\").\n * @example\n * parseLocaleString(\"1.234,56\", { locale: \"de-DE\" }); // \"1234.56\"\n * parseLocaleString(\"1,234.56\", { locale: \"en-US\" }); // \"1234.56\"\n */\nexport function parseLocaleString(\n amount: string,\n options: LocaleParseOptions,\n): string {\n // Use Intl.NumberFormat to determine the locale's separators\n const parts = new Intl.NumberFormat(options.locale, {\n style: \"decimal\",\n minimumFractionDigits: 1,\n useGrouping: true,\n }).formatToParts(1234.5);\n\n let decimalSeparator = \".\";\n let groupSeparator = \",\";\n\n for (const part of parts) {\n if (part.type === \"decimal\") {\n decimalSeparator = part.value;\n } else if (part.type === \"group\") {\n groupSeparator = part.value;\n }\n }\n\n // Handle the case where group and decimal separators are the same\n // (shouldn't happen, but be defensive)\n if (groupSeparator === decimalSeparator) {\n throw new Error(\n `Invalid locale configuration: group and decimal separators are the same for locale ${options.locale}`,\n );\n }\n\n // Remove currency symbols and whitespace\n let normalized = amount.replace(/[^\\d.,\\-\\s]/g, \"\").trim();\n\n // Handle negative sign\n const isNegative = normalized.startsWith(\"-\") || amount.includes(\"(\");\n normalized = normalized.replace(/[-()]/g, \"\");\n\n // Remove all grouping separators\n normalized = normalized.split(groupSeparator).join(\"\");\n\n // Replace locale decimal separator with standard period\n normalized = normalized.split(decimalSeparator).join(\".\");\n\n return isNegative ? `-${normalized}` : normalized;\n}\n\n/**\n * Parses a locale-formatted amount string and converts it to Money minor units.\n *\n * This is a convenience function that combines locale parsing with currency validation.\n *\n * @param amount - The locale-formatted amount string.\n * @param currency - The currency to validate against.\n * @param options - The locale options.\n * @returns The amount in minor units as a BigInt.\n * @throws {InvalidPrecisionError} If the precision exceeds the currency's decimals.\n * @example\n * parseLocaleToMinor(\"1.234,56\", EUR, { locale: \"de-DE\" }); // 123456n\n */\nexport function parseLocaleToMinor(\n amount: string,\n currency: Currency,\n options: LocaleParseOptions,\n): bigint {\n const normalized = parseLocaleString(amount, options);\n return parseToMinor(normalized, currency);\n}\n\n/**\n * Parses a string representation of a major unit amount into minor units.\n *\n * Validates the input format to ensure it is a valid decimal number without\n * scientific notation or ambiguous characters. Checks that the precision\n * does not exceed the currency's allowed decimals.\n *\n * @param amount - The amount string (e.g., \"10.50\").\n * @param currency - The currency to validate against.\n * @returns The amount in minor units as a BigInt.\n * @throws {Error} If the format is invalid (scientific notation, non-numeric chars).\n * @throws {InvalidPrecisionError} If the precision exceeds the currency's decimals.\n */\nexport function parseToMinor(amount: string, currency: Currency): bigint {\n // Validate format\n if (/[eE]/.test(amount)) {\n throw new Error(\"Scientific notation not supported\");\n }\n\n // Reject ambiguous separators (commas, spaces, etc.)\n if (/[^0-9.-]/.test(amount)) {\n throw new Error(\"Invalid characters in amount\");\n }\n\n // Reject inputs with no digits (e.g. \"-\" or \"\")\n if (!/[0-9]/.test(amount)) {\n throw new Error(\"Invalid format\");\n }\n\n const parts = amount.split(\".\");\n if (parts.length > 2) {\n throw new Error(\"Invalid format: multiple decimal points\");\n }\n\n const integerPart = parts[0];\n const fractionalPart = parts[1] || \"\";\n\n if (fractionalPart.length > currency.decimals) {\n throw new InvalidPrecisionError(\n `Precision ${fractionalPart.length} exceeds currency decimals ${currency.decimals}`,\n );\n }\n\n // Pad fractional part\n const paddedFractional = fractionalPart.padEnd(currency.decimals, \"0\");\n\n const combined = integerPart + paddedFractional;\n\n return BigInt(combined);\n}\n","import { Money } from \"../money/Money\";\n\n/**\n * Options for formatting Money values.\n */\nexport interface FormatOptions {\n /**\n * The locale to use for formatting (e.g., \"en-US\", \"de-DE\").\n * If not provided, defaults to the currency's default locale or \"en-US\".\n */\n locale?: string;\n\n /**\n * Whether to include the currency symbol in the output.\n * Defaults to true.\n */\n symbol?: boolean;\n\n /**\n * How to display the currency.\n * 'symbol' (default): \"$1.00\"\n * 'code': \"USD 1.00\"\n * 'name': \"1.00 US dollars\"\n */\n display?: \"symbol\" | \"code\" | \"name\";\n\n /**\n * Whether to use accounting format for negative numbers.\n * When true, negative values are wrapped in parentheses instead of using a minus sign.\n * Defaults to false.\n * @example\n * // accounting: false (default): \"-$1.00\"\n * // accounting: true: \"($1.00)\"\n */\n accounting?: boolean;\n}\n\n/**\n * Formats a Money object into a string representation.\n *\n * Uses `Intl.NumberFormat` for locale-aware formatting of numbers and currency symbols.\n *\n * @param money - The Money object to format.\n * @param options - Formatting options.\n * @returns The formatted string.\n */\nexport function format(money: Money, options?: FormatOptions): string {\n const locale = options?.locale || money.currency.locale || \"en-US\";\n const showSymbol = options?.symbol ?? true;\n const display = options?.display || \"symbol\";\n const useAccounting = options?.accounting ?? false;\n\n const decimals = money.currency.decimals;\n const minor = money.minor;\n const isNegative = minor < 0n;\n const absMinor = isNegative ? -minor : minor;\n\n const divisor = 10n ** BigInt(decimals);\n const integerPart = absMinor / divisor;\n const fractionalPart = absMinor % divisor;\n\n // Pad fractional\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n\n // Get separators\n // We use a dummy format to extract the decimal separator for the locale\n const parts = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n minimumFractionDigits: 1,\n }).formatToParts(1.1);\n\n const decimalSeparator =\n parts.find((p) => p.type === \"decimal\")?.value || \".\";\n\n // Format integer part with grouping using Intl (supports BigInt)\n const integerFormatted = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n useGrouping: true,\n }).format(integerPart);\n\n const absString =\n decimals > 0\n ? `${integerFormatted}${decimalSeparator}${fractionalStr}`\n : integerFormatted;\n\n if (!showSymbol) {\n if (isNegative) {\n return useAccounting ? `(${absString})` : `-${absString}`;\n }\n return absString;\n }\n\n // Use formatToParts to get the template (sign position, currency position)\n let templateParts: Intl.NumberFormatPart[];\n try {\n templateParts = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: money.currency.code,\n currencyDisplay: display,\n }).formatToParts(isNegative ? -1234.5 : 1234.5);\n } catch (e) {\n // Fallback for custom currencies or invalid codes\n const symbol =\n display === \"symbol\" ? money.currency.symbol : money.currency.code;\n if (isNegative) {\n return useAccounting\n ? `(${symbol}${absString})`\n : `-${symbol}${absString}`;\n }\n return `${symbol}${absString}`;\n }\n\n let result = \"\";\n let numberInserted = false;\n\n for (const part of templateParts) {\n switch (part.type) {\n case \"minusSign\": {\n // Skip the minus sign, we'll handle it later for accounting format\n if (!useAccounting) {\n result += part.value;\n }\n break;\n }\n\n case \"integer\": {\n if (!numberInserted) {\n result += absString;\n numberInserted = true;\n }\n break;\n }\n\n // Skip the remaining numeric parts, since we already inserted the full number string.\n case \"group\":\n case \"decimal\":\n case \"fraction\": {\n break;\n }\n\n case \"currency\": {\n if (display === \"symbol\" && money.currency.symbol) {\n result += money.currency.symbol;\n } else {\n result += part.value;\n }\n break;\n }\n\n default: {\n result += part.value; // literals, parentheses, etc.\n break;\n }\n }\n }\n\n // Apply accounting format if negative\n if (useAccounting && isNegative) {\n return `(${result.trim()})`;\n }\n\n return result;\n}\n","import { Currency } from \"../currency/Currency\";\nimport { getCurrency } from \"../currency/registry\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nimport { assertSameCurrency } from \"./guards\";\nimport { add, subtract, multiply, divide } from \"./arithmetic\";\nimport { allocate } from \"./allocation\";\nimport { parseToMinor } from \"../format/parser\";\nimport { format } from \"../format/formatter\";\n\n/**\n * Represents a monetary value in a specific currency.\n *\n * Money objects are immutable and store values in minor units (e.g., cents) using BigInt\n * to avoid floating-point precision errors.\n */\nexport class Money {\n /**\n * The amount in minor units (e.g., cents).\n */\n readonly minor: bigint;\n\n /**\n * The currency of this money value.\n */\n readonly currency: Currency;\n\n private constructor(minor: bigint, currency: Currency) {\n this.minor = minor;\n this.currency = currency;\n }\n\n private static resolveCurrency(currency: Currency | string): Currency {\n if (typeof currency === \"string\") {\n return getCurrency(currency);\n }\n return currency;\n }\n\n /**\n * Creates a Money instance from minor units (e.g., cents).\n *\n * @param minor - The amount in minor units. Can be a number or BigInt.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @example\n * const m = Money.fromMinor(100, USD); // $1.00\n * const m2 = Money.fromMinor(100, 'USD'); // $1.00\n */\n static fromMinor(minor: bigint | number, currency: Currency | string): Money {\n return new Money(BigInt(minor), Money.resolveCurrency(currency));\n }\n\n /**\n * Alias for `fromMinor`. Creates a Money instance from cents/minor units.\n *\n * @param cents - The amount in minor units.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @example\n * const m = Money.fromCents(100, 'USD'); // $1.00\n */\n static fromCents(cents: bigint | number, currency: Currency | string): Money {\n return Money.fromMinor(cents, currency);\n }\n\n /**\n * Creates a Money instance from major units (e.g., \"10.50\").\n *\n * @param amount - The amount as a string. Must be a valid decimal number.\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.\n * @example\n * const m = Money.fromMajor(\"10.50\", USD); // $10.50\n */\n static fromMajor(amount: string, currency: Currency | string): Money {\n const resolvedCurrency = Money.resolveCurrency(currency);\n const minor = parseToMinor(amount, resolvedCurrency);\n return new Money(minor, resolvedCurrency);\n }\n\n /**\n * Alias for `fromMajor`. Creates a Money instance from a decimal string.\n *\n * @param amount - The amount as a string (e.g., \"10.50\").\n * @param currency - The currency of the money (object or code string).\n * @returns A new Money instance.\n * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.\n * @example\n * const m = Money.fromDecimal(\"10.50\", 'USD'); // $10.50\n */\n static fromDecimal(amount: string, currency: Currency | string): Money {\n return Money.fromMajor(amount, currency);\n }\n\n /**\n * Creates a Money instance from a floating-point number.\n *\n * ⚠️ WARNING: Floating-point numbers can have precision issues.\n * Prefer `Money.fromMajor(\"10.50\", currency)` for exact values.\n *\n * @param amount - The float amount in major units.\n * @param currency - The currency.\n * @param options - Options for handling precision.\n * @returns A new Money instance.\n */\n static fromFloat(\n amount: number,\n currency: Currency | string,\n options?: {\n rounding?: RoundingMode;\n suppressWarning?: boolean;\n },\n ): Money {\n if (!options?.suppressWarning && process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"[monetra] Money.fromFloat() may lose precision. \" +\n 'Consider using Money.fromMajor(\"' +\n amount +\n '\", currency) instead.',\n );\n }\n const resolvedCurrency = Money.resolveCurrency(currency);\n const factor = 10 ** resolvedCurrency.decimals;\n const minorUnits = Math.round(amount * factor);\n return new Money(BigInt(minorUnits), resolvedCurrency);\n }\n\n /**\n * Returns the minimum of the provided Money values.\n * @param values - Money values to compare (must all be same currency).\n * @returns The Money with the smallest amount.\n * @throws {CurrencyMismatchError} If currencies don't match.\n */\n static min(...values: Money[]): Money {\n if (values.length === 0)\n throw new Error(\"At least one Money value required\");\n return values.reduce((min, current) => {\n assertSameCurrency(min, current);\n return current.lessThan(min) ? current : min;\n });\n }\n\n /**\n * Returns the maximum of the provided Money values.\n * @param values - Money values to compare (must all be same currency).\n * @returns The Money with the largest amount.\n * @throws {CurrencyMismatchError} If currencies don't match.\n */\n static max(...values: Money[]): Money {\n if (values.length === 0)\n throw new Error(\"At least one Money value required\");\n return values.reduce((max, current) => {\n assertSameCurrency(max, current);\n return current.greaterThan(max) ? current : max;\n });\n }\n\n /**\n * Creates a Money instance representing zero in the given currency.\n *\n * @param currency - The currency.\n * @returns A new Money instance with value 0.\n */\n static zero(currency: Currency | string): Money {\n return new Money(0n, Money.resolveCurrency(currency));\n }\n\n private resolveOther(other: Money | number | bigint | string): Money {\n if (other instanceof Money) {\n return other;\n }\n if (typeof other === \"string\") {\n return Money.fromMajor(other, this.currency);\n }\n return Money.fromMinor(other, this.currency);\n }\n\n /**\n * Adds another Money value to this one.\n *\n * @param other - The value to add (Money, minor units as number/bigint, or major units as string).\n * @returns A new Money instance representing the sum.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n add(other: Money | number | bigint | string): Money {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return new Money(add(this.minor, otherMoney.minor), this.currency);\n }\n\n /**\n * Subtracts another Money value from this one.\n *\n * @param other - The value to subtract (Money, minor units as number/bigint, or major units as string).\n * @returns A new Money instance representing the difference.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n subtract(other: Money | number | bigint | string): Money {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return new Money(subtract(this.minor, otherMoney.minor), this.currency);\n }\n\n /**\n * Multiplies this Money value by a scalar.\n *\n * @param multiplier - The number to multiply by.\n * @param options - Options for rounding if the result is not an integer.\n * @returns A new Money instance representing the product.\n * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.\n */\n multiply(\n multiplier: string | number,\n options?: { rounding?: RoundingMode },\n ): Money {\n const result = multiply(this.minor, multiplier, options?.rounding);\n return new Money(result, this.currency);\n }\n\n /**\n * Divides this Money value by a divisor.\n *\n * @param divisor - The number to divide by.\n * @param options - Options for rounding if the result is not an integer.\n * @returns A new Money instance representing the quotient.\n * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.\n * @throws {Error} If divisor is zero.\n */\n divide(\n divisor: number | string,\n options?: { rounding?: RoundingMode },\n ): Money {\n if (divisor === 0 || divisor === \"0\") {\n throw new Error(\"Division by zero\");\n }\n const result = divide(this.minor, divisor, options?.rounding);\n return new Money(result, this.currency);\n }\n\n /**\n * Returns the absolute value of this Money.\n * @returns A new Money instance with the absolute value.\n */\n abs(): Money {\n return new Money(this.minor < 0n ? -this.minor : this.minor, this.currency);\n }\n\n /**\n * Returns the negated value of this Money.\n * @returns A new Money instance with the negated value.\n */\n negate(): Money {\n return new Money(-this.minor, this.currency);\n }\n\n /**\n * Allocates (splits) this Money value according to a list of ratios.\n *\n * The sum of the parts will always equal the original amount.\n * Remainders are distributed to the parts with the largest fractional remainders.\n *\n * @param ratios - A list of numbers representing the ratios to split by.\n * @returns An array of Money instances.\n */\n allocate(ratios: number[]): Money[] {\n const shares = allocate(this.minor, ratios);\n return shares.map((share) => new Money(share, this.currency));\n }\n\n /**\n * Formats this Money value as a string.\n *\n * @param options - Formatting options.\n * @returns The formatted string.\n */\n format(options?: {\n locale?: string;\n symbol?: boolean;\n display?: \"symbol\" | \"code\" | \"name\";\n }): string {\n return format(this, options);\n }\n\n /**\n * Checks if this Money value is equal to another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if amounts and currencies are equal.\n */\n equals(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n return (\n this.currency.code === otherMoney.currency.code &&\n this.minor === otherMoney.minor\n );\n }\n\n /**\n * Checks if this Money value is greater than another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if this value is greater.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n greaterThan(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor > otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is less than another.\n *\n * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).\n * @returns True if this value is less.\n * @throws {CurrencyMismatchError} If the currencies do not match.\n */\n lessThan(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor < otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is greater than or equal to another.\n */\n greaterThanOrEqual(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor >= otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is less than or equal to another.\n */\n lessThanOrEqual(other: Money | number | bigint | string): boolean {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n return this.minor <= otherMoney.minor;\n }\n\n /**\n * Checks if this Money value is positive (greater than zero).\n */\n isPositive(): boolean {\n return this.minor > 0n;\n }\n\n /**\n * Compares this Money to another, returning -1, 0, or 1.\n * Useful for sorting.\n */\n compare(other: Money | number | bigint | string): -1 | 0 | 1 {\n const otherMoney = this.resolveOther(other);\n assertSameCurrency(this, otherMoney);\n if (this.minor < otherMoney.minor) return -1;\n if (this.minor > otherMoney.minor) return 1;\n return 0;\n }\n\n /**\n * Calculates a percentage of the money.\n * @param percent - The percentage (e.g., 50 for 50%).\n * @param rounding - Rounding mode (defaults to HALF_EVEN).\n */\n percentage(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN,\n ): Money {\n return this.multiply(percent / 100, { rounding });\n }\n\n /**\n * Adds a percentage to the money.\n * @param percent - The percentage to add.\n * @param rounding - Rounding mode.\n */\n addPercent(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN,\n ): Money {\n return this.add(this.percentage(percent, rounding));\n }\n\n /**\n * Subtracts a percentage from the money.\n * @param percent - The percentage to subtract.\n * @param rounding - Rounding mode.\n */\n subtractPercent(\n percent: number,\n rounding: RoundingMode = RoundingMode.HALF_EVEN,\n ): Money {\n return this.subtract(this.percentage(percent, rounding));\n }\n\n /**\n * Splits the money into equal parts.\n * @param parts - Number of parts.\n */\n split(parts: number): Money[] {\n const ratios = Array(parts).fill(1);\n return this.allocate(ratios);\n }\n\n /**\n * Checks if this Money value is zero.\n *\n * @returns True if the amount is zero.\n */\n isZero(): boolean {\n return this.minor === 0n;\n }\n\n /**\n * Checks if this Money value is negative.\n *\n * @returns True if the amount is negative.\n */\n isNegative(): boolean {\n return this.minor < 0n;\n }\n\n /**\n * Clamps this Money value between a minimum and maximum.\n *\n * @param min - The minimum Money value.\n * @param max - The maximum Money value.\n * @returns A new Money instance clamped between min and max.\n * @throws {CurrencyMismatchError} If currencies don't match.\n * @throws {Error} If min is greater than max.\n * @example\n * const price = Money.fromMajor(\"150\", 'USD');\n * const clamped = price.clamp(Money.fromMajor(\"50\", 'USD'), Money.fromMajor(\"100\", 'USD'));\n * // clamped is $100.00\n */\n clamp(min: Money, max: Money): Money {\n assertSameCurrency(this, min);\n assertSameCurrency(this, max);\n\n if (min.greaterThan(max)) {\n throw new Error(\"Clamp min cannot be greater than max\");\n }\n\n if (this.lessThan(min)) {\n return new Money(min.minor, this.currency);\n }\n if (this.greaterThan(max)) {\n return new Money(max.minor, this.currency);\n }\n return this;\n }\n\n /**\n * Returns the value as a decimal string without locale formatting.\n *\n * This returns a raw decimal representation suitable for storage or calculations,\n * without any currency symbols, grouping separators, or locale-specific formatting.\n *\n * @returns The decimal string representation (e.g., \"10.50\", \"-5.25\").\n * @example\n * const m = Money.fromMajor(\"1234.56\", 'USD');\n * m.toDecimalString(); // \"1234.56\"\n */\n toDecimalString(): string {\n const decimals = this.currency.decimals;\n const isNegative = this.minor < 0n;\n const absMinor = isNegative ? -this.minor : this.minor;\n\n if (decimals === 0) {\n return isNegative ? `-${absMinor.toString()}` : absMinor.toString();\n }\n\n const divisor = 10n ** BigInt(decimals);\n const integerPart = absMinor / divisor;\n const fractionalPart = absMinor % divisor;\n\n const fractionalStr = fractionalPart.toString().padStart(decimals, \"0\");\n const result = `${integerPart}.${fractionalStr}`;\n\n return isNegative ? `-${result}` : result;\n }\n\n /**\n * Returns a JSON representation of the Money object.\n *\n * @returns An object with amount (string), currency (code), and precision.\n */\n toJSON(): { amount: string; currency: string; precision: number } {\n return {\n amount: this.minor.toString(),\n currency: this.currency.code,\n precision: this.currency.decimals,\n };\n }\n\n /**\n * JSON reviver function for deserializing Money objects.\n *\n * Use with `JSON.parse()` to automatically reconstruct Money instances:\n *\n * @param key - The JSON key (unused).\n * @param value - The parsed JSON value.\n * @returns A Money instance if value is a serialized Money object, otherwise the original value.\n * @example\n * const json = '{\"amount\": \"1050\", \"currency\": \"USD\", \"precision\": 2}';\n * const money = JSON.parse(json, Money.reviver);\n * // money is Money instance: $10.50\n */\n static reviver(key: string, value: unknown): unknown {\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"amount\" in value &&\n \"currency\" in value &&\n \"precision\" in value &&\n typeof (value as Record<string, unknown>).amount === \"string\" &&\n typeof (value as Record<string, unknown>).currency === \"string\" &&\n typeof (value as Record<string, unknown>).precision === \"number\"\n ) {\n const obj = value as {\n amount: string;\n currency: string;\n precision: number;\n };\n return Money.fromMinor(BigInt(obj.amount), obj.currency);\n }\n return value;\n }\n\n /**\n * Returns a string representation of the Money object (formatted).\n */\n toString(): string {\n return this.format();\n }\n}\n","import { Money } from \"./Money\";\nimport { Currency } from \"../currency/Currency\";\nimport { getCurrency } from \"../currency/registry\";\nimport { RoundingMode } from \"../rounding\";\n\n/**\n * Handles currency conversion using exchange rates.\n */\nexport class Converter {\n private rates: Record<string, number>;\n private base: string;\n\n /**\n * Creates a new Converter.\n *\n * @param base - The base currency code (e.g., \"USD\").\n * @param rates - A map of currency codes to exchange rates relative to the base.\n * Example: { \"EUR\": 0.85, \"GBP\": 0.75 } (where 1 Base = 0.85 EUR).\n */\n constructor(base: string, rates: Record<string, number>) {\n this.base = base;\n this.rates = { ...rates };\n\n // Ensure base rate is 1\n if (this.rates[base] === undefined) {\n this.rates[base] = 1;\n }\n }\n\n /**\n * Converts a Money object to a target currency.\n *\n * @param money - The Money object to convert.\n * @param toCurrency - The target currency (code or object).\n * @returns A new Money object in the target currency.\n * @throws {Error} If exchange rates are missing.\n */\n convert(money: Money, toCurrency: Currency | string): Money {\n const targetCurrency =\n typeof toCurrency === \"string\" ? getCurrency(toCurrency) : toCurrency;\n\n if (money.currency.code === targetCurrency.code) {\n return money;\n }\n\n const fromRate = this.rates[money.currency.code];\n const toRate = this.rates[targetCurrency.code];\n\n if (fromRate === undefined || toRate === undefined) {\n throw new Error(\n `Exchange rate missing for conversion from ${money.currency.code} to ${targetCurrency.code}`,\n );\n }\n\n // Calculate the exchange rate ratio\n const ratio = toRate / fromRate;\n\n // Adjust for difference in decimal places\n // targetMinor = sourceMinor * ratio * 10^(targetDecimals - sourceDecimals)\n const decimalAdjustment =\n 10 ** (targetCurrency.decimals - money.currency.decimals);\n\n // We use the multiply method of Money which handles rounding.\n // Default rounding is usually needed for conversion.\n // We'll use the default rounding (HALF_EVEN is common for money, but Money.multiply requires explicit if fractional).\n // Let's assume standard rounding (HALF_UP) or require options?\n // For ease of use, we should probably default to HALF_UP or similar.\n // But Money.multiply throws if rounding is needed and not provided.\n\n // Let's pass a default rounding mode.\n // We need to import RoundingMode.\n\n const multiplier = ratio * decimalAdjustment;\n\n // We need to access the internal multiply or use the public one.\n // Public one: money.multiply(multiplier, { rounding: 'HALF_EVEN' })\n\n const convertedAmount = money.multiply(multiplier, {\n rounding: RoundingMode.HALF_EVEN,\n });\n return Money.fromMinor(convertedAmount.minor, targetCurrency);\n }\n}\n","import { Money } from \"./Money\";\nimport { Currency } from \"../currency/Currency\";\nimport { Converter } from \"./Converter\";\nimport { getCurrency } from \"../currency/registry\";\n\n/**\n * A collection of Money objects in different currencies.\n * Useful for representing a wallet or portfolio.\n */\nexport class MoneyBag {\n private contents: Map<string, Money> = new Map();\n\n /**\n * Adds a Money amount to the bag.\n * @param money The money to add.\n */\n add(money: Money): void {\n const code = money.currency.code;\n const existing = this.contents.get(code);\n if (existing) {\n this.contents.set(code, existing.add(money));\n } else {\n this.contents.set(code, money);\n }\n }\n\n /**\n * Subtracts a Money amount from the bag.\n * @param money The money to subtract.\n */\n subtract(money: Money): void {\n const code = money.currency.code;\n const existing = this.contents.get(code);\n if (existing) {\n this.contents.set(code, existing.subtract(money));\n } else {\n // If not present, we assume 0 - amount\n const zero = Money.zero(money.currency);\n this.contents.set(code, zero.subtract(money));\n }\n }\n\n /**\n * Gets the amount for a specific currency.\n * @param currency The currency to retrieve.\n * @returns The Money amount in that currency (or zero if not present).\n */\n get(currency: Currency | string): Money {\n const code = typeof currency === \"string\" ? currency : currency.code;\n return (\n this.contents.get(code) ||\n Money.zero(\n typeof currency === \"string\" ? getCurrency(currency) : currency,\n )\n );\n }\n\n /**\n * Calculates the total value of the bag in a specific currency.\n *\n * @param targetCurrency The currency to convert everything to.\n * @param converter The converter instance with exchange rates.\n * @returns The total amount in the target currency.\n */\n total(targetCurrency: Currency | string, converter: Converter): Money {\n const target =\n typeof targetCurrency === \"string\"\n ? getCurrency(targetCurrency)\n : targetCurrency;\n let total = Money.zero(target);\n\n for (const money of this.contents.values()) {\n const converted = converter.convert(money, target);\n total = total.add(converted);\n }\n\n return total;\n }\n\n /**\n * Returns a list of all Money objects in the bag.\n */\n getAll(): Money[] {\n return Array.from(this.contents.values());\n }\n\n /**\n * Returns a JSON representation of the bag.\n */\n toJSON(): { amount: string; currency: string; precision: number }[] {\n return this.getAll().map((m) => m.toJSON());\n }\n}\n","import { Currency } from \"./Currency\";\nimport { registerCurrency } from \"./registry\";\n\n// ============================================================================\n// MAJOR WORLD CURRENCIES\n// ============================================================================\n\n/**\n * United States Dollar (USD).\n */\nexport const USD: Currency = {\n code: \"USD\",\n decimals: 2,\n symbol: \"$\",\n locale: \"en-US\",\n};\nregisterCurrency(USD);\n\n/**\n * Euro (EUR).\n */\nexport const EUR: Currency = {\n code: \"EUR\",\n decimals: 2,\n symbol: \"€\",\n locale: \"de-DE\",\n};\nregisterCurrency(EUR);\n\n/**\n * British Pound Sterling (GBP).\n */\nexport const GBP: Currency = {\n code: \"GBP\",\n decimals: 2,\n symbol: \"£\",\n locale: \"en-GB\",\n};\nregisterCurrency(GBP);\n\n/**\n * Japanese Yen (JPY).\n */\nexport const JPY: Currency = {\n code: \"JPY\",\n decimals: 0,\n symbol: \"¥\",\n locale: \"ja-JP\",\n};\nregisterCurrency(JPY);\n\n/**\n * Swiss Franc (CHF).\n */\nexport const CHF: Currency = {\n code: \"CHF\",\n decimals: 2,\n symbol: \"CHF\",\n locale: \"de-CH\",\n};\nregisterCurrency(CHF);\n\n/**\n * Canadian Dollar (CAD).\n */\nexport const CAD: Currency = {\n code: \"CAD\",\n decimals: 2,\n symbol: \"CA$\",\n locale: \"en-CA\",\n};\nregisterCurrency(CAD);\n\n/**\n * Australian Dollar (AUD).\n */\nexport const AUD: Currency = {\n code: \"AUD\",\n decimals: 2,\n symbol: \"A$\",\n locale: \"en-AU\",\n};\nregisterCurrency(AUD);\n\n/**\n * New Zealand Dollar (NZD).\n */\nexport const NZD: Currency = {\n code: \"NZD\",\n decimals: 2,\n symbol: \"NZ$\",\n locale: \"en-NZ\",\n};\nregisterCurrency(NZD);\n\n/**\n * Chinese Yuan Renminbi (CNY).\n */\nexport const CNY: Currency = {\n code: \"CNY\",\n decimals: 2,\n symbol: \"¥\",\n locale: \"zh-CN\",\n};\nregisterCurrency(CNY);\n\n/**\n * Hong Kong Dollar (HKD).\n */\nexport const HKD: Currency = {\n code: \"HKD\",\n decimals: 2,\n symbol: \"HK$\",\n locale: \"zh-HK\",\n};\nregisterCurrency(HKD);\n\n/**\n * Singapore Dollar (SGD).\n */\nexport const SGD: Currency = {\n code: \"SGD\",\n decimals: 2,\n symbol: \"S$\",\n locale: \"en-SG\",\n};\nregisterCurrency(SGD);\n\n/**\n * South Korean Won (KRW).\n */\nexport const KRW: Currency = {\n code: \"KRW\",\n decimals: 0,\n symbol: \"₩\",\n locale: \"ko-KR\",\n};\nregisterCurrency(KRW);\n\n/**\n * Indian Rupee (INR).\n */\nexport const INR: Currency = {\n code: \"INR\",\n decimals: 2,\n symbol: \"₹\",\n locale: \"en-IN\",\n};\nregisterCurrency(INR);\n\n// ============================================================================\n// EUROPEAN CURRENCIES\n// ============================================================================\n\n/**\n * Swedish Krona (SEK).\n */\nexport const SEK: Currency = {\n code: \"SEK\",\n decimals: 2,\n symbol: \"kr\",\n locale: \"sv-SE\",\n};\nregisterCurrency(SEK);\n\n/**\n * Norwegian Krone (NOK).\n */\nexport const NOK: Currency = {\n code: \"NOK\",\n decimals: 2,\n symbol: \"kr\",\n locale: \"nb-NO\",\n};\nregisterCurrency(NOK);\n\n/**\n * Danish Krone (DKK).\n */\nexport const DKK: Currency = {\n code: \"DKK\",\n decimals: 2,\n symbol: \"kr\",\n locale: \"da-DK\",\n};\nregisterCurrency(DKK);\n\n/**\n * Polish Zloty (PLN).\n */\nexport const PLN: Currency = {\n code: \"PLN\",\n decimals: 2,\n symbol: \"zł\",\n locale: \"pl-PL\",\n};\nregisterCurrency(PLN);\n\n/**\n * Czech Koruna (CZK).\n */\nexport const CZK: Currency = {\n code: \"CZK\",\n decimals: 2,\n symbol: \"Kč\",\n locale: \"cs-CZ\",\n};\nregisterCurrency(CZK);\n\n/**\n * Hungarian Forint (HUF).\n */\nexport const HUF: Currency = {\n code: \"HUF\",\n decimals: 2,\n symbol: \"Ft\",\n locale: \"hu-HU\",\n};\nregisterCurrency(HUF);\n\n/**\n * Romanian Leu (RON).\n */\nexport const RON: Currency = {\n code: \"RON\",\n decimals: 2,\n symbol: \"lei\",\n locale: \"ro-RO\",\n};\nregisterCurrency(RON);\n\n/**\n * Bulgarian Lev (BGN).\n */\nexport const BGN: Currency = {\n code: \"BGN\",\n decimals: 2,\n symbol: \"лв\",\n locale: \"bg-BG\",\n};\nregisterCurrency(BGN);\n\n/**\n * Croatian Kuna (HRK).\n * Note: Croatia adopted EUR on Jan 1, 2023, but HRK may still be needed for historical data.\n */\nexport const HRK: Currency = {\n code: \"HRK\",\n decimals: 2,\n symbol: \"kn\",\n locale: \"hr-HR\",\n};\nregisterCurrency(HRK);\n\n/**\n * Turkish Lira (TRY).\n */\nexport const TRY: Currency = {\n code: \"TRY\",\n decimals: 2,\n symbol: \"₺\",\n locale: \"tr-TR\",\n};\nregisterCurrency(TRY);\n\n/**\n * Russian Ruble (RUB).\n */\nexport const RUB: Currency = {\n code: \"RUB\",\n decimals: 2,\n symbol: \"₽\",\n locale: \"ru-RU\",\n};\nregisterCurrency(RUB);\n\n/**\n * Ukrainian Hryvnia (UAH).\n */\nexport const UAH: Currency = {\n code: \"UAH\",\n decimals: 2,\n symbol: \"₴\",\n locale: \"uk-UA\",\n};\nregisterCurrency(UAH);\n\n/**\n * Israeli New Shekel (ILS).\n */\nexport const ILS: Currency = {\n code: \"ILS\",\n decimals: 2,\n symbol: \"₪\",\n locale: \"he-IL\",\n};\nregisterCurrency(ILS);\n\n// ============================================================================\n// AMERICAS\n// ============================================================================\n\n/**\n * Mexican Peso (MXN).\n */\nexport const MXN: Currency = {\n code: \"MXN\",\n decimals: 2,\n symbol: \"MX$\",\n locale: \"es-MX\",\n};\nregisterCurrency(MXN);\n\n/**\n * Brazilian Real (BRL).\n */\nexport const BRL: Currency = {\n code: \"BRL\",\n decimals: 2,\n symbol: \"R$\",\n locale: \"pt-BR\",\n};\nregisterCurrency(BRL);\n\n/**\n * Argentine Peso (ARS).\n */\nexport const ARS: Currency = {\n code: \"ARS\",\n decimals: 2,\n symbol: \"AR$\",\n locale: \"es-AR\",\n};\nregisterCurrency(ARS);\n\n/**\n * Chilean Peso (CLP).\n */\nexport const CLP: Currency = {\n code: \"CLP\",\n decimals: 0,\n symbol: \"CL$\",\n locale: \"es-CL\",\n};\nregisterCurrency(CLP);\n\n/**\n * Colombian Peso (COP).\n */\nexport const COP: Currency = {\n code: \"COP\",\n decimals: 2,\n symbol: \"CO$\",\n locale: \"es-CO\",\n};\nregisterCurrency(COP);\n\n/**\n * Peruvian Sol (PEN).\n */\nexport const PEN: Currency = {\n code: \"PEN\",\n decimals: 2,\n symbol: \"S/\",\n locale: \"es-PE\",\n};\nregisterCurrency(PEN);\n\n// ============================================================================\n// AFRICA\n// ============================================================================\n\n/**\n * South African Rand (ZAR).\n */\nexport const ZAR: Currency = {\n code: \"ZAR\",\n decimals: 2,\n symbol: \"R\",\n locale: \"en-ZA\",\n};\nregisterCurrency(ZAR);\n\n/**\n * Nigerian Naira (NGN).\n */\nexport const NGN: Currency = {\n code: \"NGN\",\n decimals: 2,\n symbol: \"₦\",\n locale: \"en-NG\",\n};\nregisterCurrency(NGN);\n\n/**\n * Kenyan Shilling (KES).\n */\nexport const KES: Currency = {\n code: \"KES\",\n decimals: 2,\n symbol: \"KSh\",\n locale: \"en-KE\",\n};\nregisterCurrency(KES);\n\n/**\n * Egyptian Pound (EGP).\n */\nexport const EGP: Currency = {\n code: \"EGP\",\n decimals: 2,\n symbol: \"E£\",\n locale: \"ar-EG\",\n};\nregisterCurrency(EGP);\n\n/**\n * Moroccan Dirham (MAD).\n */\nexport const MAD: Currency = {\n code: \"MAD\",\n decimals: 2,\n symbol: \"د.م.\",\n locale: \"ar-MA\",\n};\nregisterCurrency(MAD);\n\n/**\n * Ghanaian Cedi (GHS).\n */\nexport const GHS: Currency = {\n code: \"GHS\",\n decimals: 2,\n symbol: \"GH₵\",\n locale: \"en-GH\",\n};\nregisterCurrency(GHS);\n\n/**\n * Tanzanian Shilling (TZS).\n */\nexport const TZS: Currency = {\n code: \"TZS\",\n decimals: 2,\n symbol: \"TSh\",\n locale: \"sw-TZ\",\n};\nregisterCurrency(TZS);\n\n/**\n * Ugandan Shilling (UGX).\n */\nexport const UGX: Currency = {\n code: \"UGX\",\n decimals: 0,\n symbol: \"USh\",\n locale: \"en-UG\",\n};\nregisterCurrency(UGX);\n\n// ============================================================================\n// ASIA-PACIFIC\n// ============================================================================\n\n/**\n * Thai Baht (THB).\n */\nexport const THB: Currency = {\n code: \"THB\",\n decimals: 2,\n symbol: \"฿\",\n locale: \"th-TH\",\n};\nregisterCurrency(THB);\n\n/**\n * Malaysian Ringgit (MYR).\n */\nexport const MYR: Currency = {\n code: \"MYR\",\n decimals: 2,\n symbol: \"RM\",\n locale: \"ms-MY\",\n};\nregisterCurrency(MYR);\n\n/**\n * Indonesian Rupiah (IDR).\n */\nexport const IDR: Currency = {\n code: \"IDR\",\n decimals: 2,\n symbol: \"Rp\",\n locale: \"id-ID\",\n};\nregisterCurrency(IDR);\n\n/**\n * Philippine Peso (PHP).\n */\nexport const PHP: Currency = {\n code: \"PHP\",\n decimals: 2,\n symbol: \"₱\",\n locale: \"en-PH\",\n};\nregisterCurrency(PHP);\n\n/**\n * Vietnamese Dong (VND).\n */\nexport const VND: Currency = {\n code: \"VND\",\n decimals: 0,\n symbol: \"₫\",\n locale: \"vi-VN\",\n};\nregisterCurrency(VND);\n\n/**\n * Taiwan Dollar (TWD).\n */\nexport const TWD: Currency = {\n code: \"TWD\",\n decimals: 2,\n symbol: \"NT$\",\n locale: \"zh-TW\",\n};\nregisterCurrency(TWD);\n\n/**\n * Pakistani Rupee (PKR).\n */\nexport const PKR: Currency = {\n code: \"PKR\",\n decimals: 2,\n symbol: \"₨\",\n locale: \"ur-PK\",\n};\nregisterCurrency(PKR);\n\n/**\n * Bangladeshi Taka (BDT).\n */\nexport const BDT: Currency = {\n code: \"BDT\",\n decimals: 2,\n symbol: \"৳\",\n locale: \"bn-BD\",\n};\nregisterCurrency(BDT);\n\n/**\n * Sri Lankan Rupee (LKR).\n */\nexport const LKR: Currency = {\n code: \"LKR\",\n decimals: 2,\n symbol: \"Rs\",\n locale: \"si-LK\",\n};\nregisterCurrency(LKR);\n\n// ============================================================================\n// MIDDLE EAST\n// ============================================================================\n\n/**\n * United Arab Emirates Dirham (AED).\n */\nexport const AED: Currency = {\n code: \"AED\",\n decimals: 2,\n symbol: \"د.إ\",\n locale: \"ar-AE\",\n};\nregisterCurrency(AED);\n\n/**\n * Saudi Riyal (SAR).\n */\nexport const SAR: Currency = {\n code: \"SAR\",\n decimals: 2,\n symbol: \"﷼\",\n locale: \"ar-SA\",\n};\nregisterCurrency(SAR);\n\n/**\n * Qatari Riyal (QAR).\n */\nexport const QAR: Currency = {\n code: \"QAR\",\n decimals: 2,\n symbol: \"﷼\",\n locale: \"ar-QA\",\n};\nregisterCurrency(QAR);\n\n/**\n * Kuwaiti Dinar (KWD).\n * Note: 3 decimal places (fils).\n */\nexport const KWD: Currency = {\n code: \"KWD\",\n decimals: 3,\n symbol: \"د.ك\",\n locale: \"ar-KW\",\n};\nregisterCurrency(KWD);\n\n/**\n * Bahraini Dinar (BHD).\n * Note: 3 decimal places (fils).\n */\nexport const BHD: Currency = {\n code: \"BHD\",\n decimals: 3,\n symbol: \"د.ب\",\n locale: \"ar-BH\",\n};\nregisterCurrency(BHD);\n\n/**\n * Omani Rial (OMR).\n * Note: 3 decimal places (baisa).\n */\nexport const OMR: Currency = {\n code: \"OMR\",\n decimals: 3,\n symbol: \"﷼\",\n locale: \"ar-OM\",\n};\nregisterCurrency(OMR);\n\n/**\n * Jordanian Dinar (JOD).\n * Note: 3 decimal places (fils).\n */\nexport const JOD: Currency = {\n code: \"JOD\",\n decimals: 3,\n symbol: \"د.ا\",\n locale: \"ar-JO\",\n};\nregisterCurrency(JOD);\n\n// ============================================================================\n// SPECIAL CURRENCIES\n// ============================================================================\n\n/**\n * Icelandic Króna (ISK).\n * Note: 0 decimal places.\n */\nexport const ISK: Currency = {\n code: \"ISK\",\n decimals: 0,\n symbol: \"kr\",\n locale: \"is-IS\",\n};\nregisterCurrency(ISK);\n\n/**\n * Mauritanian Ouguiya (MRU).\n * Note: Uses 2 decimals (khoums), but often displayed without.\n */\nexport const MRU: Currency = {\n code: \"MRU\",\n decimals: 2,\n symbol: \"UM\",\n locale: \"ar-MR\",\n};\nregisterCurrency(MRU);\n\n/**\n * A collection of common currencies.\n * @deprecated Use registry instead. Import individual currencies or use getCurrency().\n */\nexport const CURRENCIES: Record<string, Currency> = {\n // Major world currencies\n USD,\n EUR,\n GBP,\n JPY,\n CHF,\n CAD,\n AUD,\n NZD,\n CNY,\n HKD,\n SGD,\n KRW,\n INR,\n // European\n SEK,\n NOK,\n DKK,\n PLN,\n CZK,\n HUF,\n RON,\n BGN,\n HRK,\n TRY,\n RUB,\n UAH,\n ILS,\n // Americas\n MXN,\n BRL,\n ARS,\n CLP,\n COP,\n PEN,\n // Africa\n ZAR,\n NGN,\n KES,\n EGP,\n MAD,\n GHS,\n TZS,\n UGX,\n // Asia-Pacific\n THB,\n MYR,\n IDR,\n PHP,\n VND,\n TWD,\n PKR,\n BDT,\n LKR,\n // Middle East\n AED,\n SAR,\n QAR,\n KWD,\n BHD,\n OMR,\n JOD,\n // Special\n ISK,\n MRU,\n};\n","import { Currency } from \"./Currency\";\n\nexport function getMinorUnitExponent(currency: Currency): bigint {\n return 10n ** BigInt(currency.decimals);\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface LoanScheduleEntry {\n period: number;\n payment: Money;\n principal: Money;\n interest: Money;\n balance: Money;\n}\n\nexport interface LoanOptions {\n principal: Money;\n annualRate: number; // e.g., 0.05 for 5%\n periods: number; // Total number of payments\n periodsPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\nexport interface InterestOnlyOptions {\n principal: Money;\n annualRate: number; // e.g., 0.05 for 5%\n periodsPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates loan amortization schedule.\n */\nexport function loan(options: LoanOptions): LoanScheduleEntry[] {\n const {\n principal,\n annualRate,\n periods,\n periodsPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const periodicRate = annualRate / periodsPerYear;\n let payment: Money;\n\n if (annualRate === 0) {\n payment = principal.divide(periods, { rounding });\n } else {\n // PMT formula: P * (r(1+r)^n) / ((1+r)^n - 1)\n const r = periodicRate;\n const n = periods;\n const numerator = r * Math.pow(1 + r, n);\n const denominator = Math.pow(1 + r, n) - 1;\n const pmtMultiplier = numerator / denominator;\n payment = principal.multiply(pmtMultiplier, { rounding });\n }\n\n const schedule: LoanScheduleEntry[] = [];\n let balance = principal;\n\n for (let period = 1; period <= periods; period++) {\n const interest =\n annualRate === 0\n ? Money.zero(principal.currency)\n : balance.multiply(periodicRate, { rounding });\n\n let principalPayment = payment.subtract(interest);\n\n // If payment < interest (negative amortization), principal payment is negative.\n // This implementation assumes standard amortization.\n\n balance = balance.subtract(principalPayment);\n\n // Handle final period rounding adjustment\n if (period === periods && !balance.isZero()) {\n const adjustedPrincipal = principalPayment.add(balance);\n schedule.push({\n period,\n payment: interest.add(adjustedPrincipal),\n principal: adjustedPrincipal,\n interest,\n balance: Money.zero(principal.currency),\n });\n } else {\n schedule.push({\n period,\n payment,\n principal: principalPayment,\n interest,\n balance: balance.isNegative()\n ? Money.zero(principal.currency)\n : balance,\n });\n }\n }\n\n return schedule;\n}\n\n/**\n * Calculates monthly payment amount.\n */\nexport function pmt(\n options: Omit<LoanOptions, \"rounding\"> & { rounding?: RoundingMode },\n): Money {\n const schedule = loan(options);\n return schedule[0].payment;\n}\n\n/**\n * Calculates total interest over the life of the loan using the payment formula.\n */\nexport function totalInterest(options: LoanOptions): Money {\n const {\n principal,\n annualRate,\n periods,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n if (annualRate === 0) {\n return Money.zero(principal.currency);\n }\n\n const payment = pmt(options);\n const totalPaid = payment.multiply(periods, { rounding });\n return totalPaid.subtract(principal);\n}\n\n/**\n * Sums the interest column from a loan schedule.\n */\nexport function totalInterestFromSchedule(\n schedule: LoanScheduleEntry[],\n): Money {\n if (schedule.length === 0) {\n throw new Error(\"Schedule must have at least one entry\");\n }\n\n const currency = schedule[0].interest.currency;\n return schedule.reduce(\n (sum, entry) => sum.add(entry.interest),\n Money.zero(currency),\n );\n}\n\n/**\n * Calculates the periodic payment for an interest-only loan.\n *\n * In an interest-only loan, the borrower pays only the interest each period,\n * with the full principal due at maturity or refinancing. This is common in:\n * - Commercial real estate\n * - Construction loans\n * - Home Equity Lines of Credit (HELOCs)\n *\n * Formula: Payment = Principal × Periodic Rate\n * Where Periodic Rate = Annual Rate / Periods Per Year\n *\n * @param options - Interest-only loan configuration\n * @returns The periodic interest payment as a Money object\n *\n * @example\n * ```typescript\n * const principal = Money.fromMajor(\"100000\", USD);\n * const payment = interestOnlyPayment({\n * principal,\n * annualRate: 0.06, // 6% annual\n * periodsPerYear: 12 // Monthly payments\n * });\n * // Returns $500.00 per month\n * ```\n */\nexport function interestOnlyPayment(options: InterestOnlyOptions): Money {\n const {\n principal,\n annualRate,\n periodsPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n // If rate is zero, interest payment is zero\n if (annualRate === 0) {\n return Money.zero(principal.currency);\n }\n\n const periodicRate = annualRate / periodsPerYear;\n return principal.multiply(periodicRate, { rounding });\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface CompoundOptions {\n rate: number; // Annual rate (e.g., 0.07 for 7%)\n years: number;\n compoundingPerYear?: number; // Default: 12 (monthly)\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates future value with compound interest.\n * FV = PV * (1 + r/n)^(n*t)\n */\nexport function futureValue(\n presentValue: Money,\n options: CompoundOptions,\n): Money {\n const {\n rate,\n years,\n compoundingPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const n = compoundingPerYear;\n const t = years;\n const multiplier = Math.pow(1 + rate / n, n * t);\n\n return presentValue.multiply(multiplier, { rounding });\n}\n\n/**\n * Calculates present value (discounting).\n * PV = FV / (1 + r/n)^(n*t)\n */\nexport function presentValue(\n futureVal: Money,\n options: CompoundOptions,\n): Money {\n const {\n rate,\n years,\n compoundingPerYear = 12,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n const n = compoundingPerYear;\n const t = years;\n const divisor = Math.pow(1 + rate / n, n * t);\n\n return futureVal.divide(divisor, { rounding });\n}\n\n// Alias for familiarity\nexport const compound = futureValue;\nexport const discount = presentValue;\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\nimport { CurrencyMismatchError } from \"../errors/CurrencyMismatchError\";\nimport { InvalidArgumentError } from \"../errors/InvalidArgumentError\";\n\n/**\n * Calculates Return on Investment (ROI).\n * ROI = (Final Value - Initial Value) / Initial Value\n *\n * @param initialValue - The initial investment cost.\n * @param finalValue - The final value of the investment.\n * @returns The ROI as a decimal (e.g., 0.15 for 15%).\n * @throws {CurrencyMismatchError} If currencies differ.\n */\nexport function roi(initialValue: Money, finalValue: Money): number {\n if (initialValue.currency.code !== finalValue.currency.code) {\n throw new CurrencyMismatchError(\n initialValue.currency.code,\n finalValue.currency.code,\n );\n }\n\n const gain = finalValue.subtract(initialValue);\n return Number(gain.minor) / Number(initialValue.minor);\n}\n\n/**\n * Calculates Net Present Value of cash flows.\n */\nexport function npv(\n discountRate: number,\n cashFlows: Money[], // First is initial investment (usually negative)\n): Money {\n if (cashFlows.length === 0) {\n throw new Error(\"At least one cash flow required\");\n }\n\n const currency = cashFlows[0].currency;\n\n let total = Money.zero(currency);\n\n for (let i = 0; i < cashFlows.length; i++) {\n const discountFactor = Math.pow(1 + discountRate, i);\n const discounted = cashFlows[i].divide(discountFactor, {\n rounding: RoundingMode.HALF_EVEN,\n });\n total = total.add(discounted);\n }\n\n return total;\n}\n\n/**\n * Calculates Internal Rate of Return using Newton-Raphson method.\n * @returns The IRR as a decimal (e.g., 0.12 for 12%)\n */\nexport function irr(cashFlows: Money[], guess: number = 0.1): number {\n const values = cashFlows.map((cf) => Number(cf.minor));\n\n const maxIterations = 100;\n const tolerance = 1e-7;\n let rate = guess;\n\n for (let i = 0; i < maxIterations; i++) {\n let npvValue = 0;\n let derivative = 0;\n\n for (let j = 0; j < values.length; j++) {\n const denominator = Math.pow(1 + rate, j);\n npvValue += values[j] / denominator;\n\n if (j > 0) {\n derivative -= (j * values[j]) / Math.pow(1 + rate, j + 1);\n }\n }\n\n const newRate = rate - npvValue / derivative;\n\n if (Math.abs(newRate - rate) < tolerance) {\n return newRate;\n }\n\n rate = newRate;\n }\n\n throw new Error(\"IRR calculation did not converge\");\n}\n\n/**\n * Calculates the Current Yield of a bond.\n * Current Yield = Annual Coupon Payment / Current Market Price\n *\n * @param annualCoupon - The total annual coupon payment.\n * @param currentPrice - The current market price of the bond.\n * @returns The current yield as a decimal (e.g., 0.05 for 5%).\n * @throws {CurrencyMismatchError} If currencies differ.\n * @throws {InvalidArgumentError} If price is zero or negative.\n */\nexport function currentYield(annualCoupon: Money, currentPrice: Money): number {\n if (annualCoupon.currency.code !== currentPrice.currency.code) {\n throw new CurrencyMismatchError(\n annualCoupon.currency.code,\n currentPrice.currency.code,\n );\n }\n\n if (currentPrice.minor <= 0n) {\n throw new InvalidArgumentError(\"Current price must be positive\");\n }\n\n return Number(annualCoupon.minor) / Number(currentPrice.minor);\n}\n","/**\n * Represents an interest rate or percentage rate with explicit handling\n * to avoid confusion between percentage and decimal forms.\n *\n * @example\n * const rate = Rate.percent(5); // 5% interest rate\n * const rate2 = Rate.decimal(0.05); // Same as 5%\n *\n * rate.toPercent(); // 5\n * rate.toDecimal(); // 0.05\n *\n * // Safe operations\n * rate.add(Rate.percent(2)); // 7%\n * rate.multiply(2); // 10%\n */\nexport class Rate {\n /**\n * Internal storage as a decimal (e.g., 0.05 for 5%).\n * Uses a scaled BigInt internally for precision.\n */\n private readonly decimalValue: bigint;\n\n /**\n * Scale factor for internal precision (1e18 for 18 decimal places).\n */\n private static readonly SCALE = 10n ** 18n;\n\n private constructor(decimalValue: bigint) {\n this.decimalValue = decimalValue;\n }\n\n /**\n * Creates a Rate from a percentage value (e.g., 5 for 5%).\n *\n * @param percent - The percentage value.\n * @returns A new Rate instance.\n * @example\n * const rate = Rate.percent(5.5); // 5.5%\n */\n static percent(percent: number | string): Rate {\n const decimal = typeof percent === \"string\" ? parseFloat(percent) : percent;\n const scaled = BigInt(Math.round((decimal / 100) * Number(Rate.SCALE)));\n return new Rate(scaled);\n }\n\n /**\n * Creates a Rate from a decimal value (e.g., 0.05 for 5%).\n *\n * @param decimal - The decimal value.\n * @returns A new Rate instance.\n * @example\n * const rate = Rate.decimal(0.055); // 5.5%\n */\n static decimal(decimal: number | string): Rate {\n const value = typeof decimal === \"string\" ? parseFloat(decimal) : decimal;\n const scaled = BigInt(Math.round(value * Number(Rate.SCALE)));\n return new Rate(scaled);\n }\n\n /**\n * Creates a Rate representing zero.\n *\n * @returns A Rate of 0%.\n */\n static zero(): Rate {\n return new Rate(0n);\n }\n\n /**\n * Returns the rate as a percentage (e.g., 5 for 5%).\n *\n * @returns The percentage value as a number.\n */\n toPercent(): number {\n return (Number(this.decimalValue) / Number(Rate.SCALE)) * 100;\n }\n\n /**\n * Returns the rate as a decimal (e.g., 0.05 for 5%).\n *\n * @returns The decimal value as a number.\n */\n toDecimal(): number {\n return Number(this.decimalValue) / Number(Rate.SCALE);\n }\n\n /**\n * Adds another rate to this one.\n *\n * @param other - The rate to add.\n * @returns A new Rate representing the sum.\n */\n add(other: Rate): Rate {\n return new Rate(this.decimalValue + other.decimalValue);\n }\n\n /**\n * Subtracts another rate from this one.\n *\n * @param other - The rate to subtract.\n * @returns A new Rate representing the difference.\n */\n subtract(other: Rate): Rate {\n return new Rate(this.decimalValue - other.decimalValue);\n }\n\n /**\n * Multiplies this rate by a scalar.\n *\n * @param multiplier - The number to multiply by.\n * @returns A new Rate representing the product.\n */\n multiply(multiplier: number): Rate {\n const scaled = BigInt(Math.round(multiplier * Number(Rate.SCALE)));\n return new Rate((this.decimalValue * scaled) / Rate.SCALE);\n }\n\n /**\n * Divides this rate by a divisor.\n *\n * @param divisor - The number to divide by.\n * @returns A new Rate representing the quotient.\n */\n divide(divisor: number): Rate {\n const scaled = BigInt(Math.round(divisor * Number(Rate.SCALE)));\n return new Rate((this.decimalValue * Rate.SCALE) / scaled);\n }\n\n /**\n * Checks if this rate equals another.\n *\n * @param other - The rate to compare.\n * @returns True if the rates are equal.\n */\n equals(other: Rate): boolean {\n return this.decimalValue === other.decimalValue;\n }\n\n /**\n * Checks if this rate is greater than another.\n *\n * @param other - The rate to compare.\n * @returns True if this rate is greater.\n */\n greaterThan(other: Rate): boolean {\n return this.decimalValue > other.decimalValue;\n }\n\n /**\n * Checks if this rate is less than another.\n *\n * @param other - The rate to compare.\n * @returns True if this rate is less.\n */\n lessThan(other: Rate): boolean {\n return this.decimalValue < other.decimalValue;\n }\n\n /**\n * Checks if this rate is zero.\n *\n * @returns True if the rate is 0%.\n */\n isZero(): boolean {\n return this.decimalValue === 0n;\n }\n\n /**\n * Checks if this rate is negative.\n *\n * @returns True if the rate is negative.\n */\n isNegative(): boolean {\n return this.decimalValue < 0n;\n }\n\n /**\n * Returns a string representation of the rate as a percentage.\n *\n * @returns The rate as a percentage string (e.g., \"5.5%\").\n */\n toString(): string {\n return `${this.toPercent()}%`;\n }\n\n /**\n * Computes compound factor: (1 + rate)^periods.\n *\n * @param periods - The number of compounding periods.\n * @returns The compound factor as a number.\n * @example\n * Rate.percent(10).compoundFactor(3); // (1.10)^3 = 1.331\n */\n compoundFactor(periods: number): number {\n return Math.pow(1 + this.toDecimal(), periods);\n }\n\n /**\n * Returns the periodic rate for a given frequency.\n *\n * @param periodsPerYear - Number of periods per year (e.g., 12 for monthly).\n * @returns A new Rate representing the periodic rate.\n * @example\n * Rate.percent(12).periodic(12); // 1% monthly\n */\n periodic(periodsPerYear: number): Rate {\n return this.divide(periodsPerYear);\n }\n\n /**\n * Converts an effective rate to a nominal rate.\n *\n * @param periodsPerYear - Number of compounding periods per year.\n * @returns The nominal annual rate.\n */\n toNominal(periodsPerYear: number): Rate {\n const effectiveDecimal = this.toDecimal();\n const nominalDecimal =\n periodsPerYear * (Math.pow(1 + effectiveDecimal, 1 / periodsPerYear) - 1);\n return Rate.decimal(nominalDecimal);\n }\n\n /**\n * Converts a nominal rate to an effective annual rate.\n *\n * @param periodsPerYear - Number of compounding periods per year.\n * @returns The effective annual rate.\n */\n toEffective(periodsPerYear: number): Rate {\n const nominalDecimal = this.toDecimal();\n const effectiveDecimal =\n Math.pow(1 + nominalDecimal / periodsPerYear, periodsPerYear) - 1;\n return Rate.decimal(effectiveDecimal);\n }\n\n /**\n * Returns a JSON representation.\n */\n toJSON(): { percent: number; decimal: number } {\n return {\n percent: this.toPercent(),\n decimal: this.toDecimal(),\n };\n }\n}\n","import { Money } from \"../money/Money\";\nimport { Rate } from \"./rate\";\nimport { RoundingMode } from \"../rounding/strategies\";\n\nexport interface SimpleInterestOptions {\n rate: Rate;\n years: number;\n rounding?: RoundingMode;\n}\n\n/**\n * Calculates simple interest earned on principal.\n *\n * Simple interest is calculated using the formula: Interest = P × r × t\n * Where:\n * - P = Principal amount\n * - r = Annual interest rate (as decimal)\n * - t = Time in years\n *\n * This is commonly used for:\n * - Short-term loans\n * - Accrued interest between bond coupon payments\n * - Basic savings calculations without compounding\n *\n * @param principal - The principal amount as a Money object\n * @param options - Configuration options including rate, years, and rounding\n * @returns The interest amount as a Money object\n *\n * @example\n * ```typescript\n * const principal = Money.fromMajor(\"1000.00\", USD);\n * const rate = Rate.percent(5); // 5% annual rate\n * const interest = simpleInterest(principal, { rate, years: 2 });\n * console.log(interest.format()); // \"$100.00\" (1000 × 0.05 × 2)\n * ```\n */\nexport function simpleInterest(\n principal: Money,\n options: SimpleInterestOptions,\n): Money {\n const { rate, years, rounding = RoundingMode.HALF_EVEN } = options;\n\n // Handle edge cases\n if (rate.isZero() || years === 0) {\n return Money.zero(principal.currency);\n }\n\n // Simple Interest = Principal × Rate × Time\n const interestMultiplier = rate.toDecimal() * years;\n\n return principal.multiply(interestMultiplier, { rounding });\n}\n\n/**\n * Calculates the total amount (principal + simple interest).\n *\n * Uses the formula: Total = P × (1 + r × t)\n * Where:\n * - P = Principal amount\n * - r = Annual interest rate (as decimal)\n * - t = Time in years\n *\n * This represents the final amount you would have after earning\n * simple interest on the principal for the specified time period.\n *\n * @param principal - The principal amount as a Money object\n * @param options - Configuration options including rate, years, and rounding\n * @returns The total amount (principal + interest) as a Money object\n *\n * @example\n * ```typescript\n * const principal = Money.fromMajor(\"1000.00\", USD);\n * const rate = Rate.percent(5); // 5% annual rate\n * const total = simpleInterestTotal(principal, { rate, years: 2 });\n * console.log(total.format()); // \"$1,100.00\" (1000 × (1 + 0.05 × 2))\n * ```\n */\nexport function simpleInterestTotal(\n principal: Money,\n options: SimpleInterestOptions,\n): Money {\n const { rate, years, rounding = RoundingMode.HALF_EVEN } = options;\n\n // Handle edge cases\n if (rate.isZero() || years === 0) {\n return principal;\n }\n\n // Total Amount = Principal × (1 + rate × time)\n const totalMultiplier = 1 + rate.toDecimal() * years;\n\n return principal.multiply(totalMultiplier, { rounding });\n}\n","import { Money } from \"../money/Money\";\nimport { assertSameCurrency } from \"../money/guards\";\n\n/**\n * Input parameters for calculating all leverage ratios\n */\nexport interface LeverageInputs {\n totalDebt: Money;\n totalEquity: Money;\n totalAssets: Money;\n ebit: Money;\n interestExpense: Money;\n}\n\n/**\n * Result of leverage ratio calculations\n */\nexport interface LeverageResult {\n debtToEquity: number;\n debtToAssets: number;\n interestCoverage: number;\n equityMultiplier: number;\n}\n\n/**\n * Calculates the Debt-to-Equity (D/E) ratio,\n * Formula: Total Debt / Total Equity\n *\n * @param totalDebt - Total liabilities\n * @param totalEquity - Total shareholders' equity\n * @returns The D/E ratio as a number\n * @throws {Error} If totalEquity is zero\n */\nexport function debtToEquity(totalDebt: Money, totalEquity: Money): number {\n assertSameCurrency(totalDebt, totalEquity);\n if (totalEquity.isZero()) {\n throw new Error(\"Total equity cannot be zero\");\n }\n return Number(totalDebt.minor) / Number(totalEquity.minor);\n}\n\n/**\n * Calculates the Debt-to-Assets ratio.\n * Formula: Total Debt / Total Assets\n *\n * @param totalDebt - Total liabilities\n * @param totalAssets - Total assets\n * @returns The Debt-to-Assets ratio as a number\n * @throws {Error} If totalAssets is zero\n */\nexport function debtToAssets(totalDebt: Money, totalAssets: Money): number {\n assertSameCurrency(totalDebt, totalAssets);\n if (totalAssets.isZero()) {\n throw new Error(\"Total assets cannot be zero\");\n }\n return Number(totalDebt.minor) / Number(totalAssets.minor);\n}\n\n/**\n * Calculates the Interest Coverage ratio.\n * Formula: EBIT / Interest Expense\n *\n * @param ebit - Earnings Before Interest and Taxes\n * @param interestExpense - Total interest expense\n * @returns The Interest Coverage ratio. Returns Infinity if interest expense is zero\n */\nexport function interestCoverage(ebit: Money, interestExpense: Money): number {\n assertSameCurrency(ebit, interestExpense);\n if (interestExpense.isZero()) {\n return Infinity;\n }\n return Number(ebit.minor) / Number(interestExpense.minor);\n}\n\n/**\n * Calculates the Equity Multiplier\n * Formula: TotalAssets / TotalEquity\n *\n * @param totalAssets - Total assets\n * @param totalEquity - Total shareholders' equity\n * @returns The Equity Multiplier ratio as a number\n * @throws {Error} If total Equity is zero\n */\nexport function equityMultiplier(\n totalAssets: Money,\n totalEquity: Money,\n): number {\n assertSameCurrency(totalAssets, totalEquity);\n if (totalEquity.isZero()) {\n throw new Error(\"Total equity cannot be zero\");\n }\n return Number(totalAssets.minor) / Number(totalEquity.minor);\n}\n\n/**\n * Calculates all leverage ratios at once\n *\n * @param inputs - Object containing all necessary Money values\n * @returns An object with all calculated leverage ratios\n */\nexport function leverageRatios(inputs: LeverageInputs): LeverageResult {\n return {\n debtToEquity: debtToEquity(inputs.totalDebt, inputs.totalEquity),\n debtToAssets: debtToAssets(inputs.totalDebt, inputs.totalAssets),\n interestCoverage: interestCoverage(inputs.ebit, inputs.interestExpense),\n equityMultiplier: equityMultiplier(inputs.totalAssets, inputs.totalEquity),\n };\n}\n","import { Money } from \"../money/Money\";\nimport { RoundingMode } from \"../rounding/strategies\";\nimport { InvalidArgumentError } from \"../errors/InvalidArgumentError\";\nimport { CurrencyMismatchError } from \"../errors/CurrencyMismatchError\";\n\nexport interface DepreciationOptions {\n cost: Money;\n salvageValue: Money;\n usefulLife: number; // in years\n rounding?: RoundingMode;\n}\n\nexport interface DepreciationResult {\n annualDepreciation: Money;\n bookValueAtYear(year: number): Money;\n schedule(): { year: number; depreciation: Money; bookValue: Money }[];\n}\n\n/**\n * Calculates straight-line depreciation for an asset.\n *\n * Formula:\n * Annual Depreciation = (Cost - Salvage Value) / Useful Life\n * Book Value at Year N = Cost - (Annual Depreciation × N)\n *\n * @param options - Configuration for depreciation calculation\n * @returns Object containing annual depreciation, book value calculator, and schedule generator\n * @throws {CurrencyMismatchError} If cost and salvage value currencies differ\n * @throws {InvalidArgumentError} If useful life is not positive or salvage value > cost\n */\nexport function straightLineDepreciation(\n options: DepreciationOptions,\n): DepreciationResult {\n const {\n cost,\n salvageValue,\n usefulLife,\n rounding = RoundingMode.HALF_EVEN,\n } = options;\n\n if (cost.currency.code !== salvageValue.currency.code) {\n throw new CurrencyMismatchError(\n cost.currency.code,\n salvageValue.currency.code,\n );\n }\n\n if (usefulLife <= 0) {\n throw new InvalidArgumentError(\"Useful life must be positive\");\n }\n\n if (salvageValue.greaterThan(cost)) {\n throw new InvalidArgumentError(\"Salvage value cannot be greater than cost\");\n }\n\n const depreciableAmount = cost.subtract(salvageValue);\n const annualDepreciation = depreciableAmount.divide(usefulLife, { rounding });\n\n const result: DepreciationResult = {\n annualDepreciation,\n\n bookValueAtYear(year: number): Money {\n if (year < 0) {\n throw new InvalidArgumentError(\"Year must be non-negative\");\n }\n if (year === 0) return cost;\n\n const totalDepreciation = annualDepreciation.multiply(year);\n const bookValue = cost.subtract(totalDepreciation);\n\n // Ensure book value doesn't drop below salvage value\n if (bookValue.lessThan(salvageValue)) {\n return salvageValue;\n }\n return bookValue;\n },\n\n schedule(): { year: number; depreciation: Money; bookValue: Money }[] {\n const schedule = [];\n let previousBookValue = cost;\n const maxYears = Math.ceil(usefulLife);\n\n for (let year = 1; year <= maxYears; year++) {\n const currentBookValue = result.bookValueAtYear(year);\n const depreciation = previousBookValue.subtract(currentBookValue);\n\n schedule.push({\n year,\n depreciation,\n bookValue: currentBookValue,\n });\n\n previousBookValue = currentBookValue;\n }\n\n return schedule;\n },\n };\n\n return result;\n}\n","import { Entry } from \"./types\";\n\n/**\n * SHA-256 hash function that works in both Node.js and browsers.\n */\nlet hashFunction: ((data: string) => string | Promise<string>) | null = null;\n\n/**\n * Initializes the hash function based on the environment.\n * Uses Node.js crypto if available, falls back to SubtleCrypto for browsers.\n */\nfunction getHashFunction(): (data: string) => string | Promise<string> {\n if (hashFunction) return hashFunction;\n\n // Private escape hatch for tests to force the SubtleCrypto path.\n // This does not affect normal usage unless explicitly set.\n const disableNodeCrypto =\n (globalThis as unknown as { __MONETRA_DISABLE_NODE_CRYPTO__?: boolean })\n .__MONETRA_DISABLE_NODE_CRYPTO__ === true;\n\n // Try Node.js crypto first\n if (!disableNodeCrypto && typeof globalThis !== \"undefined\") {\n try {\n // Dynamic import to avoid bundler issues\n const nodeCrypto = require(\"crypto\");\n if (nodeCrypto && nodeCrypto.createHash) {\n hashFunction = (data: string): string => {\n return nodeCrypto.createHash(\"sha256\").update(data).digest(\"hex\");\n };\n return hashFunction;\n }\n } catch {\n // Node crypto not available\n }\n }\n\n // Fall back to SubtleCrypto (browser)\n if (\n typeof globalThis !== \"undefined\" &&\n globalThis.crypto &&\n globalThis.crypto.subtle\n ) {\n hashFunction = async (data: string): Promise<string> => {\n const encoder = new TextEncoder();\n const dataBuffer = encoder.encode(data);\n const hashBuffer = await globalThis.crypto.subtle.digest(\n \"SHA-256\",\n dataBuffer,\n );\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n };\n return hashFunction;\n }\n\n // No crypto available\n throw new Error(\n \"No cryptographic hash function available. \" +\n \"Ensure you are running in Node.js or a browser with SubtleCrypto support.\",\n );\n}\n\n/**\n * Allows injecting a custom hash function for testing or special environments.\n */\nexport function setHashFunction(\n fn: (data: string) => string | Promise<string>,\n): void {\n hashFunction = fn;\n}\n\nfunction serialize(data: unknown): string {\n return JSON.stringify(data, (_key, value) => {\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n // Handle Money objects if they are passed directly and not via toJSON\n if (\n value &&\n typeof value === \"object\" &&\n \"minor\" in value &&\n \"currency\" in value\n ) {\n return {\n minor: (value as { minor: bigint }).minor.toString(),\n currency: (value as { currency: { code: string } }).currency.code,\n };\n }\n return value;\n });\n}\n\n/**\n * Generates a SHA-256 hash of the provided data.\n * Works in both Node.js and browser environments.\n *\n * @param data - The data to hash.\n * @returns The hash as a hex string (sync in Node.js, may be async in browser).\n */\nexport function generateHash(data: unknown): string | Promise<string> {\n const serialized = serialize(data);\n const fn = getHashFunction();\n return fn(serialized);\n}\n\n/**\n * Synchronous version of generateHash for environments that support it.\n * Throws if only async hashing is available (browser without await).\n *\n * @param data - The data to hash.\n * @returns The hash as a hex string.\n */\nexport function generateHashSync(data: unknown): string {\n const result = generateHash(data);\n if (result instanceof Promise) {\n throw new Error(\n \"Synchronous hashing not available in this environment. \" +\n \"Use generateHash() with await instead.\",\n );\n }\n return result;\n}\n\n/**\n * Verifies the integrity of a chain of ledger entries.\n * Checks that each entry's hash is correct and that previousHash pointers form a valid chain.\n *\n * @param entries - The entries to verify.\n * @returns True if the chain is valid, false if tampered.\n */\nexport async function verifyChain(entries: Entry[]): Promise<boolean> {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const previousEntry = i > 0 ? entries[i - 1] : null;\n\n // Check previous hash pointer\n if (previousEntry) {\n if (entry.previousHash !== previousEntry.hash) return false;\n } else {\n if (entry.previousHash !== null) return false;\n }\n\n // Check integrity of current entry\n const { hash, ...content } = entry;\n const calculatedHash = await generateHash(content);\n\n if (hash !== calculatedHash) return false;\n }\n return true;\n}\n\n/**\n * Synchronous version of verifyChain for Node.js environments.\n *\n * @param entries - The entries to verify.\n * @returns True if the chain is valid.\n */\nexport function verifyChainSync(entries: Entry[]): boolean {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const previousEntry = i > 0 ? entries[i - 1] : null;\n\n if (previousEntry) {\n if (entry.previousHash !== previousEntry.hash) return false;\n } else {\n if (entry.previousHash !== null) return false;\n }\n\n const { hash, ...content } = entry;\n const calculatedHash = generateHashSync(content);\n\n if (hash !== calculatedHash) return false;\n }\n return true;\n}\n","import { Money } from \"../money/Money\";\nimport { Currency } from \"../currency/Currency\";\nimport { CurrencyMismatchError } from \"../errors/CurrencyMismatchError\";\nimport {\n Entry,\n TransactionMetadata,\n LedgerSnapshot,\n TransactionType,\n} from \"./types\";\nimport {\n generateHash,\n generateHashSync,\n verifyChain,\n verifyChainSync,\n} from \"./verification\";\nimport { randomUUID } from \"crypto\";\n\n/**\n * Current snapshot format version.\n */\nconst SNAPSHOT_VERSION = 2;\n\nexport class Ledger {\n private entries: Entry[] = [];\n private currency: string;\n\n constructor(currency: string | Currency) {\n this.currency = typeof currency === \"string\" ? currency : currency.code;\n }\n\n /**\n * Records a transaction in the ledger.\n * Returns the created entry for reference.\n * Note: This is the synchronous version for Node.js. Use recordAsync for browser support.\n */\n record(money: Money, metadata: TransactionMetadata): Entry {\n if (money.currency.code !== this.currency) {\n throw new CurrencyMismatchError(this.currency, money.currency.code);\n }\n\n const previousHash =\n this.entries.length > 0\n ? this.entries[this.entries.length - 1].hash\n : null;\n\n // Construct the entry content first\n const content = {\n id: randomUUID(),\n money,\n metadata: Object.freeze({\n ...metadata,\n timestamp: metadata.timestamp ?? new Date(),\n }),\n createdAt: new Date(),\n previousHash,\n };\n\n // Calculate hash (sync)\n const hash = generateHashSync(content);\n\n // Create full entry\n const entry: Entry = {\n ...content,\n hash,\n };\n\n this.entries.push(Object.freeze(entry)); // Immutable\n\n return entry;\n }\n\n /**\n * Records a transaction in the ledger (async version for browser support).\n * Returns the created entry for reference.\n */\n async recordAsync(\n money: Money,\n metadata: TransactionMetadata,\n ): Promise<Entry> {\n if (money.currency.code !== this.currency) {\n throw new CurrencyMismatchError(this.currency, money.currency.code);\n }\n\n const previousHash =\n this.entries.length > 0\n ? this.entries[this.entries.length - 1].hash\n : null;\n\n const content = {\n id: randomUUID(),\n money,\n metadata: Object.freeze({\n ...metadata,\n timestamp: metadata.timestamp ?? new Date(),\n }),\n createdAt: new Date(),\n previousHash,\n };\n\n const hash = await generateHash(content);\n\n const entry: Entry = {\n ...content,\n hash,\n };\n\n this.entries.push(Object.freeze(entry));\n\n return entry;\n }\n\n /**\n * Gets the current balance.\n */\n getBalance(): Money {\n return this.entries.reduce(\n (balance, entry) => balance.add(entry.money),\n Money.zero(this.currency),\n );\n }\n\n /**\n * Returns the complete transaction history.\n */\n getHistory(): ReadonlyArray<Entry> {\n return Object.freeze([...this.entries]);\n }\n\n /**\n * Filters entries by criteria.\n */\n query(filter: {\n type?: TransactionType | TransactionType[];\n from?: Date;\n to?: Date;\n reference?: string;\n minAmount?: Money;\n maxAmount?: Money;\n tags?: string[];\n }): Entry[] {\n return this.entries.filter((entry) => {\n if (filter.type) {\n const types = Array.isArray(filter.type) ? filter.type : [filter.type];\n if (!types.includes(entry.metadata.type)) return false;\n }\n if (filter.from && entry.createdAt < filter.from) return false;\n if (filter.to && entry.createdAt > filter.to) return false;\n if (filter.reference && entry.metadata.reference !== filter.reference)\n return false;\n if (filter.minAmount && entry.money.lessThan(filter.minAmount))\n return false;\n if (filter.maxAmount && entry.money.greaterThan(filter.maxAmount))\n return false;\n if (filter.tags && entry.metadata.tags) {\n const hasTag = filter.tags.some((tag) =>\n entry.metadata.tags?.includes(tag),\n );\n if (!hasTag) return false;\n }\n return true;\n });\n }\n\n /**\n * Verifies the integrity of the ledger using hash chain (sync version).\n * @returns true if all hashes are valid and chain is unbroken.\n */\n verify(): boolean {\n return verifyChainSync(this.entries);\n }\n\n /**\n * Verifies the integrity of the ledger using hash chain (async version for browsers).\n * @returns Promise resolving to true if all hashes are valid and chain is unbroken.\n */\n async verifyAsync(): Promise<boolean> {\n return verifyChain(this.entries);\n }\n\n /**\n * Exports a snapshot for backup/audit purposes (sync version).\n */\n snapshot(): LedgerSnapshot {\n return {\n version: SNAPSHOT_VERSION,\n entries: [...this.entries],\n balance: this.getBalance(),\n currency: this.currency,\n createdAt: new Date(),\n checksum: generateHashSync({ entries: this.entries }),\n };\n }\n\n /**\n * Exports a snapshot for backup/audit purposes (async version for browsers).\n */\n async snapshotAsync(): Promise<LedgerSnapshot> {\n const checksum = await generateHash({ entries: this.entries });\n return {\n version: SNAPSHOT_VERSION,\n entries: [...this.entries],\n balance: this.getBalance(),\n currency: this.currency,\n createdAt: new Date(),\n checksum,\n };\n }\n\n /**\n * Restores from a snapshot (sync version).\n */\n static fromSnapshot(snapshot: LedgerSnapshot): Ledger {\n const ledger = new Ledger(snapshot.currency);\n // Verify integrity before restoring\n if (!verifyChainSync(snapshot.entries)) {\n throw new Error(\"Ledger snapshot integrity check failed\");\n }\n ledger.entries = [...snapshot.entries];\n return ledger;\n }\n\n /**\n * Restores from a snapshot (async version for browsers).\n */\n static async fromSnapshotAsync(snapshot: LedgerSnapshot): Promise<Ledger> {\n const ledger = new Ledger(snapshot.currency);\n // Verify integrity before restoring\n const isValid = await verifyChain(snapshot.entries);\n if (!isValid) {\n throw new Error(\"Ledger snapshot integrity check failed\");\n }\n ledger.entries = [...snapshot.entries];\n return ledger;\n }\n}\n","import { Money } from \"./money\";\nimport { Currency } from \"./currency\";\n\nexport * from \"./money\";\nexport * from \"./currency\";\nexport * from \"./rounding\";\nexport * from \"./errors\";\nexport * from \"./financial\";\nexport * from \"./ledger\";\nexport * from \"./format/formatter\";\nexport * from \"./format/parser\";\n\n/**\n * Helper function to create Money instances.\n *\n * If amount is a number or BigInt, it is treated as minor units.\n * If amount is a string, it is treated as major units.\n *\n * @param amount - The amount (minor units if number/bigint, major units if string).\n * @param currency - The currency code or object.\n */\nexport function money(\n amount: number | bigint | string,\n currency: string | Currency,\n): Money {\n if (typeof amount === \"string\") {\n return Money.fromMajor(amount, currency);\n }\n return Money.fromMinor(amount, currency);\n}\n"],"mappings":"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","names":["RoundingMode","MonetraErrorCode","money","money","money","money","presentValue","money"]}