@lightsparkdev/core 1.2.7 → 1.3.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.
@@ -21,6 +21,7 @@ export const CurrencyUnit = {
21
21
  USD: "USD",
22
22
  MXN: "MXN",
23
23
  PHP: "PHP",
24
+ EUR: "EUR",
24
25
 
25
26
  Bitcoin: "BITCOIN",
26
27
  Microbitcoin: "MICROBITCOIN",
@@ -59,6 +60,7 @@ const standardUnitConversionObj = {
59
60
  [CurrencyUnit.USD]: (v: number) => v,
60
61
  [CurrencyUnit.MXN]: (v: number) => v,
61
62
  [CurrencyUnit.PHP]: (v: number) => v,
63
+ [CurrencyUnit.EUR]: (v: number) => v,
62
64
  };
63
65
 
64
66
  /* Round without decimals since we're returning cents: */
@@ -86,6 +88,7 @@ const CONVERSION_MAP = {
86
88
  [CurrencyUnit.USD]: toBitcoinConversion,
87
89
  [CurrencyUnit.MXN]: toBitcoinConversion,
88
90
  [CurrencyUnit.PHP]: toBitcoinConversion,
91
+ [CurrencyUnit.EUR]: toBitcoinConversion,
89
92
  },
90
93
  [CurrencyUnit.MICROBITCOIN]: {
91
94
  [CurrencyUnit.BITCOIN]: (v: number) => v / 1_000_000,
@@ -97,6 +100,7 @@ const CONVERSION_MAP = {
97
100
  [CurrencyUnit.USD]: toMicrobitcoinConversion,
98
101
  [CurrencyUnit.MXN]: toMicrobitcoinConversion,
99
102
  [CurrencyUnit.PHP]: toMicrobitcoinConversion,
103
+ [CurrencyUnit.EUR]: toMicrobitcoinConversion,
100
104
  },
101
105
  [CurrencyUnit.MILLIBITCOIN]: {
102
106
  [CurrencyUnit.BITCOIN]: (v: number) => v / 1_000,
@@ -108,6 +112,7 @@ const CONVERSION_MAP = {
108
112
  [CurrencyUnit.USD]: toMillibitcoinConversion,
109
113
  [CurrencyUnit.MXN]: toMillibitcoinConversion,
110
114
  [CurrencyUnit.PHP]: toMillibitcoinConversion,
115
+ [CurrencyUnit.EUR]: toMillibitcoinConversion,
111
116
  },
112
117
  [CurrencyUnit.MILLISATOSHI]: {
113
118
  [CurrencyUnit.BITCOIN]: (v: number) => v / 100_000_000_000,
@@ -119,6 +124,7 @@ const CONVERSION_MAP = {
119
124
  [CurrencyUnit.USD]: toMillisatoshiConversion,
120
125
  [CurrencyUnit.MXN]: toMillisatoshiConversion,
121
126
  [CurrencyUnit.PHP]: toMillisatoshiConversion,
127
+ [CurrencyUnit.EUR]: toMillisatoshiConversion,
122
128
  },
123
129
  [CurrencyUnit.NANOBITCOIN]: {
124
130
  [CurrencyUnit.BITCOIN]: (v: number) => v / 1_000_000_000,
@@ -130,6 +136,7 @@ const CONVERSION_MAP = {
130
136
  [CurrencyUnit.USD]: toNanobitcoinConversion,
131
137
  [CurrencyUnit.MXN]: toNanobitcoinConversion,
132
138
  [CurrencyUnit.PHP]: toNanobitcoinConversion,
139
+ [CurrencyUnit.EUR]: toNanobitcoinConversion,
133
140
  },
134
141
  [CurrencyUnit.SATOSHI]: {
135
142
  [CurrencyUnit.BITCOIN]: (v: number) => v / 100_000_000,
@@ -141,10 +148,12 @@ const CONVERSION_MAP = {
141
148
  [CurrencyUnit.USD]: toSatoshiConversion,
142
149
  [CurrencyUnit.MXN]: toSatoshiConversion,
143
150
  [CurrencyUnit.PHP]: toSatoshiConversion,
151
+ [CurrencyUnit.EUR]: toSatoshiConversion,
144
152
  },
145
153
  [CurrencyUnit.USD]: standardUnitConversionObj,
146
154
  [CurrencyUnit.MXN]: standardUnitConversionObj,
147
155
  [CurrencyUnit.PHP]: standardUnitConversionObj,
156
+ [CurrencyUnit.EUR]: standardUnitConversionObj,
148
157
  };
149
158
 
150
159
  export function convertCurrencyAmountValue(
@@ -209,6 +218,7 @@ export type CurrencyMap = {
209
218
  [CurrencyUnit.USD]: number;
210
219
  [CurrencyUnit.MXN]: number;
211
220
  [CurrencyUnit.PHP]: number;
221
+ [CurrencyUnit.EUR]: number;
212
222
  [CurrencyUnit.FUTURE_VALUE]: number;
213
223
  formatted: {
214
224
  sats: string;
@@ -223,6 +233,7 @@ export type CurrencyMap = {
223
233
  [CurrencyUnit.USD]: string;
224
234
  [CurrencyUnit.MXN]: string;
225
235
  [CurrencyUnit.PHP]: string;
236
+ [CurrencyUnit.EUR]: string;
226
237
  [CurrencyUnit.FUTURE_VALUE]: string;
227
238
  };
228
239
  isZero: boolean;
@@ -241,6 +252,21 @@ export type CurrencyAmountInputObj = {
241
252
  unit: CurrencyUnitType;
242
253
  };
243
254
 
255
+ /**
256
+ * UMA has flexible currency types which contain details needed to render amounts.
257
+ */
258
+ export type UmaCurrency = {
259
+ code: string;
260
+ symbol: string;
261
+ decimals: number;
262
+ name: string;
263
+ };
264
+
265
+ export type UmaCurrencyAmount = {
266
+ value: number;
267
+ currency: UmaCurrency;
268
+ };
269
+
244
270
  /* Persisted CurrencyAmount objects may have this shape if queried from GQL in this format
245
271
  but the fields are deprecated and original_unit and original_value should be used instead: */
246
272
  export type DeprecatedCurrencyAmountObj = {
@@ -295,6 +321,21 @@ export function isCurrencyAmountInputObj(
295
321
  );
296
322
  }
297
323
 
324
+ export function isUmaCurrencyAmount(arg: unknown): arg is UmaCurrencyAmount {
325
+ return (
326
+ typeof arg === "object" &&
327
+ arg !== null &&
328
+ "value" in arg &&
329
+ typeof arg.value === "number" &&
330
+ "currency" in arg &&
331
+ typeof (arg as UmaCurrencyAmount).currency === "object" &&
332
+ typeof (arg as UmaCurrencyAmount).currency.code === "string" &&
333
+ typeof (arg as UmaCurrencyAmount).currency.symbol === "string" &&
334
+ typeof (arg as UmaCurrencyAmount).currency.name === "string" &&
335
+ typeof (arg as UmaCurrencyAmount).currency.decimals === "number"
336
+ );
337
+ }
338
+
298
339
  export function isDeprecatedCurrencyAmountObj(
299
340
  arg: unknown,
300
341
  ): arg is DeprecatedCurrencyAmountObj {
@@ -388,6 +429,7 @@ function convertCurrencyAmountValues(
388
429
  usd: CurrencyUnit.USD,
389
430
  mxn: CurrencyUnit.MXN,
390
431
  php: CurrencyUnit.PHP,
432
+ eur: CurrencyUnit.EUR,
391
433
  mibtc: CurrencyUnit.MICROBITCOIN,
392
434
  mlbtc: CurrencyUnit.MILLIBITCOIN,
393
435
  nbtc: CurrencyUnit.NANOBITCOIN,
@@ -437,7 +479,7 @@ export function mapCurrencyAmount(
437
479
  * preferred_currency_unit on CurrencyAmount types: */
438
480
  const conversionOverride = getPreferredConversionOverride(currencyAmountArg);
439
481
 
440
- const { sats, msats, btc, usd, mxn, php, mibtc, mlbtc, nbtc } =
482
+ const { sats, msats, btc, usd, mxn, php, mibtc, mlbtc, nbtc, eur } =
441
483
  convertCurrencyAmountValues(unit, value, unitsPerBtc, conversionOverride);
442
484
 
443
485
  const mapWithCurrencyUnits = {
@@ -447,6 +489,7 @@ export function mapCurrencyAmount(
447
489
  [CurrencyUnit.USD]: usd,
448
490
  [CurrencyUnit.MXN]: mxn,
449
491
  [CurrencyUnit.PHP]: php,
492
+ [CurrencyUnit.EUR]: eur,
450
493
  [CurrencyUnit.MICROBITCOIN]: mibtc,
451
494
  [CurrencyUnit.MILLIBITCOIN]: mlbtc,
452
495
  [CurrencyUnit.NANOBITCOIN]: nbtc,
@@ -488,6 +531,10 @@ export function mapCurrencyAmount(
488
531
  value: php,
489
532
  unit: CurrencyUnit.PHP,
490
533
  }),
534
+ [CurrencyUnit.EUR]: formatCurrencyStr({
535
+ value: eur,
536
+ unit: CurrencyUnit.EUR,
537
+ }),
491
538
  [CurrencyUnit.FUTURE_VALUE]: "-",
492
539
  },
493
540
  };
@@ -562,6 +609,8 @@ export const abbrCurrencyUnit = (unit: CurrencyUnitType) => {
562
609
  return "MXN";
563
610
  case CurrencyUnit.PHP:
564
611
  return "PHP";
612
+ case CurrencyUnit.EUR:
613
+ return "EUR";
565
614
  }
566
615
  return "Unsupported CurrencyUnit";
567
616
  };
@@ -591,7 +640,7 @@ type FormatCurrencyStrOptions = {
591
640
  };
592
641
 
593
642
  export function formatCurrencyStr(
594
- amount: CurrencyAmountArg,
643
+ amount: CurrencyAmountArg | UmaCurrencyAmount,
595
644
  options?: FormatCurrencyStrOptions,
596
645
  ) {
597
646
  const { precision, compact, showBtcSymbol } = {
@@ -599,19 +648,29 @@ export function formatCurrencyStr(
599
648
  ...options,
600
649
  };
601
650
 
602
- const currencyAmount = getCurrencyAmount(amount);
603
- let { value: num } = currencyAmount;
604
- const { unit } = currencyAmount;
605
-
606
- const centCurrencies = [
607
- CurrencyUnit.USD,
608
- CurrencyUnit.MXN,
609
- CurrencyUnit.PHP,
610
- ] as string[];
611
- /* centCurrencies are always provided in the smallest unit, e.g. cents for USD. These should be
612
- * divided by 100 for proper display format: */
613
- if (centCurrencies.includes(unit)) {
614
- num = num / 100;
651
+ let num: number;
652
+ let unit: string;
653
+ if (isUmaCurrencyAmount(amount)) {
654
+ num = amount.value;
655
+ unit = amount.currency.code;
656
+ if (amount.currency.decimals > 0) {
657
+ num = amount.value / Math.pow(10, amount.currency.decimals);
658
+ }
659
+ } else {
660
+ const currencyAmount = getCurrencyAmount(amount);
661
+ num = currencyAmount.value;
662
+ unit = currencyAmount.unit;
663
+ const centCurrencies = [
664
+ CurrencyUnit.USD,
665
+ CurrencyUnit.MXN,
666
+ CurrencyUnit.PHP,
667
+ CurrencyUnit.EUR,
668
+ ] as string[];
669
+ /* centCurrencies are always provided in the smallest unit, e.g. cents for USD. These should be
670
+ * divided by 100 for proper display format: */
671
+ if (centCurrencies.includes(unit)) {
672
+ num = num / 100;
673
+ }
615
674
  }
616
675
 
617
676
  function getDefaultMaxFractionDigits(
@@ -634,25 +693,28 @@ export function formatCurrencyStr(
634
693
  ? ""
635
694
  : unit === CurrencyUnit.BITCOIN
636
695
  ? ""
637
- : unit === CurrencyUnit.SATOSHI
696
+ : unit === CurrencyUnit.SATOSHI ||
697
+ unit === abbrCurrencyUnit(CurrencyUnit.SATOSHI)
638
698
  ? ""
639
699
  : "";
640
700
 
641
701
  const currentLocale = getCurrentLocale();
642
702
 
643
- let formattedStr = "";
644
- switch (unit) {
645
- case CurrencyUnit.MXN:
646
- case CurrencyUnit.USD:
647
- case CurrencyUnit.PHP:
648
- formattedStr = num.toLocaleString(currentLocale, {
703
+ function isFormattableFiatCurrencyCode(currencyCode: string) {
704
+ try {
705
+ new Intl.NumberFormat(currentLocale, {
649
706
  style: "currency",
650
- currency: unit,
651
- currencyDisplay: "narrowSymbol",
652
- notation: compact ? ("compact" as const) : undefined,
653
- maximumFractionDigits: getDefaultMaxFractionDigits(2, 2),
707
+ currency: currencyCode,
654
708
  });
655
- break;
709
+ return true;
710
+ } catch (e) {
711
+ return false;
712
+ }
713
+ }
714
+
715
+ let formattedStr = "";
716
+ let forceAppendUnits = false;
717
+ switch (unit) {
656
718
  case CurrencyUnit.BITCOIN:
657
719
  /* In most cases product prefers 4 precision digtis for BTC. In a few places
658
720
  full precision (8 digits) are preferred, e.g. for a transaction details page: */
@@ -662,6 +724,7 @@ export function formatCurrencyStr(
662
724
  })}`;
663
725
  break;
664
726
  case CurrencyUnit.SATOSHI:
727
+ case abbrCurrencyUnit(CurrencyUnit.SATOSHI):
665
728
  /* In most cases product prefers hiding sub sat precision (msats). In a few
666
729
  places full precision (3 digits) are preferred, e.g. for Lightning fees
667
730
  paid on a transaction details page: */
@@ -674,27 +737,44 @@ export function formatCurrencyStr(
674
737
  case CurrencyUnit.MICROBITCOIN:
675
738
  case CurrencyUnit.MILLIBITCOIN:
676
739
  case CurrencyUnit.NANOBITCOIN:
677
- default:
678
740
  formattedStr = `${symbol}${num.toLocaleString(currentLocale, {
679
741
  notation: compact ? ("compact" as const) : undefined,
680
742
  maximumFractionDigits: getDefaultMaxFractionDigits(0, 0),
681
743
  })}`;
744
+ break;
745
+ default:
746
+ if (isFormattableFiatCurrencyCode(unit)) {
747
+ formattedStr = num.toLocaleString(currentLocale, {
748
+ style: "currency",
749
+ currency: unit,
750
+ currencyDisplay: "narrowSymbol",
751
+ notation: compact ? ("compact" as const) : undefined,
752
+ maximumFractionDigits: getDefaultMaxFractionDigits(2, 2),
753
+ });
754
+ } else {
755
+ formattedStr = `${num}`;
756
+ forceAppendUnits = true;
757
+ }
758
+ break;
682
759
  }
683
760
 
684
- if (options?.appendUnits) {
761
+ if (options?.appendUnits || forceAppendUnits) {
685
762
  const localeCurrencyCode = localeToCurrencyCode(currentLocale);
686
763
  if (
687
764
  unit === localeCurrencyCode &&
765
+ options?.appendUnits &&
688
766
  !options.appendUnits.showForCurrentLocaleUnit
689
767
  ) {
690
768
  return formattedStr;
691
769
  }
692
770
 
693
- const unitStr = abbrCurrencyUnit(unit);
694
- const unitSuffix = options.appendUnits.plural && num > 1 ? "s" : "";
771
+ const unitStr = isUmaCurrencyAmount(amount)
772
+ ? amount.currency.code
773
+ : abbrCurrencyUnit(unit as CurrencyUnitType);
774
+ const unitSuffix = options?.appendUnits?.plural && num > 1 ? "s" : "";
695
775
  const unitStrWithSuffix = `${unitStr}${unitSuffix}`;
696
776
  formattedStr += ` ${
697
- options.appendUnits.lowercase
777
+ options?.appendUnits?.lowercase
698
778
  ? unitStrWithSuffix.toLowerCase()
699
779
  : unitStrWithSuffix
700
780
  }`;
@@ -22,6 +22,10 @@ export const isType =
22
22
  return node?.__typename === typename;
23
23
  };
24
24
 
25
+ export type ExtractByTypename<T, N extends string> = T extends { __typename: N }
26
+ ? T
27
+ : never;
28
+
25
29
  export type DeepPartial<T> = T extends object
26
30
  ? {
27
31
  [P in keyof T]?: DeepPartial<T[P]>;
@@ -55,3 +59,7 @@ export type Complete<T> = { [P in keyof T]-?: NonNullable<T[P]> };
55
59
  export type RequiredKeys<T> = {
56
60
  [K in keyof T]-?: Record<string, never> extends Pick<T, K> ? never : K;
57
61
  }[keyof T];
62
+
63
+ export function isRecord(value: unknown): value is Record<string, unknown> {
64
+ return typeof value === "object" && value !== null && !Array.isArray(value);
65
+ }