{"_id":"@birtalanrobert/money","_rev":"5-1bb58bccd30e5c3c9d42b61a2b04b915","name":"@birtalanrobert/money","dist-tags":{"latest":"1.1.1"},"versions":{"0.1.0":{"name":"@birtalanrobert/money","version":"0.1.0","license":"AGPL-3.0-only","_id":"@birtalanrobert/money@0.1.0","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"homepage":"https://github.com/birtalanrobert/mortar#readme","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"beaabf5840aa4d5197d3bb9b85962a9ff4d53d84","tarball":"https://registry.npmjs.org/@birtalanrobert/money/-/money-0.1.0.tgz","fileCount":44,"integrity":"sha512-6U+psAWPZXkiAtztMG24rCzFevOno4LTrTmij66KFr16PGYqsf4+xH04aOLlaLCgRaaER4OPSOY8ZxEETThJSg==","signatures":[{"sig":"MEUCIEbHNTZa4TNARooV3in8B6h4iwWJBYcBae7Do357LOx0AiEApgFYZ0Z/Tyuz0irP5ggQURWKVgHfXhSOWPB8kMEsiO0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":130995},"main":"./dist/index.js","type":"commonjs","_from":"file:birtalanrobert-money-0.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/0bf042d804c462f2b26021b3630b1e51/birtalanrobert-money-0.1.0.tgz","_integrity":"sha512-6U+psAWPZXkiAtztMG24rCzFevOno4LTrTmij66KFr16PGYqsf4+xH04aOLlaLCgRaaER4OPSOY8ZxEETThJSg==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/money"},"_npmVersion":"11.13.0","description":"Integer minor-unit money, arithmetic, allocation and formatting","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/money_0.1.0_1787664399899_0.8155170276674875","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@birtalanrobert/money","version":"0.2.0","license":"AGPL-3.0-only","_id":"@birtalanrobert/money@0.2.0","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"homepage":"https://github.com/birtalanrobert/mortar#readme","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"644fa1323f0a3e873b52fd541c4602fb7997bcd0","tarball":"https://registry.npmjs.org/@birtalanrobert/money/-/money-0.2.0.tgz","fileCount":45,"integrity":"sha512-g2oyRu2cO4/yM1kow2tZYiSHZkHFcjbut4lc9J1eTTGoe+eqlp1NQI502H78dvWLoE4ZTSpToQbOAUbcs4l2Cw==","signatures":[{"sig":"MEUCIHsG1EL4Ccaoi29ijmMGU3pPeyML6evEBO+1YM7JT62OAiEAlAnKXH+X9eM3/7zNWirXoPrAmwO9Ps8/Zv6Nu4UT+MM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":132988},"main":"./dist/index.js","type":"commonjs","_from":"file:birtalanrobert-money-0.2.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/7c4152aca1dc1c2cb055ab6a5555caca/birtalanrobert-money-0.2.0.tgz","_integrity":"sha512-g2oyRu2cO4/yM1kow2tZYiSHZkHFcjbut4lc9J1eTTGoe+eqlp1NQI502H78dvWLoE4ZTSpToQbOAUbcs4l2Cw==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/money"},"_npmVersion":"11.13.0","description":"Integer minor-unit money, arithmetic, allocation and formatting","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/money_0.2.0_1787732709339_0.28061483924775854","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@birtalanrobert/money","version":"1.0.0","license":"AGPL-3.0-only","_id":"@birtalanrobert/money@1.0.0","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"homepage":"https://github.com/birtalanrobert/mortar#readme","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"2a9cd95933b79de24b3df74a3a2b5ece629d7fc5","tarball":"https://registry.npmjs.org/@birtalanrobert/money/-/money-1.0.0.tgz","fileCount":45,"integrity":"sha512-RDwz8jKSEfQHxiemaRjW8BjA7USfSu0ppTPA0hYmiE7qtuvinq4/p9a5vnihZrclmuWbY/uEDIlsnNEN5ya6tA==","signatures":[{"sig":"MEUCIQCpL4NzAsfecqXulBqpdInJpV846YUbGjusOeTpk40xGQIgGAbuBVixKAele71sOdjZ2COMOTUGRFL3ySvppMTY/F4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":135988},"main":"./dist/index.js","type":"commonjs","_from":"file:birtalanrobert-money-1.0.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/31d3391a1b4d743a1275012cb76ccbef/birtalanrobert-money-1.0.0.tgz","_integrity":"sha512-RDwz8jKSEfQHxiemaRjW8BjA7USfSu0ppTPA0hYmiE7qtuvinq4/p9a5vnihZrclmuWbY/uEDIlsnNEN5ya6tA==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/money"},"_npmVersion":"11.13.0","description":"Integer minor-unit money, arithmetic, allocation and formatting","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/money_1.0.0_1787735893537_0.7007985600402356","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@birtalanrobert/money","version":"1.1.0","license":"AGPL-3.0-only","_id":"@birtalanrobert/money@1.1.0","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"homepage":"https://github.com/birtalanrobert/mortar#readme","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"0c6c332367ea5cf03e2f3710cf6d3c69c5c4e286","tarball":"https://registry.npmjs.org/@birtalanrobert/money/-/money-1.1.0.tgz","fileCount":50,"integrity":"sha512-ck5jz78FVI8OaFpNrfXKUix8k55SrV0BXPBGgn/F2ckrp15V9aN9CFnOUOPXGaFA4sWeMrkifvevw3fmd8QpPA==","signatures":[{"sig":"MEUCIQDN6UQUYJS87Or8rWI/5FJDfCK+ITItv5Cfw8DN98LrmQIgKPVCg1hH+kOPVb2bSzCnFol4897ZIPWkMUnDF+JZEWU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQD7F3IxWp7/In3ASxtMqFgC1kfGIYkxeBKT1n5nxSx2VAIhAP15b0BurvinUywc4bF5v1NzZK7qLBFCKM5xamh7BahS","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":256871},"main":"./dist/index.js","type":"commonjs","_from":"file:birtalanrobert-money-1.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./rates":{"types":"./dist/rates.d.ts","default":"./dist/rates.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/0a79774cacde9697ed250ad665a94d3f/birtalanrobert-money-1.1.0.tgz","_integrity":"sha512-ck5jz78FVI8OaFpNrfXKUix8k55SrV0BXPBGgn/F2ckrp15V9aN9CFnOUOPXGaFA4sWeMrkifvevw3fmd8QpPA==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/money"},"_npmVersion":"11.13.0","description":"Integer minor-unit money, arithmetic, allocation and formatting","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/money_1.1.0_1789549580154_0.8237871424845069","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"_id":"@birtalanrobert/money@1.1.1","bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"dist":{"shasum":"59e0742234b018a9c72a05df4194cfe0c3c5ec6c","tarball":"https://registry.npmjs.org/@birtalanrobert/money/-/money-1.1.1.tgz","fileCount":50,"integrity":"sha512-S4csRp57eDG/SjwOL3rcWjGG98+jKL8JRMpsNe7Zbwe3FFjIYutuY4SCPyr4GoJkyS2vrk1sxGaywSsr686EPQ==","signatures":[{"sig":"MEUCIQDrRsUE8BNdFIGXDAAKKxMLW1VTRSNAQakTmq9XTzjHrAIgXi7IWFsICRXO7Epg4huXGo2EUS0yJhvXfwmTtWwpe+U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEfD8xYkssvM58GbwObm1FTqctbSdBz+Dg2NraME6tMhAiEAvOwNU5BCdXzo6xDgtuIWCRmn8jM6MOSitrnwApj2krk="}],"unpackedSize":256892},"main":"./dist/index.js","name":"@birtalanrobert/money","type":"commonjs","_from":"file:birtalanrobert-money-1.1.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./rates":{"types":"./dist/rates.d.ts","default":"./dist/rates.js"},"./package.json":"./package.json"},"license":"AGPL-3.0-only","scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist *.tsbuildinfo","typecheck":"tsc -p tsconfig.json"},"version":"1.1.1","_npmUser":{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"},"homepage":"https://github.com/birtalanrobert/mortar#readme","_resolved":"/private/var/folders/zx/7dcyg3mn6kjfyzsymzgpx1jr0000gn/T/29a153485ad5372d7bfcee6a23ba2970/birtalanrobert-money-1.1.1.tgz","_integrity":"sha512-S4csRp57eDG/SjwOL3rcWjGG98+jKL8JRMpsNe7Zbwe3FFjIYutuY4SCPyr4GoJkyS2vrk1sxGaywSsr686EPQ==","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/money"},"_npmVersion":"11.13.0","description":"Integer minor-unit money, arithmetic, allocation and formatting","directories":{},"maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/money_1.1.1_1789562938906_0.4518554348563457"}}},"time":{"created":"2026-08-25T13:26:39.646Z","modified":"2026-09-16T12:48:59.159Z","0.1.0":"2026-08-25T13:26:40.065Z","0.2.0":"2026-08-26T08:25:09.502Z","1.0.0":"2026-08-26T09:18:13.667Z","1.1.0":"2026-09-16T09:06:20.252Z","1.1.1":"2026-09-16T12:48:58.997Z"},"bugs":{"url":"https://github.com/birtalanrobert/mortar/issues"},"license":"AGPL-3.0-only","homepage":"https://github.com/birtalanrobert/mortar#readme","repository":{"url":"git+https://github.com/birtalanrobert/mortar.git","type":"git","directory":"packages/money"},"description":"Integer minor-unit money, arithmetic, allocation and formatting","maintainers":[{"name":"birtalanrobert","email":"birtalanrobert@gmail.com"}],"readme":"# @birtalanrobert/money\n\nInteger minor-unit money. No floats, ever, at any point in the chain.\n\nThis requirement comes up in every financial system — _\"money in integer minor units, never floats\"_ — which is why\nthis package exists and why it has no dependencies.\n\n## Using it in a NestJS application\n\n**There is no module to import.** This package is pure functions and a value\ntype with no dependencies, so it is imported directly wherever it is needed —\nin a service, in a domain module, in a React component, in a worker.\n\n```ts\nimport { money, add, format } from '@birtalanrobert/money';\n\nconst price = money(1999, 'RON'); // 19.99 RON\nconst total = add(price, money(500, 'RON'));\n```\n\nPersisting it is two columns, never a float. The column helpers live in\n`@birtalanrobert/database`, so that this package stays dependency-free:\n\n```ts\nimport { MONEY_AMOUNT_COLUMN, CURRENCY_COLUMN } from '@birtalanrobert/database';\n\n@Column(MONEY_AMOUNT_COLUMN) amount!: number;\n@Column(CURRENCY_COLUMN) currency!: string;\n```\n\nBeing dependency-free is the point: a Next.js bundle can format a price without\ninstalling an ORM, and a worker can total an invoice without a framework.\n\n## Core ideas\n\n- **`Money` is `{ amount, currency }`**, where `amount` is a safe integer count\n  of minor units (cents, bani, fillér). It is frozen on construction.\n- **Currency is never implicit.** Mixing currencies throws rather than coercing;\n  quietly coercing is how money goes missing.\n- **Floats enter in exactly one place** — `fromMajor()` — because user input and\n  third-party payloads arrive that way. They never leave except through\n  `toMajor()` for display.\n\n## Usage\n\n```ts\nimport { money, fromMajor, add, allocate, fromNet, format } from '@birtalanrobert/money';\n\nconst price = fromMajor(12.34, 'EUR'); // 1234 minor units\nconst total = add(price, money(500, 'EUR')); // 1734\n\n// VAT, with net and gross always distinguishable\nconst line = fromNet(total, 19);\nline.net.amount; // 1734\nline.tax.amount; // 329\nline.gross.amount; // 2063\n\n// Splitting without losing a cent\nallocate(money(1000, 'EUR'), [1, 1, 1]); // 334, 333, 333 — sums to exactly 1000\n\nformat(price, { locale: 'ro-RO' });\n```\n\n## Currencies\n\nEUR, RON, HUF and the surrounding regional currencies are registered by default\nwith their ISO 4217 exponents. **Note that ISO gives HUF an exponent of 2** even\nthough Hungarian everyday practice uses whole forints. If a project wants\ninteger forints it must say so explicitly at boot, rather than relying on a\nsurprising default:\n\n```ts\nregisterCurrency({ code: 'HUF', exponent: 0, name: 'Hungarian forint' });\n```\n\n## Rounding\n\n`RoundingMode.HalfUp` is the default, deliberately: these are commercial\napplications issuing invoices, and HalfUp is what the surrounding paperwork and\nthe customer's own arithmetic use. `HalfEven` is available for statistical work.\n\n## Allocation\n\n`allocate()` is the algorithm behind every bill split, fee distribution,\ndiscount apportionment and commission calculation. Shares are\nhanded out by integer division and the remaining units distributed to the\nlargest fractional remainders — so the parts **always** sum exactly back to the\nwhole, for any input, including negatives.\n\nThe naive alternative (multiply by ratio, round each) either loses money or\ninvents it, and the discrepancy surfaces later as an unexplainable one-cent\ndifference on a reconciliation report.\n\n## Tax\n\n`fromGross()` derives the net from the gross rather than recomputing it, so\n`net + tax === gross` exactly. The gross is what the customer actually paid and\nit must not move. Verified across every rate in use in both target markets.\n\n## Exchange rates\n\nBehind a subpath, because most consumers of this package format prices and never\nconvert between currencies — and a barrel that re-exported the rate arithmetic\nwould put it in every one of their bundles.\n\n```ts\nimport { convert, invert, rate, rateOn, rateToString } from '@birtalanrobert/money/rates';\n\nconst bnr = rate('EUR', 'RON', '4.9772', { asOf: '2026-09-15', source: 'BNR' });\n\nconvert(fromMajor(450, 'EUR'), bnr); // { amount: 223_974, currency: 'RON' }\n```\n\nFour decisions, each of which is a bug this prevents:\n\n- **Direction is part of the value.** `base` is what one unit of is priced,\n  `quote` is what it is priced in. `convert` throws `RateDirectionError` rather\n  than inverting silently — applying a EUR/RON rate to lei gives an answer wrong\n  by a factor of twenty-five that looks entirely plausible on a screen.\n- **A rate is never a float.** It is an integer scaled by `10 ** RATE_SCALE`\n  (ten decimal places, the same precision as a `numeric(20, 10)` column), parsed\n  from the decimal string a central bank publishes. `Number('1.005')` is\n  `1.00499999999999989`, and that is a rate one unit short of the real one.\n- **Conversion goes through major units.** Minor-unit counts differ — EUR has\n  two, JPY has none — so `minor × rate` is right only by coincidence. The whole\n  calculation is `bigint` and rounds once at the end, because a million euros\n  times a scaled rate is two hundred times past the largest exact integer a\n  JavaScript number holds.\n- **`rateOn` takes the latest published on or before a day, never after.**\n  Central banks do not publish at weekends and rent falls due on the first. A\n  lookup that reached forward would give a different answer depending on when\n  the report was run.\n\n`conversionFactor` returns the same arithmetic as an exact rational, for callers\ncarrying a value `Money` cannot hold — a price _per gram_, a fractional count of\nminor units. Multiply first, divide second.\n\n`invert` exists and is lossy by nature: 4.9772 inverts to 0.2009161778 and back\nto 4.9771999993. Store the published direction and convert once.\n","readmeFilename":"README.md"}