subunit-money 3.0.0 → 3.1.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.
package/dist/currency.js CHANGED
@@ -1,15 +1,7 @@
1
- "use strict";
2
1
  /**
3
2
  * Currency registry and types.
4
3
  * Manages ISO 4217 currency definitions and custom currencies.
5
4
  */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.registerCurrency = registerCurrency;
8
- exports.getCurrency = getCurrency;
9
- exports.hasCurrency = hasCurrency;
10
- exports.getAllCurrencies = getAllCurrencies;
11
- exports.loadCurrencyMap = loadCurrencyMap;
12
- exports.clearCurrencies = clearCurrencies;
13
5
  // Internal registry - mutable for registerCurrency()
14
6
  const currencies = new Map();
15
7
  /**
@@ -17,33 +9,33 @@ const currencies = new Map();
17
9
  * @param code - ISO 4217 currency code (e.g., 'USD', 'EUR', 'BTC')
18
10
  * @param decimalDigits - Number of decimal places (e.g., 2 for USD, 8 for BTC)
19
11
  */
20
- function registerCurrency(code, decimalDigits) {
12
+ export function registerCurrency(code, decimalDigits) {
21
13
  currencies.set(code, { code, decimalDigits });
22
14
  }
23
15
  /**
24
16
  * Get a currency definition by code.
25
17
  * @returns The currency definition, or undefined if not registered
26
18
  */
27
- function getCurrency(code) {
19
+ export function getCurrency(code) {
28
20
  return currencies.get(code);
29
21
  }
30
22
  /**
31
23
  * Check if a currency is registered.
32
24
  */
33
- function hasCurrency(code) {
25
+ export function hasCurrency(code) {
34
26
  return currencies.has(code);
35
27
  }
36
28
  /**
37
29
  * Get all registered currencies, sorted by code.
38
30
  */
39
- function getAllCurrencies() {
31
+ export function getAllCurrencies() {
40
32
  return Array.from(currencies.values()).sort((a, b) => a.code.localeCompare(b.code));
41
33
  }
42
34
  /**
43
35
  * Load currencies from the legacy currencymap.json format.
44
36
  * @param map - Object with currency codes as keys and {decimal_digits: number} as values
45
37
  */
46
- function loadCurrencyMap(map) {
38
+ export function loadCurrencyMap(map) {
47
39
  for (const [code, data] of Object.entries(map)) {
48
40
  registerCurrency(code, data.decimal_digits);
49
41
  }
@@ -51,6 +43,6 @@ function loadCurrencyMap(map) {
51
43
  /**
52
44
  * Clear all registered currencies. Useful for testing.
53
45
  */
54
- function clearCurrencies() {
46
+ export function clearCurrencies() {
55
47
  currencies.clear();
56
48
  }
package/dist/errors.js CHANGED
@@ -1,16 +1,13 @@
1
- "use strict";
2
1
  /**
3
2
  * Custom error types for Money operations.
4
3
  * All errors extend built-in Error types for proper instanceof checks.
5
4
  */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ExchangeRateError = exports.AmountError = exports.SubunitError = exports.CurrencyUnknownError = exports.CurrencyMismatchError = void 0;
8
5
  /**
9
6
  * Thrown when attempting operations between different currencies.
10
7
  * @example
11
8
  * new Money('USD', 10).add(new Money('EUR', 5)) // throws CurrencyMismatchError
12
9
  */
13
- class CurrencyMismatchError extends TypeError {
10
+ export class CurrencyMismatchError extends TypeError {
14
11
  constructor(fromCurrency, toCurrency) {
15
12
  super(`Cannot operate on ${fromCurrency} and ${toCurrency} - currencies must match`);
16
13
  this.name = 'CurrencyMismatchError';
@@ -19,13 +16,12 @@ class CurrencyMismatchError extends TypeError {
19
16
  Error.captureStackTrace?.(this, CurrencyMismatchError);
20
17
  }
21
18
  }
22
- exports.CurrencyMismatchError = CurrencyMismatchError;
23
19
  /**
24
20
  * Thrown when using an unregistered currency code.
25
21
  * @example
26
22
  * new Money('FAKE', 10) // throws CurrencyUnknownError
27
23
  */
28
- class CurrencyUnknownError extends TypeError {
24
+ export class CurrencyUnknownError extends TypeError {
29
25
  constructor(currency) {
30
26
  super(`Unknown currency '${currency}' - register it first with Money.registerCurrency()`);
31
27
  this.name = 'CurrencyUnknownError';
@@ -33,13 +29,12 @@ class CurrencyUnknownError extends TypeError {
33
29
  Error.captureStackTrace?.(this, CurrencyUnknownError);
34
30
  }
35
31
  }
36
- exports.CurrencyUnknownError = CurrencyUnknownError;
37
32
  /**
38
33
  * Thrown when an amount has more decimal places than the currency allows.
39
34
  * @example
40
35
  * new Money('USD', '1.234') // throws SubunitError (USD only allows 2 decimals)
41
36
  */
42
- class SubunitError extends RangeError {
37
+ export class SubunitError extends RangeError {
43
38
  constructor(currency, maxDecimals) {
44
39
  super(`${currency} only supports ${maxDecimals} decimal place(s)`);
45
40
  this.name = 'SubunitError';
@@ -48,13 +43,12 @@ class SubunitError extends RangeError {
48
43
  Error.captureStackTrace?.(this, SubunitError);
49
44
  }
50
45
  }
51
- exports.SubunitError = SubunitError;
52
46
  /**
53
47
  * Thrown when an amount cannot be parsed as a valid number.
54
48
  * @example
55
49
  * new Money('USD', 'abc') // throws AmountError
56
50
  */
57
- class AmountError extends TypeError {
51
+ export class AmountError extends TypeError {
58
52
  constructor(amount) {
59
53
  super(`Invalid amount: ${JSON.stringify(amount)}`);
60
54
  this.name = 'AmountError';
@@ -62,13 +56,12 @@ class AmountError extends TypeError {
62
56
  Error.captureStackTrace?.(this, AmountError);
63
57
  }
64
58
  }
65
- exports.AmountError = AmountError;
66
59
  /**
67
60
  * Thrown when an exchange rate is not available.
68
61
  * @example
69
62
  * converter.convert(usdMoney, 'XYZ') // throws ExchangeRateError if no USD->XYZ rate
70
63
  */
71
- class ExchangeRateError extends Error {
64
+ export class ExchangeRateError extends Error {
72
65
  constructor(fromCurrency, toCurrency) {
73
66
  super(`No exchange rate available from ${fromCurrency} to ${toCurrency}`);
74
67
  this.name = 'ExchangeRateError';
@@ -77,4 +70,3 @@ class ExchangeRateError extends Error {
77
70
  Error.captureStackTrace?.(this, ExchangeRateError);
78
71
  }
79
72
  }
80
- exports.ExchangeRateError = ExchangeRateError;
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Exchange Rate Service - Central authority for currency conversion rates.
4
3
  *
@@ -14,8 +13,6 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
14
13
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
15
14
  };
16
15
  var _ExchangeRateService_instances, _ExchangeRateService_rates, _ExchangeRateService_key;
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.ExchangeRateService = void 0;
19
16
  /**
20
17
  * Service for managing exchange rates between currencies.
21
18
  *
@@ -24,7 +21,7 @@ exports.ExchangeRateService = void 0;
24
21
  * rates.setRate('USD', 'EUR', 0.92, 'ECB')
25
22
  * rates.getRate('USD', 'EUR') // { from: 'USD', to: 'EUR', rate: '0.92', ... }
26
23
  */
27
- class ExchangeRateService {
24
+ export class ExchangeRateService {
28
25
  constructor() {
29
26
  _ExchangeRateService_instances.add(this);
30
27
  _ExchangeRateService_rates.set(this, new Map()
@@ -168,7 +165,6 @@ class ExchangeRateService {
168
165
  }
169
166
  }
170
167
  }
171
- exports.ExchangeRateService = ExchangeRateService;
172
168
  _ExchangeRateService_rates = new WeakMap(), _ExchangeRateService_instances = new WeakSet(), _ExchangeRateService_key = function _ExchangeRateService_key(from, to) {
173
169
  return `${from}:${to}`;
174
170
  };
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * subunit-money - A type-safe value object for monetary amounts
4
3
  *
@@ -16,33 +15,14 @@
16
15
  * const converter = new MoneyConverter(rates)
17
16
  * const euros = converter.convert(total, 'EUR')
18
17
  */
19
- var __importDefault = (this && this.__importDefault) || function (mod) {
20
- return (mod && mod.__esModule) ? mod : { "default": mod };
21
- };
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.clearCurrencies = exports.loadCurrencyMap = exports.getAllCurrencies = exports.hasCurrency = exports.getCurrency = exports.registerCurrency = exports.ExchangeRateError = exports.AmountError = exports.SubunitError = exports.CurrencyUnknownError = exports.CurrencyMismatchError = exports.MoneyConverter = exports.ExchangeRateService = exports.Money = void 0;
24
18
  // Core classes
25
- var money_js_1 = require("./money.js");
26
- Object.defineProperty(exports, "Money", { enumerable: true, get: function () { return money_js_1.Money; } });
27
- var exchange_rate_service_js_1 = require("./exchange-rate-service.js");
28
- Object.defineProperty(exports, "ExchangeRateService", { enumerable: true, get: function () { return exchange_rate_service_js_1.ExchangeRateService; } });
29
- var money_converter_js_1 = require("./money-converter.js");
30
- Object.defineProperty(exports, "MoneyConverter", { enumerable: true, get: function () { return money_converter_js_1.MoneyConverter; } });
19
+ export { Money } from './money.js';
20
+ export { ExchangeRateService } from './exchange-rate-service.js';
21
+ export { MoneyConverter } from './money-converter.js';
31
22
  // Error types
32
- var errors_js_1 = require("./errors.js");
33
- Object.defineProperty(exports, "CurrencyMismatchError", { enumerable: true, get: function () { return errors_js_1.CurrencyMismatchError; } });
34
- Object.defineProperty(exports, "CurrencyUnknownError", { enumerable: true, get: function () { return errors_js_1.CurrencyUnknownError; } });
35
- Object.defineProperty(exports, "SubunitError", { enumerable: true, get: function () { return errors_js_1.SubunitError; } });
36
- Object.defineProperty(exports, "AmountError", { enumerable: true, get: function () { return errors_js_1.AmountError; } });
37
- Object.defineProperty(exports, "ExchangeRateError", { enumerable: true, get: function () { return errors_js_1.ExchangeRateError; } });
23
+ export { CurrencyMismatchError, CurrencyUnknownError, SubunitError, AmountError, ExchangeRateError, } from './errors.js';
38
24
  // Currency utilities
39
- var currency_js_1 = require("./currency.js");
40
- Object.defineProperty(exports, "registerCurrency", { enumerable: true, get: function () { return currency_js_1.registerCurrency; } });
41
- Object.defineProperty(exports, "getCurrency", { enumerable: true, get: function () { return currency_js_1.getCurrency; } });
42
- Object.defineProperty(exports, "hasCurrency", { enumerable: true, get: function () { return currency_js_1.hasCurrency; } });
43
- Object.defineProperty(exports, "getAllCurrencies", { enumerable: true, get: function () { return currency_js_1.getAllCurrencies; } });
44
- Object.defineProperty(exports, "loadCurrencyMap", { enumerable: true, get: function () { return currency_js_1.loadCurrencyMap; } });
45
- Object.defineProperty(exports, "clearCurrencies", { enumerable: true, get: function () { return currency_js_1.clearCurrencies; } });
25
+ export { registerCurrency, getCurrency, hasCurrency, getAllCurrencies, loadCurrencyMap, clearCurrencies, } from './currency.js';
46
26
  // Auto-load default currencies
47
27
  // The currencymap.json file is the official ISO 4217 currency list (List One) as of 2026-01-01,
48
28
  // sourced from SIX Financial Information AG (the ISO 4217 Maintenance Agency).
@@ -53,6 +33,6 @@ Object.defineProperty(exports, "clearCurrencies", { enumerable: true, get: funct
53
33
  //
54
34
  // Note: This excludes historical currencies, supranational funds, and precious metals,
55
35
  // keeping only active national and regional currencies for practical use.
56
- const currency_js_2 = require("./currency.js");
57
- const currencymap_json_1 = __importDefault(require("../currencymap.json"));
58
- (0, currency_js_2.loadCurrencyMap)(currencymap_json_1.default);
36
+ import { loadCurrencyMap } from './currency.js';
37
+ import currencyMap from '../currencymap.json';
38
+ loadCurrencyMap(currencyMap);
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Money Converter - Safe cross-currency operations.
4
3
  *
@@ -19,11 +18,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
19
18
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
20
19
  };
21
20
  var _MoneyConverter_instances, _MoneyConverter_rateService, _MoneyConverter_bankersRound;
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.MoneyConverter = void 0;
24
- const money_js_1 = require("./money.js");
25
- const errors_js_1 = require("./errors.js");
26
- const currency_js_1 = require("./currency.js");
21
+ import { Money } from './money.js';
22
+ import { ExchangeRateError, CurrencyUnknownError } from './errors.js';
23
+ import { getCurrency } from './currency.js';
27
24
  /**
28
25
  * Converter for performing operations between different currencies.
29
26
  *
@@ -35,7 +32,7 @@ const currency_js_1 = require("./currency.js");
35
32
  * const euros = converter.convert(new Money('USD', '100'), 'EUR')
36
33
  * console.log(euros.toString()) // "92.00 EUR"
37
34
  */
38
- class MoneyConverter {
35
+ export class MoneyConverter {
39
36
  constructor(rateService) {
40
37
  _MoneyConverter_instances.add(this);
41
38
  _MoneyConverter_rateService.set(this, void 0);
@@ -53,15 +50,15 @@ class MoneyConverter {
53
50
  if (money.currency === targetCurrency) {
54
51
  return money;
55
52
  }
56
- const currencyDef = (0, currency_js_1.getCurrency)(targetCurrency);
53
+ const currencyDef = getCurrency(targetCurrency);
57
54
  if (!currencyDef) {
58
- throw new errors_js_1.CurrencyUnknownError(targetCurrency);
55
+ throw new CurrencyUnknownError(targetCurrency);
59
56
  }
60
57
  const rate = __classPrivateFieldGet(this, _MoneyConverter_rateService, "f").getRate(money.currency, targetCurrency);
61
58
  if (!rate) {
62
- throw new errors_js_1.ExchangeRateError(money.currency, targetCurrency);
59
+ throw new ExchangeRateError(money.currency, targetCurrency);
63
60
  }
64
- const sourceCurrencyDef = (0, currency_js_1.getCurrency)(money.currency);
61
+ const sourceCurrencyDef = getCurrency(money.currency);
65
62
  const sourceSubunits = money.toSubunits();
66
63
  const sourceMultiplier = 10n ** BigInt(sourceCurrencyDef.decimalDigits);
67
64
  const targetMultiplier = 10n ** BigInt(currencyDef.decimalDigits);
@@ -72,7 +69,7 @@ class MoneyConverter {
72
69
  const product = sourceSubunits * rateBigInt * targetMultiplier;
73
70
  const divisor = rateMultiplier * sourceMultiplier;
74
71
  const targetSubunits = __classPrivateFieldGet(this, _MoneyConverter_instances, "m", _MoneyConverter_bankersRound).call(this, product, divisor);
75
- return money_js_1.Money.fromSubunits(targetSubunits, targetCurrency);
72
+ return Money.fromSubunits(targetSubunits, targetCurrency);
76
73
  }
77
74
  /**
78
75
  * Add two Money amounts, converting as needed.
@@ -121,7 +118,7 @@ class MoneyConverter {
121
118
  * @returns Total in the target currency
122
119
  */
123
120
  sum(amounts, targetCurrency) {
124
- let total = money_js_1.Money.zero(targetCurrency);
121
+ let total = Money.zero(targetCurrency);
125
122
  for (const amount of amounts) {
126
123
  const converted = this.convert(amount, targetCurrency);
127
124
  total = total.add(converted);
@@ -139,7 +136,7 @@ class MoneyConverter {
139
136
  compare(a, b) {
140
137
  // Convert b to a's currency for comparison
141
138
  const bConverted = this.convert(b, a.currency);
142
- return money_js_1.Money.compare(a, bConverted);
139
+ return Money.compare(a, bConverted);
143
140
  }
144
141
  /**
145
142
  * Get the exchange rate service (for direct rate access).
@@ -148,7 +145,6 @@ class MoneyConverter {
148
145
  return __classPrivateFieldGet(this, _MoneyConverter_rateService, "f");
149
146
  }
150
147
  }
151
- exports.MoneyConverter = MoneyConverter;
152
148
  _MoneyConverter_rateService = new WeakMap(), _MoneyConverter_instances = new WeakSet(), _MoneyConverter_bankersRound = function _MoneyConverter_bankersRound(numerator, denominator) {
153
149
  if (denominator === 1n)
154
150
  return numerator;
package/dist/money.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Money - An immutable value object for monetary amounts.
4
3
  *
@@ -20,10 +19,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
20
19
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
21
20
  };
22
21
  var _Money_instances, _a, _Money_subunits, _Money_currencyDef, _Money_parseAmount, _Money_assertSameCurrency, _Money_getInternalValue, _Money_parseFactor, _Money_roundedDivide, _Money_createFromSubunits, _Money_formatSubunits;
23
- Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.Money = void 0;
25
- const errors_js_1 = require("./errors.js");
26
- const currency_js_1 = require("./currency.js");
22
+ import { CurrencyMismatchError, CurrencyUnknownError, SubunitError, AmountError, } from './errors.js';
23
+ import { getCurrency } from './currency.js';
27
24
  /**
28
25
  * Money class - represents a monetary amount in a specific currency.
29
26
  *
@@ -35,7 +32,7 @@ const currency_js_1 = require("./currency.js");
35
32
  * const total = price.add(tax)
36
33
  * console.log(total.amount) // "21.59"
37
34
  */
38
- class Money {
35
+ export class Money {
39
36
  /**
40
37
  * Create a new Money instance.
41
38
  *
@@ -50,9 +47,9 @@ class Money {
50
47
  // Private BigInt storage - stores currency native subunits directly
51
48
  _Money_subunits.set(this, void 0);
52
49
  _Money_currencyDef.set(this, void 0);
53
- const currencyDef = (0, currency_js_1.getCurrency)(currency);
50
+ const currencyDef = getCurrency(currency);
54
51
  if (!currencyDef) {
55
- throw new errors_js_1.CurrencyUnknownError(currency);
52
+ throw new CurrencyUnknownError(currency);
56
53
  }
57
54
  this.currency = currency;
58
55
  __classPrivateFieldSet(this, _Money_currencyDef, currencyDef, "f");
@@ -256,9 +253,9 @@ class Money {
256
253
  * Useful for loading from database (Stripe-style integer storage).
257
254
  */
258
255
  static fromSubunits(subunits, currency) {
259
- const currencyDef = (0, currency_js_1.getCurrency)(currency);
256
+ const currencyDef = getCurrency(currency);
260
257
  if (!currencyDef) {
261
- throw new errors_js_1.CurrencyUnknownError(currency);
258
+ throw new CurrencyUnknownError(currency);
262
259
  }
263
260
  const bigintSubunits = typeof subunits === 'number' ? BigInt(subunits) : subunits;
264
261
  return __classPrivateFieldGet(_a, _a, "m", _Money_createFromSubunits).call(_a, bigintSubunits, currency, currencyDef);
@@ -269,7 +266,7 @@ class Money {
269
266
  */
270
267
  static compare(a, b) {
271
268
  if (a.currency !== b.currency) {
272
- throw new errors_js_1.CurrencyMismatchError(a.currency, b.currency);
269
+ throw new CurrencyMismatchError(a.currency, b.currency);
273
270
  }
274
271
  const aVal = __classPrivateFieldGet(a, _Money_instances, "m", _Money_getInternalValue).call(a);
275
272
  const bVal = __classPrivateFieldGet(b, _Money_instances, "m", _Money_getInternalValue).call(b);
@@ -286,23 +283,22 @@ class Money {
286
283
  return new _a(currency, '0');
287
284
  }
288
285
  }
289
- exports.Money = Money;
290
286
  _a = Money, _Money_subunits = new WeakMap(), _Money_currencyDef = new WeakMap(), _Money_instances = new WeakSet(), _Money_parseAmount = function _Money_parseAmount(amount) {
291
287
  const str = typeof amount === 'number' ? String(amount) : amount;
292
288
  const match = str.match(/^(-)?(\d+)(?:\.(\d+))?$/);
293
289
  if (!match) {
294
- throw new errors_js_1.AmountError(amount);
290
+ throw new AmountError(amount);
295
291
  }
296
292
  const [, sign, whole, frac = ''] = match;
297
293
  if (frac.length > __classPrivateFieldGet(this, _Money_currencyDef, "f").decimalDigits) {
298
- throw new errors_js_1.SubunitError(this.currency, __classPrivateFieldGet(this, _Money_currencyDef, "f").decimalDigits);
294
+ throw new SubunitError(this.currency, __classPrivateFieldGet(this, _Money_currencyDef, "f").decimalDigits);
299
295
  }
300
296
  const paddedFrac = frac.padEnd(__classPrivateFieldGet(this, _Money_currencyDef, "f").decimalDigits, '0');
301
297
  const combined = BigInt(whole + paddedFrac);
302
298
  return sign === '-' ? -combined : combined;
303
299
  }, _Money_assertSameCurrency = function _Money_assertSameCurrency(other) {
304
300
  if (this.currency !== other.currency) {
305
- throw new errors_js_1.CurrencyMismatchError(this.currency, other.currency);
301
+ throw new CurrencyMismatchError(this.currency, other.currency);
306
302
  }
307
303
  }, _Money_getInternalValue = function _Money_getInternalValue() {
308
304
  return __classPrivateFieldGet(this, _Money_subunits, "f");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subunit-money",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "A type-safe value object for monetary amounts with currency conversion support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "README.md"
19
19
  ],
20
20
  "scripts": {
21
- "build": "tsc",
21
+ "build": "tsc && tsc --module commonjs --outDir dist/cjs",
22
22
  "test": "node --import tsx --test test/*.test.ts",
23
23
  "lint": "tsc --noEmit",
24
24
  "check-clean": "git diff --quiet && git diff --cached --quiet",