@lightsparkdev/core 1.0.5 → 1.0.6
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/CHANGELOG.md +8 -0
- package/dist/chunk-W5XKQOE6.js +903 -0
- package/dist/index.cjs +597 -25
- package/dist/index.d.ts +1 -1
- package/dist/index.js +35 -1
- package/dist/utils/index.cjs +597 -25
- package/dist/utils/index.d.ts +146 -21
- package/dist/utils/index.js +35 -1
- package/package.json +3 -2
- package/src/utils/currency.ts +393 -50
- package/src/utils/index.ts +3 -0
- package/src/utils/locale.ts +3 -0
- package/src/utils/localeToCurrencyCodes.ts +272 -0
- package/src/utils/numbers.ts +32 -0
- package/src/utils/tests/currency.test.ts +190 -0
- package/dist/chunk-5P2KZ44N.js +0 -348
package/src/utils/currency.ts
CHANGED
|
@@ -1,32 +1,14 @@
|
|
|
1
1
|
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
2
|
|
|
3
3
|
import LightsparkException from "../LightsparkException.js";
|
|
4
|
+
import { getCurrentLocale } from "./locale.js";
|
|
5
|
+
import { localeToCurrencyCode } from "./localeToCurrencyCodes.js";
|
|
6
|
+
import { isNumber, round } from "./numbers.js";
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
type CurrencyAmount = {
|
|
7
|
-
/** The original numeric value for this CurrencyAmount. **/
|
|
8
|
-
originalValue: number;
|
|
9
|
-
|
|
10
|
-
/** The original unit of currency for this CurrencyAmount. **/
|
|
11
|
-
originalUnit: CurrencyUnit;
|
|
12
|
-
|
|
13
|
-
/** The unit of user's preferred currency. **/
|
|
14
|
-
preferredCurrencyUnit: CurrencyUnit;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The rounded numeric value for this CurrencyAmount in the very base level of user's preferred
|
|
18
|
-
* currency. For example, for USD, the value will be in cents.
|
|
19
|
-
**/
|
|
20
|
-
preferredCurrencyValueRounded: number;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The approximate float value for this CurrencyAmount in the very base level of user's preferred
|
|
24
|
-
* currency. For example, for USD, the value will be in cents.
|
|
25
|
-
**/
|
|
26
|
-
preferredCurrencyValueApprox: number;
|
|
27
|
-
};
|
|
8
|
+
export const defaultCurrencyCode = "USD";
|
|
28
9
|
|
|
29
|
-
enum
|
|
10
|
+
/** This enum identifies the unit of currency associated with a CurrencyAmount. **/
|
|
11
|
+
export enum CurrencyUnit {
|
|
30
12
|
/**
|
|
31
13
|
* This is an enum value that represents values that could be added in the future.
|
|
32
14
|
* Clients should support unknown values as more of them could be added without notice.
|
|
@@ -48,6 +30,26 @@ enum CurrencyUnit {
|
|
|
48
30
|
MILLIBITCOIN = "MILLIBITCOIN",
|
|
49
31
|
}
|
|
50
32
|
|
|
33
|
+
/** This object represents the value and unit for an amount of currency. **/
|
|
34
|
+
export type CurrencyAmountType = {
|
|
35
|
+
/** The original numeric value for this CurrencyAmount. **/
|
|
36
|
+
originalValue: number;
|
|
37
|
+
/** The original unit of currency for this CurrencyAmount. **/
|
|
38
|
+
originalUnit: CurrencyUnit;
|
|
39
|
+
/** The unit of user's preferred currency. **/
|
|
40
|
+
preferredCurrencyUnit: CurrencyUnit;
|
|
41
|
+
/**
|
|
42
|
+
* The rounded numeric value for this CurrencyAmount in the very base level of user's preferred
|
|
43
|
+
* currency. For example, for USD, the value will be in cents.
|
|
44
|
+
**/
|
|
45
|
+
preferredCurrencyValueRounded: number;
|
|
46
|
+
/**
|
|
47
|
+
* The approximate float value for this CurrencyAmount in the very base level of user's preferred
|
|
48
|
+
* currency. For example, for USD, the value will be in cents.
|
|
49
|
+
**/
|
|
50
|
+
preferredCurrencyValueApprox: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
51
53
|
const CONVERSION_MAP = {
|
|
52
54
|
[CurrencyUnit.BITCOIN]: {
|
|
53
55
|
[CurrencyUnit.BITCOIN]: (v: number) => v,
|
|
@@ -56,73 +58,414 @@ const CONVERSION_MAP = {
|
|
|
56
58
|
[CurrencyUnit.MILLISATOSHI]: (v: number) => v * 100_000_000_000,
|
|
57
59
|
[CurrencyUnit.NANOBITCOIN]: (v: number) => v * 1_000_000_000,
|
|
58
60
|
[CurrencyUnit.SATOSHI]: (v: number) => v * 100_000_000,
|
|
61
|
+
[CurrencyUnit.USD]: (v: number, centsPerBtc = 1) =>
|
|
62
|
+
/* Round without decimals since we're returning cents: */
|
|
63
|
+
round(v * centsPerBtc, 2),
|
|
59
64
|
},
|
|
60
65
|
[CurrencyUnit.MICROBITCOIN]: {
|
|
61
|
-
[CurrencyUnit.BITCOIN]: (v: number) =>
|
|
66
|
+
[CurrencyUnit.BITCOIN]: (v: number) => v / 1_000_000,
|
|
62
67
|
[CurrencyUnit.MICROBITCOIN]: (v: number) => v,
|
|
63
|
-
[CurrencyUnit.MILLIBITCOIN]: (v: number) =>
|
|
68
|
+
[CurrencyUnit.MILLIBITCOIN]: (v: number) => v / 1000,
|
|
64
69
|
[CurrencyUnit.MILLISATOSHI]: (v: number) => v * 100_000,
|
|
65
70
|
[CurrencyUnit.NANOBITCOIN]: (v: number) => v * 1000,
|
|
66
71
|
[CurrencyUnit.SATOSHI]: (v: number) => v * 100,
|
|
72
|
+
[CurrencyUnit.USD]: (v: number, centsPerBtc = 1) =>
|
|
73
|
+
/* Round without decimals since we're returning cents: */
|
|
74
|
+
round((v / 1_000_000) * centsPerBtc),
|
|
67
75
|
},
|
|
68
76
|
[CurrencyUnit.MILLIBITCOIN]: {
|
|
69
|
-
[CurrencyUnit.BITCOIN]: (v: number) =>
|
|
77
|
+
[CurrencyUnit.BITCOIN]: (v: number) => v / 1_000,
|
|
70
78
|
[CurrencyUnit.MICROBITCOIN]: (v: number) => v * 1000,
|
|
71
79
|
[CurrencyUnit.MILLIBITCOIN]: (v: number) => v,
|
|
72
80
|
[CurrencyUnit.MILLISATOSHI]: (v: number) => v * 100_000_000,
|
|
73
81
|
[CurrencyUnit.NANOBITCOIN]: (v: number) => v * 1_000_000,
|
|
74
82
|
[CurrencyUnit.SATOSHI]: (v: number) => v * 100_000,
|
|
83
|
+
[CurrencyUnit.USD]: (v: number, centsPerBtc = 1) =>
|
|
84
|
+
/* Round without decimals since we're returning cents: */
|
|
85
|
+
round((v / 1_000) * centsPerBtc),
|
|
75
86
|
},
|
|
76
87
|
[CurrencyUnit.MILLISATOSHI]: {
|
|
77
|
-
[CurrencyUnit.BITCOIN]: (v: number) =>
|
|
78
|
-
[CurrencyUnit.MICROBITCOIN]: (v: number) =>
|
|
79
|
-
[CurrencyUnit.MILLIBITCOIN]: (v: number) =>
|
|
88
|
+
[CurrencyUnit.BITCOIN]: (v: number) => v / 100_000_000_000,
|
|
89
|
+
[CurrencyUnit.MICROBITCOIN]: (v: number) => v / 100_000,
|
|
90
|
+
[CurrencyUnit.MILLIBITCOIN]: (v: number) => v / 100_000_000,
|
|
80
91
|
[CurrencyUnit.MILLISATOSHI]: (v: number) => v,
|
|
81
|
-
[CurrencyUnit.NANOBITCOIN]: (v: number) =>
|
|
82
|
-
[CurrencyUnit.SATOSHI]: (v: number) =>
|
|
92
|
+
[CurrencyUnit.NANOBITCOIN]: (v: number) => v / 100,
|
|
93
|
+
[CurrencyUnit.SATOSHI]: (v: number) => v / 1000,
|
|
94
|
+
[CurrencyUnit.USD]: (v: number, centsPerBtc = 1) =>
|
|
95
|
+
/* Round without decimals since we're returning cents: */
|
|
96
|
+
round((v / 100_000_000_000) * centsPerBtc),
|
|
83
97
|
},
|
|
84
98
|
[CurrencyUnit.NANOBITCOIN]: {
|
|
85
|
-
[CurrencyUnit.BITCOIN]: (v: number) =>
|
|
86
|
-
[CurrencyUnit.MICROBITCOIN]: (v: number) =>
|
|
87
|
-
[CurrencyUnit.MILLIBITCOIN]: (v: number) =>
|
|
99
|
+
[CurrencyUnit.BITCOIN]: (v: number) => v / 1_000_000_000,
|
|
100
|
+
[CurrencyUnit.MICROBITCOIN]: (v: number) => v / 1000,
|
|
101
|
+
[CurrencyUnit.MILLIBITCOIN]: (v: number) => v / 1_000_000,
|
|
88
102
|
[CurrencyUnit.MILLISATOSHI]: (v: number) => v * 100,
|
|
89
103
|
[CurrencyUnit.NANOBITCOIN]: (v: number) => v,
|
|
90
|
-
[CurrencyUnit.SATOSHI]: (v: number) =>
|
|
104
|
+
[CurrencyUnit.SATOSHI]: (v: number) => v / 10,
|
|
105
|
+
[CurrencyUnit.USD]: (v: number, centsPerBtc = 1) =>
|
|
106
|
+
/* Round without decimals since we're returning cents: */
|
|
107
|
+
round((v / 1_000_000_000) * centsPerBtc),
|
|
91
108
|
},
|
|
92
109
|
[CurrencyUnit.SATOSHI]: {
|
|
93
|
-
[CurrencyUnit.BITCOIN]: (v: number) =>
|
|
94
|
-
[CurrencyUnit.MICROBITCOIN]: (v: number) =>
|
|
95
|
-
[CurrencyUnit.MILLIBITCOIN]: (v: number) =>
|
|
110
|
+
[CurrencyUnit.BITCOIN]: (v: number) => v / 100_000_000,
|
|
111
|
+
[CurrencyUnit.MICROBITCOIN]: (v: number) => v / 100,
|
|
112
|
+
[CurrencyUnit.MILLIBITCOIN]: (v: number) => v / 100_000,
|
|
96
113
|
[CurrencyUnit.MILLISATOSHI]: (v: number) => v * 1000,
|
|
97
114
|
[CurrencyUnit.NANOBITCOIN]: (v: number) => v * 10,
|
|
98
115
|
[CurrencyUnit.SATOSHI]: (v: number) => v,
|
|
116
|
+
[CurrencyUnit.USD]: (v: number, centsPerBtc = 1) =>
|
|
117
|
+
/* Round without decimals since we're returning cents: */
|
|
118
|
+
round((v / 100_000_000) * centsPerBtc),
|
|
119
|
+
},
|
|
120
|
+
[CurrencyUnit.USD]: {
|
|
121
|
+
[CurrencyUnit.BITCOIN]: (v: number, centsPerBtc = 1) => v / centsPerBtc,
|
|
122
|
+
[CurrencyUnit.MICROBITCOIN]: (v: number, centsPerBtc = 1) =>
|
|
123
|
+
(v / centsPerBtc) * 1_000_000,
|
|
124
|
+
[CurrencyUnit.MILLIBITCOIN]: (v: number, centsPerBtc = 1) =>
|
|
125
|
+
(v / centsPerBtc) * 1_000,
|
|
126
|
+
[CurrencyUnit.MILLISATOSHI]: (v: number, centsPerBtc = 1) =>
|
|
127
|
+
(v / centsPerBtc) * 100_000_000_000,
|
|
128
|
+
[CurrencyUnit.NANOBITCOIN]: (v: number, centsPerBtc = 1) =>
|
|
129
|
+
(v / centsPerBtc) * 1_000_000_000,
|
|
130
|
+
[CurrencyUnit.SATOSHI]: (v: number, centsPerBtc = 1) =>
|
|
131
|
+
(v / centsPerBtc) * 100_000_000,
|
|
132
|
+
[CurrencyUnit.USD]: (v: number) => v,
|
|
99
133
|
},
|
|
100
134
|
};
|
|
101
135
|
|
|
102
|
-
export
|
|
103
|
-
|
|
136
|
+
export function convertCurrencyAmountValue(
|
|
137
|
+
fromUnit: CurrencyUnit,
|
|
104
138
|
toUnit: CurrencyUnit,
|
|
105
|
-
|
|
139
|
+
amount: number,
|
|
140
|
+
centsPerBtc = 1,
|
|
141
|
+
): number {
|
|
106
142
|
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
toUnit === CurrencyUnit.FUTURE_VALUE ||
|
|
110
|
-
toUnit === CurrencyUnit.USD
|
|
143
|
+
fromUnit === CurrencyUnit.FUTURE_VALUE ||
|
|
144
|
+
toUnit === CurrencyUnit.FUTURE_VALUE
|
|
111
145
|
) {
|
|
112
146
|
throw new LightsparkException("CurrencyError", `Unsupported CurrencyUnit.`);
|
|
113
147
|
}
|
|
114
148
|
|
|
115
|
-
|
|
149
|
+
if (fromUnit === toUnit) {
|
|
150
|
+
return amount;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const conversionFn = CONVERSION_MAP[fromUnit][toUnit];
|
|
116
154
|
if (!conversionFn) {
|
|
117
155
|
throw new LightsparkException(
|
|
118
156
|
"CurrencyError",
|
|
119
|
-
`Cannot convert from ${
|
|
157
|
+
`Cannot convert from ${fromUnit} to ${toUnit}`,
|
|
120
158
|
);
|
|
121
159
|
}
|
|
160
|
+
|
|
161
|
+
return conversionFn(amount, centsPerBtc);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const convertCurrencyAmount = (
|
|
165
|
+
from: CurrencyAmountType,
|
|
166
|
+
toUnit: CurrencyUnit,
|
|
167
|
+
): CurrencyAmountType => {
|
|
168
|
+
const value = convertCurrencyAmountValue(
|
|
169
|
+
from.originalUnit,
|
|
170
|
+
toUnit,
|
|
171
|
+
from.originalValue,
|
|
172
|
+
);
|
|
122
173
|
return {
|
|
123
174
|
...from,
|
|
124
175
|
preferredCurrencyUnit: toUnit,
|
|
125
|
-
preferredCurrencyValueApprox:
|
|
126
|
-
preferredCurrencyValueRounded:
|
|
176
|
+
preferredCurrencyValueApprox: value,
|
|
177
|
+
preferredCurrencyValueRounded: value,
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export type CurrencyMap = {
|
|
182
|
+
sats: number;
|
|
183
|
+
msats: number;
|
|
184
|
+
btc: number;
|
|
185
|
+
[CurrencyUnit.BITCOIN]: number;
|
|
186
|
+
[CurrencyUnit.SATOSHI]: number;
|
|
187
|
+
[CurrencyUnit.MILLISATOSHI]: number;
|
|
188
|
+
[CurrencyUnit.MICROBITCOIN]: number;
|
|
189
|
+
[CurrencyUnit.MILLIBITCOIN]: number;
|
|
190
|
+
[CurrencyUnit.NANOBITCOIN]: number;
|
|
191
|
+
[CurrencyUnit.USD]: number;
|
|
192
|
+
[CurrencyUnit.FUTURE_VALUE]: number;
|
|
193
|
+
formatted: {
|
|
194
|
+
sats: string;
|
|
195
|
+
msats: string;
|
|
196
|
+
btc: string;
|
|
197
|
+
[CurrencyUnit.BITCOIN]: string;
|
|
198
|
+
[CurrencyUnit.SATOSHI]: string;
|
|
199
|
+
[CurrencyUnit.MILLISATOSHI]: string;
|
|
200
|
+
[CurrencyUnit.MILLIBITCOIN]: string;
|
|
201
|
+
[CurrencyUnit.MICROBITCOIN]: string;
|
|
202
|
+
[CurrencyUnit.NANOBITCOIN]: string;
|
|
203
|
+
[CurrencyUnit.USD]: string;
|
|
204
|
+
[CurrencyUnit.FUTURE_VALUE]: string;
|
|
205
|
+
};
|
|
206
|
+
isZero: boolean;
|
|
207
|
+
isLessThan: (other: CurrencyMap | CurrencyAmountObj | number) => boolean;
|
|
208
|
+
isGreaterThan: (other: CurrencyMap | CurrencyAmountObj | number) => boolean;
|
|
209
|
+
isEqualTo: (other: CurrencyMap | CurrencyAmountObj | number) => boolean;
|
|
210
|
+
type: "CurrencyMap";
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export type CurrencyAmountObj = {
|
|
214
|
+
/* Technically the generated graphql schema has value as `any` but it's always a number.
|
|
215
|
+
We are intentionally widening the type here to allow for more forgiving input: */
|
|
216
|
+
value?: number | string | null;
|
|
217
|
+
/* assume satoshi if not provided */
|
|
218
|
+
unit?: CurrencyUnit;
|
|
219
|
+
__typename?: "CurrencyAmount";
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export type CurrencyAmountArg =
|
|
223
|
+
| CurrencyAmountObj
|
|
224
|
+
| CurrencyAmountType
|
|
225
|
+
| undefined
|
|
226
|
+
| null;
|
|
227
|
+
|
|
228
|
+
export function isCurrencyAmountObj(arg: unknown): arg is CurrencyAmountObj {
|
|
229
|
+
return (
|
|
230
|
+
typeof arg === "object" && arg !== null && "value" in arg && "unit" in arg
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function isCurrencyAmount(arg: unknown): arg is CurrencyAmountType {
|
|
235
|
+
return (
|
|
236
|
+
typeof arg === "object" &&
|
|
237
|
+
arg !== null &&
|
|
238
|
+
"originalValue" in arg &&
|
|
239
|
+
"originalUnit" in arg &&
|
|
240
|
+
"preferredCurrencyUnit" in arg &&
|
|
241
|
+
"preferredCurrencyValueRounded" in arg &&
|
|
242
|
+
"preferredCurrencyValueApprox" in arg
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function asNumber(value: string | number | null | undefined) {
|
|
247
|
+
if (typeof value === "string") {
|
|
248
|
+
return Number(value);
|
|
249
|
+
}
|
|
250
|
+
return value || 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function getCurrencyAmount(currencyAmountArg: CurrencyAmountArg) {
|
|
254
|
+
let value = 0;
|
|
255
|
+
let unit = undefined;
|
|
256
|
+
|
|
257
|
+
if (isCurrencyAmountObj(currencyAmountArg)) {
|
|
258
|
+
value = asNumber(currencyAmountArg.value);
|
|
259
|
+
unit = currencyAmountArg.unit;
|
|
260
|
+
} else if (isCurrencyAmount(currencyAmountArg)) {
|
|
261
|
+
value = currencyAmountArg.originalValue;
|
|
262
|
+
unit = currencyAmountArg.originalUnit;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
value: asNumber(value),
|
|
267
|
+
unit: unit || CurrencyUnit.SATOSHI,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function mapCurrencyAmount(
|
|
272
|
+
currencyAmountArg: CurrencyAmountArg,
|
|
273
|
+
centsPerBtc = 1,
|
|
274
|
+
): CurrencyMap {
|
|
275
|
+
const { value, unit } = getCurrencyAmount(currencyAmountArg);
|
|
276
|
+
|
|
277
|
+
const convert = convertCurrencyAmountValue;
|
|
278
|
+
const sats = convert(unit, CurrencyUnit.SATOSHI, value, centsPerBtc);
|
|
279
|
+
const btc = convert(unit, CurrencyUnit.BITCOIN, value, centsPerBtc);
|
|
280
|
+
const msats = convert(unit, CurrencyUnit.MILLISATOSHI, value, centsPerBtc);
|
|
281
|
+
const usd = convert(unit, CurrencyUnit.USD, value, centsPerBtc);
|
|
282
|
+
const mibtc = convert(unit, CurrencyUnit.MICROBITCOIN, value, centsPerBtc);
|
|
283
|
+
const mlbtc = convert(unit, CurrencyUnit.MILLIBITCOIN, value, centsPerBtc);
|
|
284
|
+
const nbtc = convert(unit, CurrencyUnit.NANOBITCOIN, value, centsPerBtc);
|
|
285
|
+
|
|
286
|
+
const mapWithCurrencyUnits = {
|
|
287
|
+
[CurrencyUnit.BITCOIN]: btc,
|
|
288
|
+
[CurrencyUnit.SATOSHI]: sats,
|
|
289
|
+
[CurrencyUnit.MILLISATOSHI]: msats,
|
|
290
|
+
[CurrencyUnit.USD]: usd,
|
|
291
|
+
[CurrencyUnit.MICROBITCOIN]: mibtc,
|
|
292
|
+
[CurrencyUnit.MILLIBITCOIN]: mlbtc,
|
|
293
|
+
[CurrencyUnit.NANOBITCOIN]: nbtc,
|
|
294
|
+
[CurrencyUnit.FUTURE_VALUE]: NaN,
|
|
295
|
+
formatted: {
|
|
296
|
+
[CurrencyUnit.BITCOIN]: formatCurrencyStr({
|
|
297
|
+
value: btc,
|
|
298
|
+
unit: CurrencyUnit.BITCOIN,
|
|
299
|
+
}),
|
|
300
|
+
[CurrencyUnit.SATOSHI]: formatCurrencyStr({
|
|
301
|
+
value: sats,
|
|
302
|
+
unit: CurrencyUnit.SATOSHI,
|
|
303
|
+
}),
|
|
304
|
+
[CurrencyUnit.MILLISATOSHI]: formatCurrencyStr({
|
|
305
|
+
value: msats,
|
|
306
|
+
unit: CurrencyUnit.MILLISATOSHI,
|
|
307
|
+
}),
|
|
308
|
+
[CurrencyUnit.MICROBITCOIN]: formatCurrencyStr({
|
|
309
|
+
value: mibtc,
|
|
310
|
+
unit: CurrencyUnit.MICROBITCOIN,
|
|
311
|
+
}),
|
|
312
|
+
[CurrencyUnit.MILLIBITCOIN]: formatCurrencyStr({
|
|
313
|
+
value: mlbtc,
|
|
314
|
+
unit: CurrencyUnit.MILLIBITCOIN,
|
|
315
|
+
}),
|
|
316
|
+
[CurrencyUnit.NANOBITCOIN]: formatCurrencyStr({
|
|
317
|
+
value: nbtc,
|
|
318
|
+
unit: CurrencyUnit.NANOBITCOIN,
|
|
319
|
+
}),
|
|
320
|
+
[CurrencyUnit.USD]: formatCurrencyStr({
|
|
321
|
+
value: usd,
|
|
322
|
+
unit: CurrencyUnit.USD,
|
|
323
|
+
}),
|
|
324
|
+
[CurrencyUnit.FUTURE_VALUE]: "-",
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
...mapWithCurrencyUnits,
|
|
330
|
+
btc,
|
|
331
|
+
sats,
|
|
332
|
+
msats,
|
|
333
|
+
isZero: msats === 0,
|
|
334
|
+
isLessThan: (other: CurrencyMap | CurrencyAmountObj | number) => {
|
|
335
|
+
if (isNumber(other)) {
|
|
336
|
+
return msats < other;
|
|
337
|
+
}
|
|
338
|
+
if (isCurrencyAmountObj(other)) {
|
|
339
|
+
other = mapCurrencyAmount(other);
|
|
340
|
+
}
|
|
341
|
+
return msats < other.msats;
|
|
342
|
+
},
|
|
343
|
+
isGreaterThan: (other: CurrencyMap | CurrencyAmountObj | number) => {
|
|
344
|
+
if (isNumber(other)) {
|
|
345
|
+
return msats > other;
|
|
346
|
+
}
|
|
347
|
+
if (isCurrencyAmountObj(other)) {
|
|
348
|
+
other = mapCurrencyAmount(other);
|
|
349
|
+
}
|
|
350
|
+
return msats > other.msats;
|
|
351
|
+
},
|
|
352
|
+
isEqualTo: (other: CurrencyMap | CurrencyAmountObj | number) => {
|
|
353
|
+
if (isNumber(other)) {
|
|
354
|
+
return msats === other;
|
|
355
|
+
}
|
|
356
|
+
if (isCurrencyAmountObj(other)) {
|
|
357
|
+
other = mapCurrencyAmount(other);
|
|
358
|
+
}
|
|
359
|
+
return msats === other.msats;
|
|
360
|
+
},
|
|
361
|
+
formatted: {
|
|
362
|
+
...mapWithCurrencyUnits.formatted,
|
|
363
|
+
btc: mapWithCurrencyUnits.formatted[CurrencyUnit.BITCOIN],
|
|
364
|
+
sats: mapWithCurrencyUnits.formatted[CurrencyUnit.SATOSHI],
|
|
365
|
+
msats: mapWithCurrencyUnits.formatted[CurrencyUnit.MILLISATOSHI],
|
|
366
|
+
},
|
|
367
|
+
type: "CurrencyMap" as const,
|
|
127
368
|
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export const isCurrencyMap = (
|
|
372
|
+
currencyMap: unknown,
|
|
373
|
+
): currencyMap is CurrencyMap =>
|
|
374
|
+
typeof currencyMap === "object" &&
|
|
375
|
+
currencyMap !== null &&
|
|
376
|
+
"type" in currencyMap &&
|
|
377
|
+
typeof currencyMap.type === "string" &&
|
|
378
|
+
currencyMap.type === "CurrencyMap";
|
|
379
|
+
|
|
380
|
+
export const abbrCurrencyUnit = (unit: CurrencyUnit) => {
|
|
381
|
+
switch (unit) {
|
|
382
|
+
case CurrencyUnit.BITCOIN:
|
|
383
|
+
return "BTC";
|
|
384
|
+
case CurrencyUnit.SATOSHI:
|
|
385
|
+
return "SAT";
|
|
386
|
+
case CurrencyUnit.MILLISATOSHI:
|
|
387
|
+
return "MSAT";
|
|
388
|
+
case CurrencyUnit.USD:
|
|
389
|
+
return "USD";
|
|
390
|
+
}
|
|
391
|
+
return "Unsupported CurrencyUnit";
|
|
128
392
|
};
|
|
393
|
+
|
|
394
|
+
export function formatCurrencyStr(
|
|
395
|
+
amount: CurrencyAmountArg,
|
|
396
|
+
maxFractionDigits?: number,
|
|
397
|
+
compact?: boolean,
|
|
398
|
+
showBtcSymbol = false,
|
|
399
|
+
options: Intl.NumberFormatOptions = {},
|
|
400
|
+
) {
|
|
401
|
+
const currencyAmount = getCurrencyAmount(amount);
|
|
402
|
+
let { value: num } = currencyAmount;
|
|
403
|
+
const { unit } = currencyAmount;
|
|
404
|
+
|
|
405
|
+
/* Currencies should always be represented in the smallest unit, e.g. cents for USD: */
|
|
406
|
+
if (unit === CurrencyUnit.USD) {
|
|
407
|
+
num = num / 100;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function getDefaultMaxFractionDigits(defaultDigits: number) {
|
|
411
|
+
return typeof maxFractionDigits === "undefined"
|
|
412
|
+
? compact
|
|
413
|
+
? 1
|
|
414
|
+
: defaultDigits
|
|
415
|
+
: maxFractionDigits;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Symbol handled by toLocaleString for USD. These rely on the LightsparkIcons font
|
|
419
|
+
const symbol = !showBtcSymbol
|
|
420
|
+
? ""
|
|
421
|
+
: unit === CurrencyUnit.BITCOIN
|
|
422
|
+
? ""
|
|
423
|
+
: unit === CurrencyUnit.SATOSHI
|
|
424
|
+
? ""
|
|
425
|
+
: "";
|
|
426
|
+
|
|
427
|
+
const currentLocale = getCurrentLocale();
|
|
428
|
+
|
|
429
|
+
switch (unit) {
|
|
430
|
+
case CurrencyUnit.BITCOIN:
|
|
431
|
+
return `${symbol}${num.toLocaleString(currentLocale, {
|
|
432
|
+
notation: compact ? ("compact" as const) : undefined,
|
|
433
|
+
maximumFractionDigits: getDefaultMaxFractionDigits(4),
|
|
434
|
+
...options,
|
|
435
|
+
})}`;
|
|
436
|
+
case CurrencyUnit.MILLISATOSHI:
|
|
437
|
+
case CurrencyUnit.SATOSHI:
|
|
438
|
+
case CurrencyUnit.MICROBITCOIN:
|
|
439
|
+
case CurrencyUnit.MILLIBITCOIN:
|
|
440
|
+
case CurrencyUnit.NANOBITCOIN:
|
|
441
|
+
default:
|
|
442
|
+
return `${symbol}${num.toLocaleString(currentLocale, {
|
|
443
|
+
notation: compact ? ("compact" as const) : undefined,
|
|
444
|
+
maximumFractionDigits: getDefaultMaxFractionDigits(0),
|
|
445
|
+
...options,
|
|
446
|
+
})}`;
|
|
447
|
+
case CurrencyUnit.USD:
|
|
448
|
+
return num.toLocaleString(currentLocale, {
|
|
449
|
+
style: "currency",
|
|
450
|
+
currency: defaultCurrencyCode,
|
|
451
|
+
notation: compact ? ("compact" as const) : undefined,
|
|
452
|
+
maximumFractionDigits: getDefaultMaxFractionDigits(2),
|
|
453
|
+
...options,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export function localeToCurrencySymbol(locale: string) {
|
|
459
|
+
const currencyCode = localeToCurrencyCode(locale);
|
|
460
|
+
const formatted = new Intl.NumberFormat(locale, {
|
|
461
|
+
style: "currency",
|
|
462
|
+
currency: currencyCode,
|
|
463
|
+
useGrouping: false, // to avoid thousands separators
|
|
464
|
+
minimumFractionDigits: 0,
|
|
465
|
+
maximumFractionDigits: 0,
|
|
466
|
+
}).format(0);
|
|
467
|
+
|
|
468
|
+
// Remove numeric and non-breaking space characters to extract the currency symbol
|
|
469
|
+
const symbol = formatted.replace(/[0-9\s\u00a0]/g, "");
|
|
470
|
+
return symbol;
|
|
471
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -6,6 +6,9 @@ export * from "./currency.js";
|
|
|
6
6
|
export * from "./environment.js";
|
|
7
7
|
export * from "./errors.js";
|
|
8
8
|
export * from "./hex.js";
|
|
9
|
+
export * from "./locale.js";
|
|
10
|
+
export * from "./localeToCurrencyCodes.js";
|
|
11
|
+
export * from "./numbers.js";
|
|
9
12
|
export * from "./pollUntil.js";
|
|
10
13
|
export * from "./sleep.js";
|
|
11
14
|
export * from "./types.js";
|