first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
# @suaveplan/money - Universal precise currency/money arithmetic using integer minor-unit (bigint) representation: immutable Money class with full arithmetic + comparison + conversion surface, locale-aware Intl-backed formatting (formatMoney, formatMoneyCompact), fair allocators preserving the input total (allocateEvenly, allocateByRatios, allocateByPercentages), aggregators (sumMoney, minMoney, maxMoney), 30 ISO 4217 fiat + 5 cryptocurrency built-ins, custom and virtual currency registration, lossless JSON round-trip, typed MoneyError hierarchy with stable MONEY.* code registry.
Universal precise currency and money arithmetic using integer minor-unit
representation. All operations use `bigint` so consumers never hit
floating-point rounding drift; cross-currency mistakes raise typed errors;
allocations preserve the input total to the minor unit.
<!-- begin:auto-docs -->
## Documentation tree
- [allocator](./src/allocator/allocator.md) — The allocator module solves two related problems: splitting a `Money` amount across N recipients (or N weights or N per…
- [allocator](./src/allocator/allocator.md) — The allocator module solves two related problems: splitting a `Money` amount across N recipients (or N weights or N per…
- [currencies](./src/currencies/currencies.md) — This module owns the currency-metadata registry that every other part of `@suaveplan/money` consults to compute minor-u…
- [currencies](./src/currencies/currencies.md) — This module owns the currency-metadata registry that every other part of `@suaveplan/money` consults to compute minor-u…
- [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/money` raises only typed errors. This module owns the stable `MONEY_CODES` registry (built with `defineCode…
- [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/money` raises only typed errors. This module owns the stable `MONEY_CODES` registry (built with `defineCode…
- [formatter](./src/formatter/formatter.md) — The formatter renders `MoneyLike` values to human-readable strings using `Intl.NumberFormat(locale)`-derived separators…
- [formatter](./src/formatter/formatter.md) — The formatter renders `MoneyLike` values to human-readable strings using `Intl.NumberFormat(locale)`-derived separators…
- [money](./src/money/money.md) — `Money` is the cornerstone of the package: an immutable value object that stores monetary amounts as `bigint` minor uni…
- [money](./src/money/money.md) — `Money` is the cornerstone of the package: an immutable value object that stores monetary amounts as `bigint` minor uni…
- [types](./src/types/common.md) — `@suaveplan/money` exposes a small, stable set of types that downstream packages (`@suaveplan/currency`, `@suaveplan/pa…
- [common](./src/types/common.md) — `@suaveplan/money` exposes a small, stable set of types that downstream packages (`@suaveplan/currency`, `@suaveplan/pa…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/money
```
## Quick start
```ts
import { Money, formatMoney, allocateEvenly } from "@suaveplan/money";
const price = Money.fromMajor(29.99, "USD");
const tax = price.multiply(0.08);
const total = price.add(tax);
console.log(formatMoney(total)); // "$32.39"
console.log(total.toDecimalString()); // "32.39"
// Split a $32.39 bill among 3 — no penny lost
const { shares } = allocateEvenly(total, 3);
console.log(shares.map((s) => formatMoney(s))); // ["$10.80", "$10.80", "$10.79"]
```
## Features
- **Immutable `Money` class** with full arithmetic (`add`, `subtract`,
`multiply`, `divide`, `abs`, `negate`), comparison (`compareTo`, `equals`,
`greaterThan`, ...), and conversion (`toMajor`, `toDecimalString`, `toJSON`,
`toString`).
- **30 ISO 4217 fiat currencies** (USD, EUR, GBP, JPY, ...) plus **5
cryptocurrencies** (BTC, ETH, SOL, USDT, USDC) with accurate exponents.
- **Custom and virtual currency registration** via `registerCurrency(info)`
with `virtual` / `issuerId` flags for game-currency use cases.
- **Locale-aware formatting** through `Intl.NumberFormat`-derived separators;
`decimalSeparator` / `thousandsSeparator` overrides for locked output.
- **Compact notation** (`formatMoneyCompact`) with K / M / B suffixes.
- **Fair allocators** (`allocateEvenly`, `allocateByRatios`,
`allocateByPercentages`) that always preserve the input total.
- **Aggregators** (`sumMoney`, `minMoney`, `maxMoney`) with typed empty-input
and cross-currency guards.
- **Lossless JSON round-trip** via `Money.toJSON()` / `Money.fromJSON()`
(`bigint` encoded as decimal string).
- **Typed `MoneyError` hierarchy** extending `SuaveplanError<MoneyErrorCode>`
with stable `MONEY.*` code registry and `currency` / `otherCurrency`
discriminants.
- **Subpath exports** for every public module so consumers can tree-shake.
- **Universal** — no `node:*`, `bun:*`, DOM, or fs imports; runs unchanged
on Node ≥ 18, Bun, browsers, and Web Workers.
## Modules
- [`money/money.md`](./src/money/money.md) — `Money` class + `applyRounding`
- [`currencies/currencies.md`](./src/currencies/currencies.md) — built-in
registry, lookup, custom / virtual currency registration
- [`formatter/formatter.md`](./src/formatter/formatter.md) — `formatMoney` +
`formatMoneyCompact`
- [`allocator/allocator.md`](./src/allocator/allocator.md) — allocators +
aggregators (`sumMoney`, `minMoney`, `maxMoney`)
- [`error-codes/error-codes.md`](./src/error-codes/error-codes.md) —
`MONEY_CODES` registry + `MoneyError` class
- [`types/common.md`](./src/types/common.md) — public type contracts
## Subpath exports
```ts
import { Money } from "@suaveplan/money/money/money";
import { formatMoney } from "@suaveplan/money/formatter/formatter";
import { allocateEvenly } from "@suaveplan/money/allocator/allocator";
import { registerCurrency } from "@suaveplan/money/currencies/currencies";
import { MoneyError } from "@suaveplan/money/error-codes/error-codes";
import type { MoneyLike } from "@suaveplan/money/types/common";
```
## Error handling
Every failure path raises a typed `MoneyError` carrying a stable
`MONEY.*` code. Six codes are declared: `CURRENCY_MISMATCH`,
`UNKNOWN_CURRENCY`, `DIVISION_BY_ZERO`, `INVALID_ALLOCATION`, `EMPTY_INPUT`,
`PARSE_ERROR`.
```ts
import { Money, MoneyError, MONEY_CODES } from "@suaveplan/money";
try {
Money.fromMinor(100n, "USD").add(Money.fromMinor(50n, "EUR"));
} catch (err) {
if (err instanceof MoneyError && err.code === MONEY_CODES.CURRENCY_MISMATCH) {
console.error(`mismatch: ${err.currency} vs ${err.otherCurrency}`);
}
}
```
## License
MIT — © Suaveplan Team