monetra 1.0.0 → 1.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/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  CURRENCIES: () => CURRENCIES,
24
+ Converter: () => Converter,
24
25
  CurrencyMismatchError: () => CurrencyMismatchError,
25
26
  EUR: () => EUR,
26
27
  GBP: () => GBP,
@@ -29,17 +30,49 @@ __export(index_exports, {
29
30
  JPY: () => JPY,
30
31
  MonetraError: () => MonetraError,
31
32
  Money: () => Money,
33
+ MoneyBag: () => MoneyBag,
32
34
  OverflowError: () => OverflowError,
33
35
  RoundingMode: () => RoundingMode,
34
36
  RoundingRequiredError: () => RoundingRequiredError,
35
37
  USD: () => USD,
36
38
  ZAR: () => ZAR,
39
+ assertNonNegative: () => assertNonNegative,
40
+ assertSameCurrency: () => assertSameCurrency,
37
41
  divideWithRounding: () => divideWithRounding,
38
42
  getCurrency: () => getCurrency,
39
- getMinorUnitExponent: () => getMinorUnitExponent
43
+ getMinorUnitExponent: () => getMinorUnitExponent,
44
+ isCurrencyRegistered: () => isCurrencyRegistered,
45
+ money: () => money,
46
+ registerCurrency: () => registerCurrency
40
47
  });
41
48
  module.exports = __toCommonJS(index_exports);
42
49
 
50
+ // src/currency/registry.ts
51
+ var registry = /* @__PURE__ */ new Map();
52
+ function registerCurrency(currency) {
53
+ registry.set(currency.code, currency);
54
+ }
55
+ function getCurrency(code) {
56
+ const currency = registry.get(code);
57
+ if (!currency) {
58
+ throw new Error(`Currency '${code}' not found in registry.`);
59
+ }
60
+ return currency;
61
+ }
62
+ function isCurrencyRegistered(code) {
63
+ return registry.has(code);
64
+ }
65
+
66
+ // src/rounding/strategies.ts
67
+ var RoundingMode = /* @__PURE__ */ ((RoundingMode3) => {
68
+ RoundingMode3["HALF_UP"] = "HALF_UP";
69
+ RoundingMode3["HALF_DOWN"] = "HALF_DOWN";
70
+ RoundingMode3["HALF_EVEN"] = "HALF_EVEN";
71
+ RoundingMode3["FLOOR"] = "FLOOR";
72
+ RoundingMode3["CEIL"] = "CEIL";
73
+ return RoundingMode3;
74
+ })(RoundingMode || {});
75
+
43
76
  // src/errors/BaseError.ts
44
77
  var MonetraError = class extends Error {
45
78
  constructor(message) {
@@ -51,8 +84,13 @@ var MonetraError = class extends Error {
51
84
 
52
85
  // src/errors/CurrencyMismatchError.ts
53
86
  var CurrencyMismatchError = class extends MonetraError {
54
- constructor(expected, actual) {
55
- super(`Currency mismatch: expected ${expected}, got ${actual}`);
87
+ constructor(expected, received) {
88
+ super(
89
+ `Currency mismatch: expected ${expected}, received ${received}.
90
+ \u{1F4A1} Tip: Use a Converter to convert between currencies:
91
+ const converter = new Converter('USD', { ${received}: rate });
92
+ const converted = converter.convert(money, '${expected}');`
93
+ );
56
94
  }
57
95
  };
58
96
 
@@ -65,8 +103,15 @@ var InvalidPrecisionError = class extends MonetraError {
65
103
 
66
104
  // src/errors/RoundingRequiredError.ts
67
105
  var RoundingRequiredError = class extends MonetraError {
68
- constructor() {
69
- super("Rounding is required for this operation but was not provided.");
106
+ constructor(operation, result) {
107
+ let message = "Rounding is required for this operation but was not provided.";
108
+ if (operation && result !== void 0) {
109
+ message = `Rounding required for ${operation}: result ${result} is not an integer.
110
+ \u{1F4A1} Tip: Provide a rounding mode:
111
+ money.${operation}(value, { rounding: RoundingMode.HALF_UP })
112
+ Available modes: HALF_UP, HALF_DOWN, HALF_EVEN, FLOOR, CEIL`;
113
+ }
114
+ super(message);
70
115
  }
71
116
  };
72
117
 
@@ -90,16 +135,11 @@ function assertSameCurrency(a, b) {
90
135
  throw new CurrencyMismatchError(a.currency.code, b.currency.code);
91
136
  }
92
137
  }
93
-
94
- // src/rounding/strategies.ts
95
- var RoundingMode = /* @__PURE__ */ ((RoundingMode3) => {
96
- RoundingMode3["HALF_UP"] = "HALF_UP";
97
- RoundingMode3["HALF_DOWN"] = "HALF_DOWN";
98
- RoundingMode3["HALF_EVEN"] = "HALF_EVEN";
99
- RoundingMode3["FLOOR"] = "FLOOR";
100
- RoundingMode3["CEIL"] = "CEIL";
101
- return RoundingMode3;
102
- })(RoundingMode || {});
138
+ function assertNonNegative(money2) {
139
+ if (money2.isNegative()) {
140
+ throw new Error("Money value must be non-negative");
141
+ }
142
+ }
103
143
 
104
144
  // src/rounding/index.ts
105
145
  function divideWithRounding(numerator, denominator, mode) {
@@ -160,10 +200,24 @@ function multiply(amount, multiplier, rounding) {
160
200
  return product / denominator;
161
201
  }
162
202
  if (!rounding) {
163
- throw new RoundingRequiredError();
203
+ throw new RoundingRequiredError(
204
+ "multiply",
205
+ Number(product) / Number(denominator)
206
+ );
164
207
  }
165
208
  return divideWithRounding(product, denominator, rounding);
166
209
  }
210
+ function divide(amount, divisor, rounding) {
211
+ const { numerator, denominator } = parseMultiplier(divisor);
212
+ const product = amount * denominator;
213
+ if (product % numerator === 0n) {
214
+ return product / numerator;
215
+ }
216
+ if (!rounding) {
217
+ throw new RoundingRequiredError("divide", Number(product) / Number(numerator));
218
+ }
219
+ return divideWithRounding(product, numerator, rounding);
220
+ }
167
221
  function parseMultiplier(multiplier) {
168
222
  const s = multiplier.toString();
169
223
  if (/[eE]/.test(s)) {
@@ -252,11 +306,12 @@ function parseToMinor(amount, currency) {
252
306
  }
253
307
 
254
308
  // src/format/formatter.ts
255
- function format(money, options) {
256
- const locale = options?.locale || money.currency.locale || "en-US";
309
+ function format(money2, options) {
310
+ const locale = options?.locale || money2.currency.locale || "en-US";
257
311
  const showSymbol = options?.symbol ?? true;
258
- const decimals = money.currency.decimals;
259
- const minor = money.minor;
312
+ const display = options?.display || "symbol";
313
+ const decimals = money2.currency.decimals;
314
+ const minor = money2.minor;
260
315
  const absMinor = minor < 0n ? -minor : minor;
261
316
  const divisor = 10n ** BigInt(decimals);
262
317
  const integerPart = absMinor / divisor;
@@ -277,7 +332,8 @@ function format(money, options) {
277
332
  }
278
333
  const templateParts = new Intl.NumberFormat(locale, {
279
334
  style: "currency",
280
- currency: money.currency.code
335
+ currency: money2.currency.code,
336
+ currencyDisplay: display
281
337
  }).formatToParts(minor < 0n ? -1 : 1);
282
338
  let result = "";
283
339
  let numberInserted = false;
@@ -302,66 +358,135 @@ var Money = class _Money {
302
358
  this.minor = minor;
303
359
  this.currency = currency;
304
360
  }
361
+ static resolveCurrency(currency) {
362
+ if (typeof currency === "string") {
363
+ return getCurrency(currency);
364
+ }
365
+ return currency;
366
+ }
305
367
  /**
306
368
  * Creates a Money instance from minor units (e.g., cents).
307
- *
369
+ *
308
370
  * @param minor - The amount in minor units. Can be a number or BigInt.
309
- * @param currency - The currency of the money.
371
+ * @param currency - The currency of the money (object or code string).
310
372
  * @returns A new Money instance.
311
373
  * @example
312
374
  * const m = Money.fromMinor(100, USD); // $1.00
375
+ * const m2 = Money.fromMinor(100, 'USD'); // $1.00
313
376
  */
314
377
  static fromMinor(minor, currency) {
315
- return new _Money(BigInt(minor), currency);
378
+ return new _Money(BigInt(minor), _Money.resolveCurrency(currency));
316
379
  }
317
380
  /**
318
381
  * Creates a Money instance from major units (e.g., "10.50").
319
- *
382
+ *
320
383
  * @param amount - The amount as a string. Must be a valid decimal number.
321
- * @param currency - The currency of the money.
384
+ * @param currency - The currency of the money (object or code string).
322
385
  * @returns A new Money instance.
323
386
  * @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.
324
387
  * @example
325
388
  * const m = Money.fromMajor("10.50", USD); // $10.50
326
389
  */
327
390
  static fromMajor(amount, currency) {
328
- const minor = parseToMinor(amount, currency);
329
- return new _Money(minor, currency);
391
+ const resolvedCurrency = _Money.resolveCurrency(currency);
392
+ const minor = parseToMinor(amount, resolvedCurrency);
393
+ return new _Money(minor, resolvedCurrency);
394
+ }
395
+ /**
396
+ * Creates a Money instance from a floating-point number.
397
+ *
398
+ * ⚠️ WARNING: Floating-point numbers can have precision issues.
399
+ * Prefer `Money.fromMajor("10.50", currency)` for exact values.
400
+ *
401
+ * @param amount - The float amount in major units.
402
+ * @param currency - The currency.
403
+ * @param options - Options for handling precision.
404
+ * @returns A new Money instance.
405
+ */
406
+ static fromFloat(amount, currency, options) {
407
+ if (!options?.suppressWarning && process.env.NODE_ENV !== "production") {
408
+ console.warn(
409
+ '[monetra] Money.fromFloat() may lose precision. Consider using Money.fromMajor("' + amount + '", currency) instead.'
410
+ );
411
+ }
412
+ const resolvedCurrency = _Money.resolveCurrency(currency);
413
+ const factor = 10 ** resolvedCurrency.decimals;
414
+ const minorUnits = Math.round(amount * factor);
415
+ return new _Money(BigInt(minorUnits), resolvedCurrency);
416
+ }
417
+ /**
418
+ * Returns the minimum of the provided Money values.
419
+ * @param values - Money values to compare (must all be same currency).
420
+ * @returns The Money with the smallest amount.
421
+ * @throws {CurrencyMismatchError} If currencies don't match.
422
+ */
423
+ static min(...values) {
424
+ if (values.length === 0)
425
+ throw new Error("At least one Money value required");
426
+ return values.reduce((min, current) => {
427
+ assertSameCurrency(min, current);
428
+ return current.lessThan(min) ? current : min;
429
+ });
430
+ }
431
+ /**
432
+ * Returns the maximum of the provided Money values.
433
+ * @param values - Money values to compare (must all be same currency).
434
+ * @returns The Money with the largest amount.
435
+ * @throws {CurrencyMismatchError} If currencies don't match.
436
+ */
437
+ static max(...values) {
438
+ if (values.length === 0)
439
+ throw new Error("At least one Money value required");
440
+ return values.reduce((max, current) => {
441
+ assertSameCurrency(max, current);
442
+ return current.greaterThan(max) ? current : max;
443
+ });
330
444
  }
331
445
  /**
332
446
  * Creates a Money instance representing zero in the given currency.
333
- *
447
+ *
334
448
  * @param currency - The currency.
335
449
  * @returns A new Money instance with value 0.
336
450
  */
337
451
  static zero(currency) {
338
- return new _Money(0n, currency);
452
+ return new _Money(0n, _Money.resolveCurrency(currency));
453
+ }
454
+ resolveOther(other) {
455
+ if (other instanceof _Money) {
456
+ return other;
457
+ }
458
+ if (typeof other === "string") {
459
+ return _Money.fromMajor(other, this.currency);
460
+ }
461
+ return _Money.fromMinor(other, this.currency);
339
462
  }
340
463
  /**
341
464
  * Adds another Money value to this one.
342
- *
343
- * @param other - The Money value to add.
465
+ *
466
+ * @param other - The value to add (Money, minor units as number/bigint, or major units as string).
344
467
  * @returns A new Money instance representing the sum.
345
468
  * @throws {CurrencyMismatchError} If the currencies do not match.
346
469
  */
347
470
  add(other) {
348
- assertSameCurrency(this, other);
349
- return new _Money(add(this.minor, other.minor), this.currency);
471
+ const otherMoney = this.resolveOther(other);
472
+ assertSameCurrency(this, otherMoney);
473
+ return new _Money(add(this.minor, otherMoney.minor), this.currency);
350
474
  }
351
475
  /**
352
476
  * Subtracts another Money value from this one.
353
- *
354
- * @param other - The Money value to subtract.
477
+ *
478
+ * @param other - The value to subtract (Money, minor units as number/bigint, or major units as string).
355
479
  * @returns A new Money instance representing the difference.
356
480
  * @throws {CurrencyMismatchError} If the currencies do not match.
357
481
  */
358
482
  subtract(other) {
359
- assertSameCurrency(this, other);
360
- return new _Money(subtract(this.minor, other.minor), this.currency);
483
+ const otherMoney = this.resolveOther(other);
484
+ assertSameCurrency(this, otherMoney);
485
+ return new _Money(subtract(this.minor, otherMoney.minor), this.currency);
361
486
  }
362
487
  /**
363
488
  * Multiplies this Money value by a scalar.
364
- *
489
+ *
365
490
  * @param multiplier - The number to multiply by.
366
491
  * @param options - Options for rounding if the result is not an integer.
367
492
  * @returns A new Money instance representing the product.
@@ -371,12 +496,45 @@ var Money = class _Money {
371
496
  const result = multiply(this.minor, multiplier, options?.rounding);
372
497
  return new _Money(result, this.currency);
373
498
  }
499
+ /**
500
+ * Divides this Money value by a divisor.
501
+ *
502
+ * @param divisor - The number to divide by.
503
+ * @param options - Options for rounding if the result is not an integer.
504
+ * @returns A new Money instance representing the quotient.
505
+ * @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.
506
+ * @throws {Error} If divisor is zero.
507
+ */
508
+ divide(divisor, options) {
509
+ if (divisor === 0 || divisor === "0") {
510
+ throw new Error("Division by zero");
511
+ }
512
+ const result = divide(this.minor, divisor, options?.rounding);
513
+ return new _Money(result, this.currency);
514
+ }
515
+ /**
516
+ * Returns the absolute value of this Money.
517
+ * @returns A new Money instance with the absolute value.
518
+ */
519
+ abs() {
520
+ return new _Money(
521
+ this.minor < 0n ? -this.minor : this.minor,
522
+ this.currency
523
+ );
524
+ }
525
+ /**
526
+ * Returns the negated value of this Money.
527
+ * @returns A new Money instance with the negated value.
528
+ */
529
+ negate() {
530
+ return new _Money(-this.minor, this.currency);
531
+ }
374
532
  /**
375
533
  * Allocates (splits) this Money value according to a list of ratios.
376
- *
534
+ *
377
535
  * The sum of the parts will always equal the original amount.
378
536
  * Remainders are distributed to the parts with the largest fractional remainders.
379
- *
537
+ *
380
538
  * @param ratios - A list of numbers representing the ratios to split by.
381
539
  * @returns An array of Money instances.
382
540
  */
@@ -386,7 +544,7 @@ var Money = class _Money {
386
544
  }
387
545
  /**
388
546
  * Formats this Money value as a string.
389
- *
547
+ *
390
548
  * @param options - Formatting options.
391
549
  * @returns The formatted string.
392
550
  */
@@ -395,38 +553,106 @@ var Money = class _Money {
395
553
  }
396
554
  /**
397
555
  * Checks if this Money value is equal to another.
398
- *
399
- * @param other - The other Money value.
556
+ *
557
+ * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).
400
558
  * @returns True if amounts and currencies are equal.
401
559
  */
402
560
  equals(other) {
403
- return this.currency.code === other.currency.code && this.minor === other.minor;
561
+ const otherMoney = this.resolveOther(other);
562
+ return this.currency.code === otherMoney.currency.code && this.minor === otherMoney.minor;
404
563
  }
405
564
  /**
406
565
  * Checks if this Money value is greater than another.
407
- *
408
- * @param other - The other Money value.
566
+ *
567
+ * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).
409
568
  * @returns True if this value is greater.
410
569
  * @throws {CurrencyMismatchError} If the currencies do not match.
411
570
  */
412
571
  greaterThan(other) {
413
- assertSameCurrency(this, other);
414
- return this.minor > other.minor;
572
+ const otherMoney = this.resolveOther(other);
573
+ assertSameCurrency(this, otherMoney);
574
+ return this.minor > otherMoney.minor;
415
575
  }
416
576
  /**
417
577
  * Checks if this Money value is less than another.
418
- *
419
- * @param other - The other Money value.
578
+ *
579
+ * @param other - The other Money value (Money, minor units as number/bigint, or major units as string).
420
580
  * @returns True if this value is less.
421
581
  * @throws {CurrencyMismatchError} If the currencies do not match.
422
582
  */
423
583
  lessThan(other) {
424
- assertSameCurrency(this, other);
425
- return this.minor < other.minor;
584
+ const otherMoney = this.resolveOther(other);
585
+ assertSameCurrency(this, otherMoney);
586
+ return this.minor < otherMoney.minor;
587
+ }
588
+ /**
589
+ * Checks if this Money value is greater than or equal to another.
590
+ */
591
+ greaterThanOrEqual(other) {
592
+ const otherMoney = this.resolveOther(other);
593
+ assertSameCurrency(this, otherMoney);
594
+ return this.minor >= otherMoney.minor;
595
+ }
596
+ /**
597
+ * Checks if this Money value is less than or equal to another.
598
+ */
599
+ lessThanOrEqual(other) {
600
+ const otherMoney = this.resolveOther(other);
601
+ assertSameCurrency(this, otherMoney);
602
+ return this.minor <= otherMoney.minor;
603
+ }
604
+ /**
605
+ * Checks if this Money value is positive (greater than zero).
606
+ */
607
+ isPositive() {
608
+ return this.minor > 0n;
609
+ }
610
+ /**
611
+ * Compares this Money to another, returning -1, 0, or 1.
612
+ * Useful for sorting.
613
+ */
614
+ compare(other) {
615
+ const otherMoney = this.resolveOther(other);
616
+ assertSameCurrency(this, otherMoney);
617
+ if (this.minor < otherMoney.minor) return -1;
618
+ if (this.minor > otherMoney.minor) return 1;
619
+ return 0;
620
+ }
621
+ /**
622
+ * Calculates a percentage of the money.
623
+ * @param percent - The percentage (e.g., 50 for 50%).
624
+ * @param rounding - Rounding mode (defaults to HALF_EVEN).
625
+ */
626
+ percentage(percent, rounding = "HALF_EVEN" /* HALF_EVEN */) {
627
+ return this.multiply(percent / 100, { rounding });
628
+ }
629
+ /**
630
+ * Adds a percentage to the money.
631
+ * @param percent - The percentage to add.
632
+ * @param rounding - Rounding mode.
633
+ */
634
+ addPercent(percent, rounding = "HALF_EVEN" /* HALF_EVEN */) {
635
+ return this.add(this.percentage(percent, rounding));
636
+ }
637
+ /**
638
+ * Subtracts a percentage from the money.
639
+ * @param percent - The percentage to subtract.
640
+ * @param rounding - Rounding mode.
641
+ */
642
+ subtractPercent(percent, rounding = "HALF_EVEN" /* HALF_EVEN */) {
643
+ return this.subtract(this.percentage(percent, rounding));
644
+ }
645
+ /**
646
+ * Splits the money into equal parts.
647
+ * @param parts - Number of parts.
648
+ */
649
+ split(parts) {
650
+ const ratios = Array(parts).fill(1);
651
+ return this.allocate(ratios);
426
652
  }
427
653
  /**
428
654
  * Checks if this Money value is zero.
429
- *
655
+ *
430
656
  * @returns True if the amount is zero.
431
657
  */
432
658
  isZero() {
@@ -434,12 +660,149 @@ var Money = class _Money {
434
660
  }
435
661
  /**
436
662
  * Checks if this Money value is negative.
437
- *
663
+ *
438
664
  * @returns True if the amount is negative.
439
665
  */
440
666
  isNegative() {
441
667
  return this.minor < 0n;
442
668
  }
669
+ /**
670
+ * Returns a JSON representation of the Money object.
671
+ *
672
+ * @returns An object with amount (string), currency (code), and precision.
673
+ */
674
+ toJSON() {
675
+ return {
676
+ amount: this.minor.toString(),
677
+ currency: this.currency.code,
678
+ precision: this.currency.decimals
679
+ };
680
+ }
681
+ /**
682
+ * Returns a string representation of the Money object (formatted).
683
+ */
684
+ toString() {
685
+ return this.format();
686
+ }
687
+ };
688
+
689
+ // src/money/Converter.ts
690
+ var Converter = class {
691
+ /**
692
+ * Creates a new Converter.
693
+ *
694
+ * @param base - The base currency code (e.g., "USD").
695
+ * @param rates - A map of currency codes to exchange rates relative to the base.
696
+ * Example: { "EUR": 0.85, "GBP": 0.75 } (where 1 Base = 0.85 EUR).
697
+ */
698
+ constructor(base, rates) {
699
+ this.base = base;
700
+ this.rates = { ...rates };
701
+ if (this.rates[base] === void 0) {
702
+ this.rates[base] = 1;
703
+ }
704
+ }
705
+ /**
706
+ * Converts a Money object to a target currency.
707
+ *
708
+ * @param money - The Money object to convert.
709
+ * @param toCurrency - The target currency (code or object).
710
+ * @returns A new Money object in the target currency.
711
+ * @throws {Error} If exchange rates are missing.
712
+ */
713
+ convert(money2, toCurrency) {
714
+ const targetCurrency = typeof toCurrency === "string" ? getCurrency(toCurrency) : toCurrency;
715
+ if (money2.currency.code === targetCurrency.code) {
716
+ return money2;
717
+ }
718
+ const fromRate = this.rates[money2.currency.code];
719
+ const toRate = this.rates[targetCurrency.code];
720
+ if (fromRate === void 0 || toRate === void 0) {
721
+ throw new Error(
722
+ `Exchange rate missing for conversion from ${money2.currency.code} to ${targetCurrency.code}`
723
+ );
724
+ }
725
+ const ratio = toRate / fromRate;
726
+ const decimalAdjustment = 10 ** (targetCurrency.decimals - money2.currency.decimals);
727
+ const multiplier = ratio * decimalAdjustment;
728
+ const convertedAmount = money2.multiply(multiplier, {
729
+ rounding: "HALF_EVEN" /* HALF_EVEN */
730
+ });
731
+ return Money.fromMinor(convertedAmount.minor, targetCurrency);
732
+ }
733
+ };
734
+
735
+ // src/money/MoneyBag.ts
736
+ var MoneyBag = class {
737
+ constructor() {
738
+ this.contents = /* @__PURE__ */ new Map();
739
+ }
740
+ /**
741
+ * Adds a Money amount to the bag.
742
+ * @param money The money to add.
743
+ */
744
+ add(money2) {
745
+ const code = money2.currency.code;
746
+ const existing = this.contents.get(code);
747
+ if (existing) {
748
+ this.contents.set(code, existing.add(money2));
749
+ } else {
750
+ this.contents.set(code, money2);
751
+ }
752
+ }
753
+ /**
754
+ * Subtracts a Money amount from the bag.
755
+ * @param money The money to subtract.
756
+ */
757
+ subtract(money2) {
758
+ const code = money2.currency.code;
759
+ const existing = this.contents.get(code);
760
+ if (existing) {
761
+ this.contents.set(code, existing.subtract(money2));
762
+ } else {
763
+ const zero = Money.zero(money2.currency);
764
+ this.contents.set(code, zero.subtract(money2));
765
+ }
766
+ }
767
+ /**
768
+ * Gets the amount for a specific currency.
769
+ * @param currency The currency to retrieve.
770
+ * @returns The Money amount in that currency (or zero if not present).
771
+ */
772
+ get(currency) {
773
+ const code = typeof currency === "string" ? currency : currency.code;
774
+ return this.contents.get(code) || Money.zero(
775
+ typeof currency === "string" ? getCurrency(currency) : currency
776
+ );
777
+ }
778
+ /**
779
+ * Calculates the total value of the bag in a specific currency.
780
+ *
781
+ * @param targetCurrency The currency to convert everything to.
782
+ * @param converter The converter instance with exchange rates.
783
+ * @returns The total amount in the target currency.
784
+ */
785
+ total(targetCurrency, converter) {
786
+ const target = typeof targetCurrency === "string" ? getCurrency(targetCurrency) : targetCurrency;
787
+ let total = Money.zero(target);
788
+ for (const money2 of this.contents.values()) {
789
+ const converted = converter.convert(money2, target);
790
+ total = total.add(converted);
791
+ }
792
+ return total;
793
+ }
794
+ /**
795
+ * Returns a list of all Money objects in the bag.
796
+ */
797
+ getAll() {
798
+ return Array.from(this.contents.values());
799
+ }
800
+ /**
801
+ * Returns a JSON representation of the bag.
802
+ */
803
+ toJSON() {
804
+ return this.getAll().map((m) => m.toJSON());
805
+ }
443
806
  };
444
807
 
445
808
  // src/currency/iso4217.ts
@@ -449,6 +812,7 @@ var USD = {
449
812
  symbol: "$",
450
813
  locale: "en-US"
451
814
  };
815
+ registerCurrency(USD);
452
816
  var EUR = {
453
817
  code: "EUR",
454
818
  decimals: 2,
@@ -456,24 +820,28 @@ var EUR = {
456
820
  locale: "de-DE"
457
821
  // Default locale, can be overridden
458
822
  };
823
+ registerCurrency(EUR);
459
824
  var GBP = {
460
825
  code: "GBP",
461
826
  decimals: 2,
462
827
  symbol: "\xA3",
463
828
  locale: "en-GB"
464
829
  };
830
+ registerCurrency(GBP);
465
831
  var JPY = {
466
832
  code: "JPY",
467
833
  decimals: 0,
468
834
  symbol: "\xA5",
469
835
  locale: "ja-JP"
470
836
  };
837
+ registerCurrency(JPY);
471
838
  var ZAR = {
472
839
  code: "ZAR",
473
840
  decimals: 2,
474
841
  symbol: "R",
475
842
  locale: "en-ZA"
476
843
  };
844
+ registerCurrency(ZAR);
477
845
  var CURRENCIES = {
478
846
  USD,
479
847
  EUR,
@@ -481,21 +849,23 @@ var CURRENCIES = {
481
849
  JPY,
482
850
  ZAR
483
851
  };
484
- function getCurrency(code) {
485
- const currency = CURRENCIES[code.toUpperCase()];
486
- if (!currency) {
487
- throw new Error(`Unknown currency code: ${code}`);
488
- }
489
- return currency;
490
- }
491
852
 
492
853
  // src/currency/precision.ts
493
854
  function getMinorUnitExponent(currency) {
494
855
  return 10n ** BigInt(currency.decimals);
495
856
  }
857
+
858
+ // src/index.ts
859
+ function money(amount, currency) {
860
+ if (typeof amount === "string") {
861
+ return Money.fromMajor(amount, currency);
862
+ }
863
+ return Money.fromMinor(amount, currency);
864
+ }
496
865
  // Annotate the CommonJS export names for ESM import in node:
497
866
  0 && (module.exports = {
498
867
  CURRENCIES,
868
+ Converter,
499
869
  CurrencyMismatchError,
500
870
  EUR,
501
871
  GBP,
@@ -504,13 +874,19 @@ function getMinorUnitExponent(currency) {
504
874
  JPY,
505
875
  MonetraError,
506
876
  Money,
877
+ MoneyBag,
507
878
  OverflowError,
508
879
  RoundingMode,
509
880
  RoundingRequiredError,
510
881
  USD,
511
882
  ZAR,
883
+ assertNonNegative,
884
+ assertSameCurrency,
512
885
  divideWithRounding,
513
886
  getCurrency,
514
- getMinorUnitExponent
887
+ getMinorUnitExponent,
888
+ isCurrencyRegistered,
889
+ money,
890
+ registerCurrency
515
891
  });
516
892
  //# sourceMappingURL=index.js.map