@lightsparkdev/core 1.0.9 → 1.0.11
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 +13 -0
- package/dist/{chunk-UU6SHVGX.js → chunk-F3XHLUGC.js} +34 -35
- package/dist/index.cjs +115 -112
- package/dist/index.d.cts +168 -0
- package/dist/index.d.ts +42 -39
- package/dist/index.js +72 -68
- package/dist/utils/index.cjs +31 -32
- package/dist/utils/index.d.cts +252 -0
- package/dist/utils/index.d.ts +50 -17
- package/dist/utils/index.js +1 -1
- package/package.json +6 -6
- package/src/Logger.ts +1 -1
- package/src/auth/StubAuthProvider.ts +6 -7
- package/src/crypto/crypto.ts +7 -6
- package/src/crypto/index.ts +1 -1
- package/src/crypto/tests/crypto.test.ts +21 -0
- package/src/index.ts +5 -5
- package/src/requester/Query.ts +4 -1
- package/src/requester/Requester.ts +20 -7
- package/src/utils/currency.ts +56 -18
- package/src/utils/localeToCurrencyCodes.ts +3 -1
- package/src/utils/pollUntil.ts +37 -36
- package/src/utils/types.ts +7 -1
package/dist/utils/index.d.ts
CHANGED
|
@@ -7,26 +7,53 @@ declare function createSha256Hash(data: SourceData): Promise<Uint8Array>;
|
|
|
7
7
|
declare function createSha256Hash(data: SourceData, asHex: true): Promise<string>;
|
|
8
8
|
|
|
9
9
|
declare const defaultCurrencyCode = "USD";
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* This enum identifies the unit of currency associated with a CurrencyAmount.
|
|
12
|
+
* *
|
|
13
|
+
*/
|
|
11
14
|
declare enum CurrencyUnit {
|
|
12
15
|
/**
|
|
13
|
-
* This is an enum value that represents values that could be added in the
|
|
14
|
-
* Clients should support unknown values as more of them could be
|
|
16
|
+
* This is an enum value that represents values that could be added in the
|
|
17
|
+
* future. Clients should support unknown values as more of them could be
|
|
18
|
+
* added without notice.
|
|
15
19
|
*/
|
|
16
20
|
FUTURE_VALUE = "FUTURE_VALUE",
|
|
17
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Bitcoin is the cryptocurrency native to the Bitcoin network.
|
|
23
|
+
* It is used as the native medium for value transfer for the Lightning
|
|
24
|
+
* Network. *
|
|
25
|
+
*/
|
|
18
26
|
BITCOIN = "BITCOIN",
|
|
19
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* 0.00000001 (10e-8) Bitcoin or one hundred millionth of a Bitcoin.
|
|
29
|
+
* This is the unit most commonly used in Lightning transactions.
|
|
30
|
+
* *
|
|
31
|
+
*/
|
|
20
32
|
SATOSHI = "SATOSHI",
|
|
21
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* 0.001 Satoshi, or 10e-11 Bitcoin. We recommend using the Satoshi unit
|
|
35
|
+
* instead when possible. *
|
|
36
|
+
*/
|
|
22
37
|
MILLISATOSHI = "MILLISATOSHI",
|
|
23
38
|
/** United States Dollar. **/
|
|
24
39
|
USD = "USD",
|
|
25
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* 0.000000001 (10e-9) Bitcoin or a billionth of a Bitcoin.
|
|
42
|
+
* We recommend using the Satoshi unit instead when possible.
|
|
43
|
+
* *
|
|
44
|
+
*/
|
|
26
45
|
NANOBITCOIN = "NANOBITCOIN",
|
|
27
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* 0.000001 (10e-6) Bitcoin or a millionth of a Bitcoin.
|
|
48
|
+
* We recommend using the Satoshi unit instead when possible.
|
|
49
|
+
* *
|
|
50
|
+
*/
|
|
28
51
|
MICROBITCOIN = "MICROBITCOIN",
|
|
29
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* 0.001 (10e-3) Bitcoin or a thousandth of a Bitcoin.
|
|
54
|
+
* We recommend using the Satoshi unit instead when possible.
|
|
55
|
+
* *
|
|
56
|
+
*/
|
|
30
57
|
MILLIBITCOIN = "MILLIBITCOIN"
|
|
31
58
|
}
|
|
32
59
|
/** This object represents the value and unit for an amount of currency. **/
|
|
@@ -38,13 +65,15 @@ type CurrencyAmountType = {
|
|
|
38
65
|
/** The unit of user's preferred currency. **/
|
|
39
66
|
preferredCurrencyUnit: CurrencyUnit;
|
|
40
67
|
/**
|
|
41
|
-
* The rounded numeric value for this CurrencyAmount in the very base level
|
|
42
|
-
* currency. For example, for USD, the value will be in
|
|
68
|
+
* The rounded numeric value for this CurrencyAmount in the very base level
|
|
69
|
+
* of user's preferred currency. For example, for USD, the value will be in
|
|
70
|
+
* cents.
|
|
43
71
|
**/
|
|
44
72
|
preferredCurrencyValueRounded: number;
|
|
45
73
|
/**
|
|
46
|
-
* The approximate float value for this CurrencyAmount in the very base level
|
|
47
|
-
* currency. For example, for USD, the value will be in
|
|
74
|
+
* The approximate float value for this CurrencyAmount in the very base level
|
|
75
|
+
* of user's preferred currency. For example, for USD, the value will be in
|
|
76
|
+
* cents.
|
|
48
77
|
**/
|
|
49
78
|
preferredCurrencyValueApprox: number;
|
|
50
79
|
};
|
|
@@ -192,13 +221,14 @@ declare function linearInterpolate(value: number, fromRangeStart: number, fromRa
|
|
|
192
221
|
declare function round(num: number, decimalPlaces?: number): number;
|
|
193
222
|
declare function isNumber(value: unknown): value is number;
|
|
194
223
|
|
|
195
|
-
|
|
224
|
+
type GetValueResult<T> = {
|
|
196
225
|
stopPolling: boolean;
|
|
197
226
|
value: null | T;
|
|
198
|
-
}
|
|
227
|
+
};
|
|
228
|
+
declare function pollUntil<D extends () => Promise<unknown>, T>(asyncFn: D, getValue: (data: Awaited<ReturnType<D>>, response: {
|
|
199
229
|
stopPolling: boolean;
|
|
200
230
|
value: null | T;
|
|
201
|
-
}
|
|
231
|
+
}) => GetValueResult<T>, maxPolls?: number, pollIntervalMs?: number, ignoreErrors?: boolean | ((e: unknown) => boolean), getMaxPollsError?: (maxPolls: number) => Error): Promise<T>;
|
|
202
232
|
|
|
203
233
|
declare function sleep(ms: number): Promise<unknown>;
|
|
204
234
|
|
|
@@ -215,5 +245,8 @@ declare const isType: <T extends string>(typename: T) => <N extends {
|
|
|
215
245
|
}>(node: N | null | undefined) => node is Extract<N, {
|
|
216
246
|
__typename: T;
|
|
217
247
|
}>;
|
|
248
|
+
type DeepPartial<T> = T extends object ? {
|
|
249
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
250
|
+
} : T;
|
|
218
251
|
|
|
219
|
-
export { ById, CurrencyAmountArg, CurrencyAmountObj, CurrencyAmountType, CurrencyCodes, CurrencyLocales, CurrencyMap, CurrencyUnit, ExpandRecursively, Maybe, OmitTypename, abbrCurrencyUnit, b64decode, b64encode, bytesToHex, clamp, convertCurrencyAmount, convertCurrencyAmountValue, countryCodesToCurrencyCodes, createSha256Hash, defaultCurrencyCode, formatCurrencyStr, getCurrentLocale, getErrorMsg, hexToBytes, isBrowser, isCurrencyAmount, isCurrencyAmountObj, isCurrencyMap, isError, isErrorMsg, isErrorWithMessage, isNode, isNumber, isTest, isType, linearInterpolate, localeToCurrencyCode, localeToCurrencySymbol, mapCurrencyAmount, pollUntil, round, separateCurrencyStrParts, sleep, urlsafe_b64decode };
|
|
252
|
+
export { ById, CurrencyAmountArg, CurrencyAmountObj, CurrencyAmountType, CurrencyCodes, CurrencyLocales, CurrencyMap, CurrencyUnit, DeepPartial, ExpandRecursively, Maybe, OmitTypename, abbrCurrencyUnit, b64decode, b64encode, bytesToHex, clamp, convertCurrencyAmount, convertCurrencyAmountValue, countryCodesToCurrencyCodes, createSha256Hash, defaultCurrencyCode, formatCurrencyStr, getCurrentLocale, getErrorMsg, hexToBytes, isBrowser, isCurrencyAmount, isCurrencyAmountObj, isCurrencyMap, isError, isErrorMsg, isErrorWithMessage, isNode, isNumber, isTest, isType, linearInterpolate, localeToCurrencyCode, localeToCurrencySymbol, mapCurrencyAmount, pollUntil, round, separateCurrencyStrParts, sleep, urlsafe_b64decode };
|
package/dist/utils/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightsparkdev/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Lightspark JS SDK",
|
|
5
5
|
"author": "Lightspark Inc.",
|
|
6
6
|
"keywords": [
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
],
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "yarn tsc && tsup",
|
|
64
|
-
"build:watch": "yarn build --watch",
|
|
64
|
+
"build:watch": "yarn build --watch --clean=false",
|
|
65
65
|
"clean": "rm -rf .turbo && rm -rf dist",
|
|
66
66
|
"dev": "yarn build -- --watch",
|
|
67
67
|
"format:fix": "prettier src --write",
|
|
@@ -96,11 +96,11 @@
|
|
|
96
96
|
"eslint": "^8.3.0",
|
|
97
97
|
"eslint-watch": "^8.0.0",
|
|
98
98
|
"jest": "^29.6.2",
|
|
99
|
-
"prettier": "3.0.
|
|
100
|
-
"prettier-plugin-organize-imports": "^3.2.
|
|
99
|
+
"prettier": "3.0.3",
|
|
100
|
+
"prettier-plugin-organize-imports": "^3.2.4",
|
|
101
101
|
"ts-jest": "^29.1.1",
|
|
102
102
|
"tsc-absolute": "^1.0.1",
|
|
103
|
-
"tsup": "^
|
|
104
|
-
"typescript": "^
|
|
103
|
+
"tsup": "^7.2.0",
|
|
104
|
+
"typescript": "^5.0.0"
|
|
105
105
|
}
|
|
106
106
|
}
|
package/src/Logger.ts
CHANGED
|
@@ -9,7 +9,7 @@ export class Logger {
|
|
|
9
9
|
|
|
10
10
|
constructor(loggerContext: string, getLoggingEnabled?: GetLoggingEnabled) {
|
|
11
11
|
this.context = loggerContext;
|
|
12
|
-
this.updateLoggingEnabled(getLoggingEnabled);
|
|
12
|
+
void this.updateLoggingEnabled(getLoggingEnabled);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
async updateLoggingEnabled(getLoggingEnabled: GetLoggingEnabled) {
|
|
@@ -4,14 +4,13 @@ import type AuthProvider from "./AuthProvider.js";
|
|
|
4
4
|
import { type Headers, type WsConnectionParams } from "./AuthProvider.js";
|
|
5
5
|
|
|
6
6
|
export default class StubAuthProvider implements AuthProvider {
|
|
7
|
-
|
|
8
|
-
return headers;
|
|
7
|
+
addAuthHeaders(headers: Headers) {
|
|
8
|
+
return Promise.resolve(headers);
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
return false;
|
|
10
|
+
isAuthorized(): Promise<boolean> {
|
|
11
|
+
return Promise.resolve(false);
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return params;
|
|
13
|
+
addWsConnectionParams(params: WsConnectionParams) {
|
|
14
|
+
return Promise.resolve(params);
|
|
16
15
|
}
|
|
17
16
|
}
|
package/src/crypto/crypto.ts
CHANGED
|
@@ -117,6 +117,8 @@ const deriveKey = async (
|
|
|
117
117
|
return [key, iv];
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
+
type Header = { v: number; i: number; lsv?: number };
|
|
121
|
+
|
|
120
122
|
const decrypt = async (
|
|
121
123
|
header_json: string,
|
|
122
124
|
ciphertext: string,
|
|
@@ -124,7 +126,7 @@ const decrypt = async (
|
|
|
124
126
|
): Promise<ArrayBuffer> => {
|
|
125
127
|
let decoded = b64decode(ciphertext);
|
|
126
128
|
|
|
127
|
-
let header;
|
|
129
|
+
let header: Header;
|
|
128
130
|
if (header_json === "AES_256_CBC_PBKDF2_5000_SHA256") {
|
|
129
131
|
header = {
|
|
130
132
|
v: 0,
|
|
@@ -133,13 +135,13 @@ const decrypt = async (
|
|
|
133
135
|
// Strip "Salted__" prefix
|
|
134
136
|
decoded = decoded.slice(8);
|
|
135
137
|
} else {
|
|
136
|
-
header = JSON.parse(header_json);
|
|
138
|
+
header = JSON.parse(header_json) as Header;
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
if (header.v < 0 || header.v > 4) {
|
|
140
142
|
throw new LightsparkException(
|
|
141
143
|
"DecryptionError",
|
|
142
|
-
|
|
144
|
+
`Unknown version ${header.v}`,
|
|
143
145
|
);
|
|
144
146
|
}
|
|
145
147
|
|
|
@@ -152,8 +154,7 @@ const decrypt = async (
|
|
|
152
154
|
const salt = decoded.slice(decoded.length - 8, decoded.length);
|
|
153
155
|
const nonce = decoded.slice(0, 12);
|
|
154
156
|
const cipherText = decoded.slice(12, decoded.length - 8);
|
|
155
|
-
|
|
156
|
-
const [key, _iv] = await deriveKey(
|
|
157
|
+
const [key /* , _iv */] = await deriveKey(
|
|
157
158
|
password,
|
|
158
159
|
salt,
|
|
159
160
|
header.i,
|
|
@@ -244,7 +245,7 @@ const sign = async (
|
|
|
244
245
|
name: "RSA-PSS",
|
|
245
246
|
saltLength: 32,
|
|
246
247
|
},
|
|
247
|
-
keyOrAlias
|
|
248
|
+
keyOrAlias,
|
|
248
249
|
data,
|
|
249
250
|
);
|
|
250
251
|
};
|
package/src/crypto/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
2
|
|
|
3
|
-
export * from "./crypto.js";
|
|
4
3
|
export * from "./KeyOrAlias.js";
|
|
5
4
|
export { default as LightsparkSigningException } from "./LightsparkSigningException.js";
|
|
6
5
|
export { default as NodeKeyCache } from "./NodeKeyCache.js";
|
|
7
6
|
export * from "./SigningKey.js";
|
|
7
|
+
export * from "./crypto.js";
|
|
8
8
|
export * from "./types.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { DefaultCrypto, b64encode } from "../../index.js";
|
|
3
|
+
|
|
4
|
+
describe("Crypto tests", () => {
|
|
5
|
+
test("should generate a key", async () => {
|
|
6
|
+
const { privateKey, publicKey } =
|
|
7
|
+
await DefaultCrypto.generateSigningKeyPair();
|
|
8
|
+
|
|
9
|
+
const serializedKeypair = {
|
|
10
|
+
privateKey: b64encode(
|
|
11
|
+
await DefaultCrypto.serializeSigningKey(privateKey, "pkcs8"),
|
|
12
|
+
),
|
|
13
|
+
publicKey: b64encode(
|
|
14
|
+
await DefaultCrypto.serializeSigningKey(publicKey, "spki"),
|
|
15
|
+
),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
expect(serializedKeypair.privateKey).not.toBeNull();
|
|
19
|
+
expect(serializedKeypair.publicKey).not.toBeNull();
|
|
20
|
+
}, 60_000);
|
|
21
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
2
|
|
|
3
|
-
export * from "./auth/index.js";
|
|
4
|
-
export * from "./constants/index.js";
|
|
5
|
-
export * from "./crypto/index.js";
|
|
6
3
|
export { default as LightsparkException } from "./LightsparkException.js";
|
|
7
4
|
export { Logger } from "./Logger.js";
|
|
8
|
-
export * from "./requester/index.js";
|
|
9
5
|
export {
|
|
10
|
-
apiDomainForEnvironment,
|
|
11
6
|
default as ServerEnvironment,
|
|
7
|
+
apiDomainForEnvironment,
|
|
12
8
|
} from "./ServerEnvironment.js";
|
|
9
|
+
export * from "./auth/index.js";
|
|
10
|
+
export * from "./constants/index.js";
|
|
11
|
+
export * from "./crypto/index.js";
|
|
12
|
+
export * from "./requester/index.js";
|
|
13
13
|
export * from "./utils/index.js";
|
package/src/requester/Query.ts
CHANGED
|
@@ -7,7 +7,10 @@ type Query<T> = {
|
|
|
7
7
|
/** The variables that will be passed to the query. **/
|
|
8
8
|
variables?: { [key: string]: unknown };
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* The function that will be called to construct the object from the
|
|
12
|
+
* response. *
|
|
13
|
+
*/
|
|
11
14
|
constructObject: (rawData: any) => T; // eslint-disable-line @typescript-eslint/no-explicit-any -- LIG-3400
|
|
12
15
|
|
|
13
16
|
/** The id of the node that will be used to sign the query. **/
|
|
@@ -26,6 +26,14 @@ export const LIGHTSPARK_BETA_HEADER_VALUE =
|
|
|
26
26
|
"z2h0BBYxTA83cjW7fi8QwWtBPCzkQKiemcuhKY08LOo";
|
|
27
27
|
dayjs.extend(utc);
|
|
28
28
|
|
|
29
|
+
type BodyData = {
|
|
30
|
+
query: string;
|
|
31
|
+
variables: { [key: string]: unknown };
|
|
32
|
+
operationName: string;
|
|
33
|
+
nonce?: number;
|
|
34
|
+
expires_at?: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
29
37
|
class Requester {
|
|
30
38
|
private readonly wsClient: WsClient;
|
|
31
39
|
constructor(
|
|
@@ -55,6 +63,7 @@ class Requester {
|
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
public async executeQuery<T>(query: Query<T>): Promise<T | null> {
|
|
66
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- LIG-3400 */
|
|
58
67
|
const data = await this.makeRawRequest(
|
|
59
68
|
query.queryPayload,
|
|
60
69
|
query.variables || {},
|
|
@@ -89,7 +98,7 @@ class Requester {
|
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
const operation = operationMatch[2];
|
|
92
|
-
const bodyData = {
|
|
101
|
+
const bodyData: BodyData = {
|
|
93
102
|
query: queryPayload,
|
|
94
103
|
variables,
|
|
95
104
|
operationName: operation,
|
|
@@ -111,7 +120,7 @@ class Requester {
|
|
|
111
120
|
signingNodeId: string | undefined = undefined,
|
|
112
121
|
skipAuth: boolean = false,
|
|
113
122
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any -- LIG-3400 */
|
|
114
|
-
): Promise<any
|
|
123
|
+
): Promise<any> {
|
|
115
124
|
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
116
125
|
const operationMatch = queryPayload.match(operationNameRegex);
|
|
117
126
|
if (!operationMatch || operationMatch.length < 3) {
|
|
@@ -131,7 +140,7 @@ class Requester {
|
|
|
131
140
|
}
|
|
132
141
|
}
|
|
133
142
|
const operation = operationMatch[2];
|
|
134
|
-
let bodyData = {
|
|
143
|
+
let bodyData: BodyData = {
|
|
135
144
|
query: queryPayload,
|
|
136
145
|
variables,
|
|
137
146
|
operationName: operation,
|
|
@@ -166,6 +175,7 @@ class Requester {
|
|
|
166
175
|
|
|
167
176
|
logger.info(`Requester.makeRawRequest`, {
|
|
168
177
|
url,
|
|
178
|
+
operationName: operation,
|
|
169
179
|
variables,
|
|
170
180
|
});
|
|
171
181
|
const response = await fetch(url, {
|
|
@@ -179,7 +189,10 @@ class Requester {
|
|
|
179
189
|
`Request ${operation} failed. ${response.statusText}`,
|
|
180
190
|
);
|
|
181
191
|
}
|
|
182
|
-
const responseJson = await response.json()
|
|
192
|
+
const responseJson = (await response.json()) as {
|
|
193
|
+
data: unknown;
|
|
194
|
+
errors: unknown;
|
|
195
|
+
};
|
|
183
196
|
const data = responseJson.data;
|
|
184
197
|
if (!data) {
|
|
185
198
|
throw new LightsparkException(
|
|
@@ -201,11 +214,11 @@ class Requester {
|
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
private async addSigningDataIfNeeded(
|
|
204
|
-
queryPayload:
|
|
217
|
+
queryPayload: BodyData,
|
|
205
218
|
headers: { [key: string]: string },
|
|
206
219
|
signingNodeId: string | undefined,
|
|
207
220
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any -- LIG-3400 */
|
|
208
|
-
): Promise<
|
|
221
|
+
): Promise<BodyData> {
|
|
209
222
|
if (!signingNodeId) {
|
|
210
223
|
return queryPayload;
|
|
211
224
|
}
|
|
@@ -225,7 +238,7 @@ class Requester {
|
|
|
225
238
|
expires_at: expiration,
|
|
226
239
|
};
|
|
227
240
|
|
|
228
|
-
const key =
|
|
241
|
+
const key = this.nodeKeyCache.getKey(signingNodeId);
|
|
229
242
|
if (!key) {
|
|
230
243
|
throw new LightsparkSigningException(
|
|
231
244
|
"Missing node of encrypted_signing_private_key",
|
package/src/utils/currency.ts
CHANGED
|
@@ -7,26 +7,53 @@ import { isNumber, round } from "./numbers.js";
|
|
|
7
7
|
|
|
8
8
|
export const defaultCurrencyCode = "USD";
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* This enum identifies the unit of currency associated with a CurrencyAmount.
|
|
12
|
+
* *
|
|
13
|
+
*/
|
|
11
14
|
export enum CurrencyUnit {
|
|
12
15
|
/**
|
|
13
|
-
* This is an enum value that represents values that could be added in the
|
|
14
|
-
* Clients should support unknown values as more of them could be
|
|
16
|
+
* This is an enum value that represents values that could be added in the
|
|
17
|
+
* future. Clients should support unknown values as more of them could be
|
|
18
|
+
* added without notice.
|
|
15
19
|
*/
|
|
16
20
|
FUTURE_VALUE = "FUTURE_VALUE",
|
|
17
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Bitcoin is the cryptocurrency native to the Bitcoin network.
|
|
23
|
+
* It is used as the native medium for value transfer for the Lightning
|
|
24
|
+
* Network. *
|
|
25
|
+
*/
|
|
18
26
|
BITCOIN = "BITCOIN",
|
|
19
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* 0.00000001 (10e-8) Bitcoin or one hundred millionth of a Bitcoin.
|
|
29
|
+
* This is the unit most commonly used in Lightning transactions.
|
|
30
|
+
* *
|
|
31
|
+
*/
|
|
20
32
|
SATOSHI = "SATOSHI",
|
|
21
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* 0.001 Satoshi, or 10e-11 Bitcoin. We recommend using the Satoshi unit
|
|
35
|
+
* instead when possible. *
|
|
36
|
+
*/
|
|
22
37
|
MILLISATOSHI = "MILLISATOSHI",
|
|
23
38
|
/** United States Dollar. **/
|
|
24
39
|
USD = "USD",
|
|
25
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* 0.000000001 (10e-9) Bitcoin or a billionth of a Bitcoin.
|
|
42
|
+
* We recommend using the Satoshi unit instead when possible.
|
|
43
|
+
* *
|
|
44
|
+
*/
|
|
26
45
|
NANOBITCOIN = "NANOBITCOIN",
|
|
27
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* 0.000001 (10e-6) Bitcoin or a millionth of a Bitcoin.
|
|
48
|
+
* We recommend using the Satoshi unit instead when possible.
|
|
49
|
+
* *
|
|
50
|
+
*/
|
|
28
51
|
MICROBITCOIN = "MICROBITCOIN",
|
|
29
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* 0.001 (10e-3) Bitcoin or a thousandth of a Bitcoin.
|
|
54
|
+
* We recommend using the Satoshi unit instead when possible.
|
|
55
|
+
* *
|
|
56
|
+
*/
|
|
30
57
|
MILLIBITCOIN = "MILLIBITCOIN",
|
|
31
58
|
}
|
|
32
59
|
|
|
@@ -39,13 +66,15 @@ export type CurrencyAmountType = {
|
|
|
39
66
|
/** The unit of user's preferred currency. **/
|
|
40
67
|
preferredCurrencyUnit: CurrencyUnit;
|
|
41
68
|
/**
|
|
42
|
-
* The rounded numeric value for this CurrencyAmount in the very base level
|
|
43
|
-
* currency. For example, for USD, the value will be in
|
|
69
|
+
* The rounded numeric value for this CurrencyAmount in the very base level
|
|
70
|
+
* of user's preferred currency. For example, for USD, the value will be in
|
|
71
|
+
* cents.
|
|
44
72
|
**/
|
|
45
73
|
preferredCurrencyValueRounded: number;
|
|
46
74
|
/**
|
|
47
|
-
* The approximate float value for this CurrencyAmount in the very base level
|
|
48
|
-
* currency. For example, for USD, the value will be in
|
|
75
|
+
* The approximate float value for this CurrencyAmount in the very base level
|
|
76
|
+
* of user's preferred currency. For example, for USD, the value will be in
|
|
77
|
+
* cents.
|
|
49
78
|
**/
|
|
50
79
|
preferredCurrencyValueApprox: number;
|
|
51
80
|
};
|
|
@@ -211,8 +240,12 @@ export type CurrencyMap = {
|
|
|
211
240
|
};
|
|
212
241
|
|
|
213
242
|
export type CurrencyAmountObj = {
|
|
214
|
-
/*
|
|
215
|
-
|
|
243
|
+
/*
|
|
244
|
+
* Technically the generated graphql schema has value as `any` but it's
|
|
245
|
+
* always a number.
|
|
246
|
+
* We are intentionally widening the type here to allow for more forgiving
|
|
247
|
+
* input:
|
|
248
|
+
*/
|
|
216
249
|
value?: number | string | null;
|
|
217
250
|
/* assume satoshi if not provided */
|
|
218
251
|
unit?: CurrencyUnit;
|
|
@@ -402,7 +435,10 @@ export function formatCurrencyStr(
|
|
|
402
435
|
let { value: num } = currencyAmount;
|
|
403
436
|
const { unit } = currencyAmount;
|
|
404
437
|
|
|
405
|
-
|
|
438
|
+
/**
|
|
439
|
+
* Currencies should always be represented in the smallest unit, e.g.
|
|
440
|
+
* cents for USD:
|
|
441
|
+
*/
|
|
406
442
|
if (unit === CurrencyUnit.USD) {
|
|
407
443
|
num = num / 100;
|
|
408
444
|
}
|
|
@@ -415,7 +451,8 @@ export function formatCurrencyStr(
|
|
|
415
451
|
: maxFractionDigits;
|
|
416
452
|
}
|
|
417
453
|
|
|
418
|
-
// Symbol handled by toLocaleString for USD.
|
|
454
|
+
// Symbol handled by toLocaleString for USD.
|
|
455
|
+
// These rely on the LightsparkIcons font
|
|
419
456
|
const symbol = !showBtcSymbol
|
|
420
457
|
? ""
|
|
421
458
|
: unit === CurrencyUnit.BITCOIN
|
|
@@ -472,7 +509,8 @@ export function localeToCurrencySymbol(locale: string) {
|
|
|
472
509
|
maximumFractionDigits: 0,
|
|
473
510
|
}).format(0);
|
|
474
511
|
|
|
475
|
-
// Remove numeric and non-breaking space characters to extract the currency
|
|
512
|
+
// Remove numeric and non-breaking space characters to extract the currency
|
|
513
|
+
// symbol
|
|
476
514
|
const { symbol } = separateCurrencyStrParts(formatted);
|
|
477
515
|
return symbol;
|
|
478
516
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* From https://github.com/tadeegan/locale-currency. For now only USD conversion from
|
|
2
|
-
|
|
2
|
+
* BTC is supported by sparkcore, strip additional currency codes from the
|
|
3
|
+
* bundle:
|
|
4
|
+
*/
|
|
3
5
|
export const countryCodesToCurrencyCodes = {
|
|
4
6
|
AD: "EUR",
|
|
5
7
|
// AE: "AED",
|
package/src/utils/pollUntil.ts
CHANGED
|
@@ -5,50 +5,51 @@ function getDefaultMaxPollsError() {
|
|
|
5
5
|
return new Error("pollUntil: Max polls reached");
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
type GetValueResult<T> = {
|
|
9
|
+
stopPolling: boolean;
|
|
10
|
+
value: null | T;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export async function pollUntil<D extends () => Promise<unknown>, T>(
|
|
9
14
|
asyncFn: D,
|
|
10
15
|
getValue: (
|
|
11
16
|
data: Awaited<ReturnType<D>>,
|
|
12
17
|
response: { stopPolling: boolean; value: null | T },
|
|
13
|
-
) =>
|
|
14
|
-
stopPolling: boolean;
|
|
15
|
-
value: null | T;
|
|
16
|
-
},
|
|
18
|
+
) => GetValueResult<T>,
|
|
17
19
|
maxPolls = 60,
|
|
18
20
|
pollIntervalMs = 500,
|
|
19
21
|
ignoreErrors: boolean | ((e: unknown) => boolean) = false,
|
|
20
22
|
getMaxPollsError: (maxPolls: number) => Error = getDefaultMaxPollsError,
|
|
21
23
|
): Promise<T> {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
await sleep(pollIntervalMs);
|
|
24
|
+
let polls = 0;
|
|
25
|
+
let stopPolling = false;
|
|
26
|
+
let result: GetValueResult<T> = {
|
|
27
|
+
stopPolling: false,
|
|
28
|
+
value: null,
|
|
29
|
+
};
|
|
30
|
+
while (!stopPolling) {
|
|
31
|
+
polls += 1;
|
|
32
|
+
if (polls > maxPolls) {
|
|
33
|
+
stopPolling = true;
|
|
34
|
+
const maxPollsError = getMaxPollsError(maxPolls);
|
|
35
|
+
throw maxPollsError;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const asyncResult = await asyncFn();
|
|
39
|
+
result = getValue(asyncResult as Awaited<ReturnType<D>>, {
|
|
40
|
+
stopPolling: false,
|
|
41
|
+
value: null,
|
|
42
|
+
});
|
|
43
|
+
if (result.stopPolling) {
|
|
44
|
+
stopPolling = true;
|
|
45
|
+
}
|
|
46
|
+
} catch (e) {
|
|
47
|
+
if (!ignoreErrors || (isFunction(ignoreErrors) && !ignoreErrors(e))) {
|
|
48
|
+
stopPolling = true;
|
|
49
|
+
throw e;
|
|
51
50
|
}
|
|
52
|
-
}
|
|
53
|
-
|
|
51
|
+
}
|
|
52
|
+
await sleep(pollIntervalMs);
|
|
53
|
+
}
|
|
54
|
+
return result.value as T;
|
|
54
55
|
}
|
package/src/utils/types.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type Maybe<T> = T | null | undefined;
|
|
|
4
4
|
|
|
5
5
|
export type ExpandRecursively<T> = T extends object
|
|
6
6
|
? T extends infer O
|
|
7
|
-
? { [K in keyof O]: ExpandRecursively<O[K]> }
|
|
7
|
+
? { [K in keyof O]: ExpandRecursively<O[K]> }
|
|
8
8
|
: never
|
|
9
9
|
: T;
|
|
10
10
|
|
|
@@ -21,3 +21,9 @@ export const isType =
|
|
|
21
21
|
): node is Extract<N, { __typename: T }> => {
|
|
22
22
|
return node?.__typename === typename;
|
|
23
23
|
};
|
|
24
|
+
|
|
25
|
+
export type DeepPartial<T> = T extends object
|
|
26
|
+
? {
|
|
27
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
28
|
+
}
|
|
29
|
+
: T;
|