A small, exact Money value object for TypeScript. The core has no runtime dependencies: amounts are
stored as safe integer minor units, currencies are explicit, and operations that can fail return
typed Result values instead of throwing. An optional @ma.vu/app-money/effect entry point adds
Effect, Either, Schema, and collection adapters.
The package is ESM-only and targets ES2022.
Requirements: Node.js 22.21.1 for development and Corepack. The built package supports Node.js 20 and later.
corepack enable
pnpm install --frozen-lockfile
pnpm test
import { add, fromDecimal, toDecimalString } from "@ma.vu/app-money";
const subtotal = fromDecimal("12.50", "CHF");
const delivery = fromDecimal("3.00", "CHF");
if (subtotal.ok && delivery.ok) {
const total = add(subtotal.value, delivery.value);
if (total.ok) console.log(toDecimalString(total.value)); // "15.50"
}
For Effect applications, install the optional effect peer and import adapters separately so core
consumers never load it:
import { Effect } from "effect";
import { fromDecimal } from "@ma.vu/app-money/effect";
const amount = await Effect.runPromise(fromDecimal("12.50", "CHF"));
| Command | Purpose |
|---|---|
pnpm test |
Run the Vitest suite once. |
pnpm test:watch |
Re-run only affected tests while editing. |
pnpm test:coverage |
Enforce thresholds and write HTML, LCOV, and JSON reports to coverage/. |
pnpm typecheck |
Run strict TypeScript checks without emitting files. |
pnpm lint |
Check lint rules, formatting, and import order with Biome. |
pnpm lint:fix |
Apply safe lint, formatting, and import-order fixes. |
pnpm build |
Build the minified ESM package and declarations in dist/. |
pnpm docs:build |
Build searchable API docs and guides in .artifacts/docs/. |
pnpm changeset |
Record the SemVer impact and release note for a consumer-visible change. |
pnpm size |
Build, print raw/gzip/Brotli sizes, and enforce the budget. |
pnpm package:check |
Validate exports, consumer types, and a real import of the built package. |
pnpm deadcode |
Find unused files, exports, and dependencies. |
pnpm security:audit |
Fail on known high- or critical-severity dependency advisories. |
pnpm check |
Run every local quality gate used by CI. |
Open coverage/index.html after pnpm test:coverage for line-by-line coverage. The current gates
require 100% line and function coverage, 99% statement coverage, and 95% branch coverage. In
addition to example tests, the suite generates 8,000 cases over round trips, allocations,
arithmetic, comparisons, and signs.
pnpm size reports both built entry points in raw, gzip, and Brotli bytes. Hard limits live in
size-budget.json, so budget changes are visible in code review.
It also refreshes the README badge with the current gzip sizes; CI fails if that badge is stale.
On every pull request, the Bundle size workflow builds both the base revision and the proposed revision. Its GitHub job summary shows the exact Brotli delta and fails if the new bundle exceeds the checked-in budget. The machine-readable reports are retained as CI artifacts for 14 days.
main, plus a weekly scheduled scan.pnpm-workspace.yaml.The generated documentation site combines hand-written
guides with API reference for both the core and optional Effect entry points. It is rebuilt on every
pull request, generated from source, and deployed from main; generated HTML is never committed.
Consumer-visible changes include a small changeset file in the same pull request. See
guides/releasing.md for the reviewed release flow and one-time npm trusted
publisher setup.
examples/react-native/money-text.tsx shows an accessible
app-level MoneyText component. It intentionally stays outside the package because it imports the
host application's typography component and path aliases. Copy it into the host app and connect
its locale source there; the dependency-free domain package remains portable.
See CONTRIBUTING.md for the development flow. Please report vulnerabilities privately as described in SECURITY.md.
MIT