@lightsparkdev/core 1.4.3 → 1.4.5
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/README.md +0 -2
- package/dist/{chunk-36QHRQJC.js → chunk-IWYMQNIA.js} +54 -20
- package/dist/chunk-L5YREN7B.js +713 -0
- package/dist/{index-gUXiTlhb.d.cts → index-CpAae9dR.d.cts} +7 -2
- package/dist/{index-gUXiTlhb.d.ts → index-CpAae9dR.d.ts} +7 -2
- package/dist/index.cjs +2618 -2574
- package/dist/index.d.cts +8 -171
- package/dist/index.d.ts +8 -171
- package/dist/index.js +25 -679
- package/dist/react-native/index.cjs +3143 -0
- package/dist/react-native/index.d.cts +175 -0
- package/dist/react-native/index.d.ts +175 -0
- package/dist/react-native/index.js +154 -0
- package/dist/utils/index.cjs +46 -11
- package/dist/utils/index.d.cts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +3 -1
- package/package.json +15 -1
- package/src/Logger.ts +2 -1
- package/src/crypto/SigningKey.ts +4 -2
- package/src/index.ts +3 -11
- package/src/react-native/index.ts +2 -0
- package/src/requester/DefaultRequester.ts +46 -0
- package/src/requester/Requester.ts +11 -44
- package/src/requester/tests/DefaultRequester.test.ts +129 -0
- package/src/requester/tests/Requester.test.ts +23 -32
- package/src/shared.ts +10 -0
- package/src/utils/currency.ts +35 -2
- package/src/utils/environment.ts +3 -0
package/dist/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { A as AppendUnitsOptions,
|
|
1
|
+
export { A as AppendUnitsOptions, ae as ById, ap as Complete, o as CurrencyAmountArg, k as CurrencyAmountInputObj, m as CurrencyAmountObj, n as CurrencyAmountPreferenceObj, Y as CurrencyCodes, X as CurrencyLocales, j as CurrencyMap, f as CurrencyUnit, g as CurrencyUnitType, ai as DeepPartial, D as DeprecatedCurrencyAmountObj, ad as ExpandRecursively, ah as ExtractByTypename, aj as JSONLiteral, al as JSONObject, ak as JSONType, ac as Maybe, am as NN, af as OmitTypename, ao as PartialBy, aq as RequiredKeys, S as SDKCurrencyAmountType, ar as StateCode, U as UmaCurrency, l as UmaCurrencyAmount, z as abbrCurrencyUnit, b as b64decode, a as b64encode, R as bytesToHex, a2 as clamp, i as convertCurrencyAmount, h as convertCurrencyAmountValue, W as countryCodesToCurrencyCodes, c as createSha256Hash, d as defaultCurrencyCode, a1 as deleteLocalStorageItem, e as ensureArray, Q as errorToJSON, B as formatCurrencyStr, G as formatInviteAmount, w as getCurrencyAmount, V as getCurrentLocale, O as getErrorMsg, $ as getLocalStorageBoolean, _ as getLocalStorageConfigItem, T as hexToBytes, K as isBare, H as isBrowser, p as isCurrencyAmountInputObj, s as isCurrencyAmountObj, t as isCurrencyAmountPreferenceObj, y as isCurrencyMap, r as isDeprecatedCurrencyAmountObj, M as isError, P as isErrorMsg, N as isErrorWithMessage, I as isNode, a5 as isNumber, aa as isObject, L as isReactNative, ab as isRecord, v as isSDKCurrencyAmount, J as isTest, ag as isType, a9 as isUint8Array, q as isUmaCurrencyAmount, a3 as linearInterpolate, Z as localeToCurrencyCode, F as localeToCurrencySymbol, a8 as lsidToUUID, x as mapCurrencyAmount, an as notNullUndefined, a6 as pollUntil, a4 as round, E as separateCurrencyStrParts, a0 as setLocalStorageBoolean, a7 as sleep, u as urlsafe_b64decode, at as zipcodeToState, as as zipcodeToStateCode } from '../index-CpAae9dR.js';
|
package/dist/utils/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
isNode,
|
|
35
35
|
isNumber,
|
|
36
36
|
isObject,
|
|
37
|
+
isReactNative,
|
|
37
38
|
isRecord,
|
|
38
39
|
isSDKCurrencyAmount,
|
|
39
40
|
isTest,
|
|
@@ -54,7 +55,7 @@ import {
|
|
|
54
55
|
urlsafe_b64decode,
|
|
55
56
|
zipcodeToState,
|
|
56
57
|
zipcodeToStateCode
|
|
57
|
-
} from "../chunk-
|
|
58
|
+
} from "../chunk-IWYMQNIA.js";
|
|
58
59
|
export {
|
|
59
60
|
CurrencyUnit,
|
|
60
61
|
abbrCurrencyUnit,
|
|
@@ -91,6 +92,7 @@ export {
|
|
|
91
92
|
isNode,
|
|
92
93
|
isNumber,
|
|
93
94
|
isObject,
|
|
95
|
+
isReactNative,
|
|
94
96
|
isRecord,
|
|
95
97
|
isSDKCurrencyAmount,
|
|
96
98
|
isTest,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightsparkdev/core",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "Lightspark JS SDK",
|
|
5
5
|
"author": "Lightspark Inc.",
|
|
6
6
|
"keywords": [
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
|
+
"react-native": "./dist/react-native/index.js",
|
|
27
28
|
"import": "./dist/index.js",
|
|
28
29
|
"require": "./dist/index.cjs"
|
|
29
30
|
},
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"src/*",
|
|
40
41
|
"dist/*",
|
|
41
42
|
"dist/utils/*",
|
|
43
|
+
"dist/react-native/*",
|
|
42
44
|
"CHANGELOG.md"
|
|
43
45
|
],
|
|
44
46
|
"scripts": {
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
"lint:fix": "eslint --fix .",
|
|
52
54
|
"lint:watch": "esw ./src -w --ext .ts,.tsx,.js --color",
|
|
53
55
|
"lint": "eslint .",
|
|
56
|
+
"circular-deps": "madge --circular --extensions ts,tsx src",
|
|
54
57
|
"package:checks": "yarn publint && yarn attw --pack .",
|
|
55
58
|
"postversion": "yarn build",
|
|
56
59
|
"test-cmd": "node --experimental-vm-modules $(yarn bin jest) --no-cache --runInBand --bail",
|
|
@@ -81,6 +84,7 @@
|
|
|
81
84
|
"eslint-watch": "^8.0.0",
|
|
82
85
|
"jest": "^29.6.2",
|
|
83
86
|
"lodash-es": "^4.17.21",
|
|
87
|
+
"madge": "^6.1.0",
|
|
84
88
|
"prettier": "3.0.3",
|
|
85
89
|
"prettier-plugin-organize-imports": "^3.2.4",
|
|
86
90
|
"publint": "^0.3.9",
|
|
@@ -89,6 +93,16 @@
|
|
|
89
93
|
"tsup": "^8.2.4",
|
|
90
94
|
"typescript": "^5.6.2"
|
|
91
95
|
},
|
|
96
|
+
"madge": {
|
|
97
|
+
"detectiveOptions": {
|
|
98
|
+
"ts": {
|
|
99
|
+
"skipTypeImports": true
|
|
100
|
+
},
|
|
101
|
+
"tsx": {
|
|
102
|
+
"skipTypeImports": true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
92
106
|
"engines": {
|
|
93
107
|
"node": ">=18"
|
|
94
108
|
}
|
package/src/Logger.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ConfigKeys
|
|
1
|
+
import { ConfigKeys } from "./constants/index.js";
|
|
2
2
|
import { isBrowser, isTest } from "./utils/environment.js";
|
|
3
|
+
import { getLocalStorageConfigItem } from "./utils/localStorage.js";
|
|
3
4
|
|
|
4
5
|
type GetLoggingEnabled = (() => Promise<boolean> | boolean) | undefined;
|
|
5
6
|
|
package/src/crypto/SigningKey.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import secp256k1 from "secp256k1";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createSha256Hash } from "../utils/createHash.js";
|
|
3
|
+
import { hexToBytes } from "../utils/hex.js";
|
|
4
|
+
import type { CryptoInterface } from "./crypto.js";
|
|
5
|
+
import { SigningKeyType } from "./types.js";
|
|
4
6
|
|
|
5
7
|
interface Alias {
|
|
6
8
|
alias: string;
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export * from "./
|
|
6
|
-
export { default as LightsparkException } from "./LightsparkException.js";
|
|
7
|
-
export { Logger, LoggingLevel, logger } from "./Logger.js";
|
|
8
|
-
export * from "./requester/index.js";
|
|
9
|
-
export {
|
|
10
|
-
default as ServerEnvironment,
|
|
11
|
-
apiDomainForEnvironment,
|
|
12
|
-
} from "./ServerEnvironment.js";
|
|
13
|
-
export * from "./utils/index.js";
|
|
3
|
+
export { DefaultRequester as Requester } from "./requester/DefaultRequester.js";
|
|
4
|
+
export { default as Query } from "./requester/Query.js";
|
|
5
|
+
export * from "./shared.js";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type AuthProvider from "../auth/AuthProvider.js";
|
|
2
|
+
import { isBare, isNode } from "../utils/environment.js";
|
|
3
|
+
import Requester from "./Requester.js";
|
|
4
|
+
|
|
5
|
+
export class DefaultRequester extends Requester {
|
|
6
|
+
protected async initWsClient(baseUrl: string, authProvider: AuthProvider) {
|
|
7
|
+
if (!this.resolveWsClient) {
|
|
8
|
+
/* If resolveWsClient is null assume already initialized: */
|
|
9
|
+
return this.wsClient;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (isBare) {
|
|
13
|
+
/* graphql-ws library is currently not supported in Bare environment, see LIG-7942 */
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let websocketImpl;
|
|
18
|
+
if (isNode && typeof WebSocket === "undefined") {
|
|
19
|
+
const wsModule = await import("ws");
|
|
20
|
+
websocketImpl = wsModule.default;
|
|
21
|
+
}
|
|
22
|
+
let websocketProtocol = "wss";
|
|
23
|
+
if (baseUrl.startsWith("http://")) {
|
|
24
|
+
websocketProtocol = "ws";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const graphqlWsModule = await import("graphql-ws");
|
|
28
|
+
const { createClient } = graphqlWsModule;
|
|
29
|
+
|
|
30
|
+
const wsClient = createClient({
|
|
31
|
+
url: `${websocketProtocol}://${this.stripProtocol(this.baseUrl)}/${
|
|
32
|
+
this.schemaEndpoint
|
|
33
|
+
}`,
|
|
34
|
+
connectionParams: () => authProvider.addWsConnectionParams({}),
|
|
35
|
+
webSocketImpl: websocketImpl,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (this.resolveWsClient) {
|
|
39
|
+
this.resolveWsClient(wsClient);
|
|
40
|
+
this.resolveWsClient = null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return wsClient;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export default DefaultRequester;
|
|
@@ -17,7 +17,7 @@ import type { SigningKey } from "../crypto/SigningKey.js";
|
|
|
17
17
|
import LightsparkException from "../LightsparkException.js";
|
|
18
18
|
import { logger } from "../Logger.js";
|
|
19
19
|
import { b64encode } from "../utils/base64.js";
|
|
20
|
-
import {
|
|
20
|
+
import { isNode } from "../utils/environment.js";
|
|
21
21
|
|
|
22
22
|
const DEFAULT_BASE_URL = "api.lightspark.com";
|
|
23
23
|
dayjs.extend(utc);
|
|
@@ -31,14 +31,14 @@ type BodyData = {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
class Requester {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
protected wsClient: Promise<WsClient | null>;
|
|
35
|
+
protected resolveWsClient: ((value: WsClient | null) => void) | null = null;
|
|
36
36
|
constructor(
|
|
37
37
|
private readonly nodeKeyCache: NodeKeyCache,
|
|
38
|
-
|
|
38
|
+
protected readonly schemaEndpoint: string,
|
|
39
39
|
private readonly sdkUserAgent: string,
|
|
40
40
|
private readonly authProvider: AuthProvider = new StubAuthProvider(),
|
|
41
|
-
|
|
41
|
+
protected readonly baseUrl: string = DEFAULT_BASE_URL,
|
|
42
42
|
private readonly cryptoImpl: CryptoInterface = DefaultCrypto,
|
|
43
43
|
private readonly signingKey?: SigningKey,
|
|
44
44
|
private readonly fetchImpl: typeof fetch = fetch,
|
|
@@ -50,44 +50,11 @@ class Requester {
|
|
|
50
50
|
autoBind(this);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (isBare) {
|
|
60
|
-
/* graphql-ws library is currently not supported in Bare environment, see LIG-7942 */
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let websocketImpl;
|
|
65
|
-
if (isNode && typeof WebSocket === "undefined") {
|
|
66
|
-
const wsModule = await import("ws");
|
|
67
|
-
websocketImpl = wsModule.default;
|
|
68
|
-
}
|
|
69
|
-
let websocketProtocol = "wss";
|
|
70
|
-
if (baseUrl.startsWith("http://")) {
|
|
71
|
-
websocketProtocol = "ws";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const graphqlWsModule = await import("graphql-ws");
|
|
75
|
-
const { createClient } = graphqlWsModule;
|
|
76
|
-
|
|
77
|
-
const wsClient = createClient({
|
|
78
|
-
url: `${websocketProtocol}://${this.stripProtocol(this.baseUrl)}/${
|
|
79
|
-
this.schemaEndpoint
|
|
80
|
-
}`,
|
|
81
|
-
connectionParams: () => authProvider.addWsConnectionParams({}),
|
|
82
|
-
webSocketImpl: websocketImpl,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
if (this.resolveWsClient) {
|
|
86
|
-
this.resolveWsClient(wsClient);
|
|
87
|
-
this.resolveWsClient = null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return wsClient;
|
|
53
|
+
protected initWsClient(
|
|
54
|
+
baseUrl: string,
|
|
55
|
+
authProvider: AuthProvider,
|
|
56
|
+
): Promise<WsClient | null> {
|
|
57
|
+
return Promise.resolve(null);
|
|
91
58
|
}
|
|
92
59
|
|
|
93
60
|
public async executeQuery<T>(query: Query<T>): Promise<T | null> {
|
|
@@ -293,7 +260,7 @@ class Requester {
|
|
|
293
260
|
return `${this.sdkUserAgent} ${platform}/${platformVersion}`;
|
|
294
261
|
}
|
|
295
262
|
|
|
296
|
-
|
|
263
|
+
protected stripProtocol(url: string): string {
|
|
297
264
|
return url.replace(/.*?:\/\//g, "");
|
|
298
265
|
}
|
|
299
266
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { beforeEach, jest } from "@jest/globals";
|
|
2
|
+
|
|
3
|
+
import type { Client as WsClient } from "graphql-ws";
|
|
4
|
+
import type AuthProvider from "../../auth/AuthProvider.js";
|
|
5
|
+
import type { CryptoInterface } from "../../crypto/crypto.js";
|
|
6
|
+
import type NodeKeyCache from "../../crypto/NodeKeyCache.js";
|
|
7
|
+
import type { SigningKey } from "../../crypto/SigningKey.js";
|
|
8
|
+
import { SigningKeyType } from "../../crypto/types.js";
|
|
9
|
+
|
|
10
|
+
/* Mocking ESM modules (when running node with --experimental-vm-modules)
|
|
11
|
+
requires unstable_mockModule, see https://bit.ly/433nRV1 */
|
|
12
|
+
await jest.unstable_mockModule("graphql-ws", () => ({
|
|
13
|
+
__esModule: true,
|
|
14
|
+
createClient: jest.fn(),
|
|
15
|
+
}));
|
|
16
|
+
/* Since Requester uses graphql-ws we need a dynamic import after the above mock */
|
|
17
|
+
const { DefaultRequester } = await import("../DefaultRequester.js");
|
|
18
|
+
|
|
19
|
+
describe("DefaultRequester", () => {
|
|
20
|
+
const schemaEndpoint = "graphql";
|
|
21
|
+
const sdkUserAgent = "test-agent";
|
|
22
|
+
const baseUrl = "https://api.example.com";
|
|
23
|
+
|
|
24
|
+
let nodeKeyCache: NodeKeyCache;
|
|
25
|
+
let authProvider: AuthProvider;
|
|
26
|
+
let signingKey: SigningKey;
|
|
27
|
+
let cryptoImpl: CryptoInterface;
|
|
28
|
+
let fetchImpl: typeof fetch;
|
|
29
|
+
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
nodeKeyCache = {
|
|
32
|
+
getKey: jest.fn(),
|
|
33
|
+
hasKey: jest.fn(),
|
|
34
|
+
} as unknown as NodeKeyCache;
|
|
35
|
+
|
|
36
|
+
authProvider = {
|
|
37
|
+
addAuthHeaders: jest.fn(async (headers: Record<string, string>) => ({
|
|
38
|
+
...headers,
|
|
39
|
+
"X-Test": "1",
|
|
40
|
+
})),
|
|
41
|
+
isAuthorized: jest.fn(async () => true),
|
|
42
|
+
addWsConnectionParams: jest.fn(
|
|
43
|
+
async (params: Record<string, unknown>) => ({
|
|
44
|
+
...params,
|
|
45
|
+
ws: true,
|
|
46
|
+
}),
|
|
47
|
+
),
|
|
48
|
+
} satisfies AuthProvider;
|
|
49
|
+
|
|
50
|
+
signingKey = {
|
|
51
|
+
type: SigningKeyType.RSASigningKey,
|
|
52
|
+
sign: jest.fn(async (data: Uint8Array) => new Uint8Array([1, 2, 3])),
|
|
53
|
+
} satisfies SigningKey;
|
|
54
|
+
|
|
55
|
+
cryptoImpl = {
|
|
56
|
+
decryptSecretWithNodePassword: jest.fn(async () => new ArrayBuffer(0)),
|
|
57
|
+
generateSigningKeyPair: jest.fn(async () => ({
|
|
58
|
+
publicKey: "",
|
|
59
|
+
privateKey: "",
|
|
60
|
+
})),
|
|
61
|
+
serializeSigningKey: jest.fn(async () => new ArrayBuffer(0)),
|
|
62
|
+
getNonce: jest.fn(async () => 123),
|
|
63
|
+
sign: jest.fn(async () => new ArrayBuffer(0)),
|
|
64
|
+
importPrivateSigningKey: jest.fn(async () => ""),
|
|
65
|
+
} satisfies CryptoInterface;
|
|
66
|
+
|
|
67
|
+
fetchImpl = jest.fn(
|
|
68
|
+
async () =>
|
|
69
|
+
({
|
|
70
|
+
ok: true,
|
|
71
|
+
json: async () => ({ data: { foo: "bar" }, errors: undefined }),
|
|
72
|
+
statusText: "OK",
|
|
73
|
+
}) as Response,
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("subscribe", () => {
|
|
78
|
+
it("returns an Observable for a valid subscription", async () => {
|
|
79
|
+
// Mock wsClient and its subscribe method
|
|
80
|
+
const wsClient = {
|
|
81
|
+
subscribe: jest.fn(
|
|
82
|
+
(
|
|
83
|
+
_body,
|
|
84
|
+
handlers: { next?: (data: unknown) => void; complete?: () => void },
|
|
85
|
+
) => {
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
handlers.next?.({ data: { foo: "bar" } });
|
|
88
|
+
handlers.complete?.();
|
|
89
|
+
}, 10);
|
|
90
|
+
return jest.fn();
|
|
91
|
+
},
|
|
92
|
+
),
|
|
93
|
+
} as unknown as WsClient;
|
|
94
|
+
|
|
95
|
+
const { createClient } = await import("graphql-ws");
|
|
96
|
+
(createClient as jest.Mock).mockReturnValue(wsClient);
|
|
97
|
+
|
|
98
|
+
const requester = new DefaultRequester(
|
|
99
|
+
nodeKeyCache,
|
|
100
|
+
schemaEndpoint,
|
|
101
|
+
sdkUserAgent,
|
|
102
|
+
authProvider,
|
|
103
|
+
baseUrl,
|
|
104
|
+
cryptoImpl,
|
|
105
|
+
signingKey,
|
|
106
|
+
fetchImpl,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const observable = requester.subscribe<{ foo: string }>(
|
|
110
|
+
"subscription TestSub { foo }",
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const results: { foo: string }[] = [];
|
|
114
|
+
await new Promise<void>((resolve) => {
|
|
115
|
+
observable.subscribe({
|
|
116
|
+
next: (data: { data: { foo: string } }) => {
|
|
117
|
+
results.push(data.data);
|
|
118
|
+
},
|
|
119
|
+
complete: () => {
|
|
120
|
+
expect(results).toEqual([{ foo: "bar" }]);
|
|
121
|
+
resolve();
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(wsClient.subscribe).toHaveBeenCalled();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { beforeEach, jest } from "@jest/globals";
|
|
2
2
|
|
|
3
|
-
import type { Client as WsClient } from "graphql-ws";
|
|
4
3
|
import type AuthProvider from "../../auth/AuthProvider.js";
|
|
5
4
|
import type { CryptoInterface } from "../../crypto/crypto.js";
|
|
6
5
|
import type NodeKeyCache from "../../crypto/NodeKeyCache.js";
|
|
@@ -16,7 +15,7 @@ await jest.unstable_mockModule("graphql-ws", () => ({
|
|
|
16
15
|
createClient: jest.fn(),
|
|
17
16
|
}));
|
|
18
17
|
/* Since Requester uses graphql-ws we need a dynamic import after the above mock */
|
|
19
|
-
const { Requester } = await import("../
|
|
18
|
+
const { default: Requester } = await import("../Requester.js");
|
|
20
19
|
|
|
21
20
|
describe("Requester", () => {
|
|
22
21
|
const schemaEndpoint = "graphql";
|
|
@@ -257,26 +256,7 @@ describe("Requester", () => {
|
|
|
257
256
|
expect(() => requester.subscribe("invalid")).toThrow(LightsparkException);
|
|
258
257
|
});
|
|
259
258
|
|
|
260
|
-
it("
|
|
261
|
-
// Mock wsClient and its subscribe method
|
|
262
|
-
const wsClient = {
|
|
263
|
-
subscribe: jest.fn(
|
|
264
|
-
(
|
|
265
|
-
_body,
|
|
266
|
-
handlers: { next?: (data: unknown) => void; complete?: () => void },
|
|
267
|
-
) => {
|
|
268
|
-
setTimeout(() => {
|
|
269
|
-
handlers.next?.({ data: { foo: "bar" } });
|
|
270
|
-
handlers.complete?.();
|
|
271
|
-
}, 10);
|
|
272
|
-
return jest.fn();
|
|
273
|
-
},
|
|
274
|
-
),
|
|
275
|
-
} as unknown as WsClient;
|
|
276
|
-
|
|
277
|
-
const { createClient } = await import("graphql-ws");
|
|
278
|
-
(createClient as jest.Mock).mockReturnValue(wsClient);
|
|
279
|
-
|
|
259
|
+
it("emits error when wsClient is not initialized", async () => {
|
|
280
260
|
const requester = new Requester(
|
|
281
261
|
nodeKeyCache,
|
|
282
262
|
schemaEndpoint,
|
|
@@ -287,25 +267,36 @@ describe("Requester", () => {
|
|
|
287
267
|
signingKey,
|
|
288
268
|
fetchImpl,
|
|
289
269
|
);
|
|
270
|
+
// Resolve internal wsClient promise to null so the observable emits an error.
|
|
271
|
+
(
|
|
272
|
+
requester as unknown as {
|
|
273
|
+
resolveWsClient: ((v: unknown) => void) | null;
|
|
274
|
+
}
|
|
275
|
+
).resolveWsClient?.(null);
|
|
290
276
|
|
|
291
|
-
const observable = requester.subscribe
|
|
292
|
-
"subscription TestSub { foo }",
|
|
293
|
-
);
|
|
277
|
+
const observable = requester.subscribe("subscription TestSub { foo }");
|
|
294
278
|
|
|
295
|
-
const results: { foo: string }[] = [];
|
|
296
279
|
await new Promise<void>((resolve) => {
|
|
297
280
|
observable.subscribe({
|
|
298
|
-
next: (
|
|
299
|
-
|
|
281
|
+
next: () => {
|
|
282
|
+
throw new Error(
|
|
283
|
+
"Should not emit next when wsClient is uninitialized",
|
|
284
|
+
);
|
|
300
285
|
},
|
|
301
|
-
|
|
302
|
-
expect(
|
|
286
|
+
error: (err) => {
|
|
287
|
+
expect(err).toBeInstanceOf(LightsparkException);
|
|
288
|
+
expect(String((err as Error).message)).toMatch(
|
|
289
|
+
/WebSocket client is not initialized/,
|
|
290
|
+
);
|
|
303
291
|
resolve();
|
|
304
292
|
},
|
|
293
|
+
complete: () => {
|
|
294
|
+
throw new Error(
|
|
295
|
+
"Should not complete when wsClient is uninitialized",
|
|
296
|
+
);
|
|
297
|
+
},
|
|
305
298
|
});
|
|
306
299
|
});
|
|
307
|
-
|
|
308
|
-
expect(wsClient.subscribe).toHaveBeenCalled();
|
|
309
300
|
});
|
|
310
301
|
});
|
|
311
302
|
|
package/src/shared.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./auth/index.js";
|
|
2
|
+
export * from "./constants/index.js";
|
|
3
|
+
export * from "./crypto/index.js";
|
|
4
|
+
export { default as LightsparkException } from "./LightsparkException.js";
|
|
5
|
+
export { Logger, LoggingLevel, logger } from "./Logger.js";
|
|
6
|
+
export {
|
|
7
|
+
default as ServerEnvironment,
|
|
8
|
+
apiDomainForEnvironment,
|
|
9
|
+
} from "./ServerEnvironment.js";
|
|
10
|
+
export * from "./utils/index.js";
|
package/src/utils/currency.ts
CHANGED
|
@@ -24,6 +24,7 @@ export const CurrencyUnit = {
|
|
|
24
24
|
EUR: "EUR",
|
|
25
25
|
GBP: "GBP",
|
|
26
26
|
INR: "INR",
|
|
27
|
+
USDT: "USDT",
|
|
27
28
|
|
|
28
29
|
Bitcoin: "BITCOIN",
|
|
29
30
|
Microbitcoin: "MICROBITCOIN",
|
|
@@ -36,6 +37,7 @@ export const CurrencyUnit = {
|
|
|
36
37
|
Php: "PHP",
|
|
37
38
|
Gbp: "GBP",
|
|
38
39
|
Inr: "INR",
|
|
40
|
+
Usdt: "USDT",
|
|
39
41
|
} as const;
|
|
40
42
|
|
|
41
43
|
export type CurrencyUnitType = (typeof CurrencyUnit)[keyof typeof CurrencyUnit];
|
|
@@ -67,6 +69,7 @@ const standardUnitConversionObj = {
|
|
|
67
69
|
[CurrencyUnit.EUR]: (v: number) => v,
|
|
68
70
|
[CurrencyUnit.GBP]: (v: number) => v,
|
|
69
71
|
[CurrencyUnit.INR]: (v: number) => v,
|
|
72
|
+
[CurrencyUnit.USDT]: (v: number) => v,
|
|
70
73
|
};
|
|
71
74
|
|
|
72
75
|
/* Round without decimals since we're returning cents: */
|
|
@@ -97,6 +100,7 @@ const CONVERSION_MAP = {
|
|
|
97
100
|
[CurrencyUnit.EUR]: toBitcoinConversion,
|
|
98
101
|
[CurrencyUnit.GBP]: toBitcoinConversion,
|
|
99
102
|
[CurrencyUnit.INR]: toBitcoinConversion,
|
|
103
|
+
[CurrencyUnit.USDT]: toBitcoinConversion,
|
|
100
104
|
},
|
|
101
105
|
[CurrencyUnit.MICROBITCOIN]: {
|
|
102
106
|
[CurrencyUnit.BITCOIN]: (v: number) => v / 1_000_000,
|
|
@@ -111,6 +115,7 @@ const CONVERSION_MAP = {
|
|
|
111
115
|
[CurrencyUnit.EUR]: toMicrobitcoinConversion,
|
|
112
116
|
[CurrencyUnit.GBP]: toMicrobitcoinConversion,
|
|
113
117
|
[CurrencyUnit.INR]: toMicrobitcoinConversion,
|
|
118
|
+
[CurrencyUnit.USDT]: toMicrobitcoinConversion,
|
|
114
119
|
},
|
|
115
120
|
[CurrencyUnit.MILLIBITCOIN]: {
|
|
116
121
|
[CurrencyUnit.BITCOIN]: (v: number) => v / 1_000,
|
|
@@ -125,6 +130,7 @@ const CONVERSION_MAP = {
|
|
|
125
130
|
[CurrencyUnit.EUR]: toMillibitcoinConversion,
|
|
126
131
|
[CurrencyUnit.GBP]: toMillibitcoinConversion,
|
|
127
132
|
[CurrencyUnit.INR]: toMillibitcoinConversion,
|
|
133
|
+
[CurrencyUnit.USDT]: toMillibitcoinConversion,
|
|
128
134
|
},
|
|
129
135
|
[CurrencyUnit.MILLISATOSHI]: {
|
|
130
136
|
[CurrencyUnit.BITCOIN]: (v: number) => v / 100_000_000_000,
|
|
@@ -139,6 +145,7 @@ const CONVERSION_MAP = {
|
|
|
139
145
|
[CurrencyUnit.EUR]: toMillisatoshiConversion,
|
|
140
146
|
[CurrencyUnit.GBP]: toMillisatoshiConversion,
|
|
141
147
|
[CurrencyUnit.INR]: toMillisatoshiConversion,
|
|
148
|
+
[CurrencyUnit.USDT]: toMillisatoshiConversion,
|
|
142
149
|
},
|
|
143
150
|
[CurrencyUnit.NANOBITCOIN]: {
|
|
144
151
|
[CurrencyUnit.BITCOIN]: (v: number) => v / 1_000_000_000,
|
|
@@ -153,6 +160,7 @@ const CONVERSION_MAP = {
|
|
|
153
160
|
[CurrencyUnit.EUR]: toNanobitcoinConversion,
|
|
154
161
|
[CurrencyUnit.GBP]: toNanobitcoinConversion,
|
|
155
162
|
[CurrencyUnit.INR]: toNanobitcoinConversion,
|
|
163
|
+
[CurrencyUnit.USDT]: toNanobitcoinConversion,
|
|
156
164
|
},
|
|
157
165
|
[CurrencyUnit.SATOSHI]: {
|
|
158
166
|
[CurrencyUnit.BITCOIN]: (v: number) => v / 100_000_000,
|
|
@@ -167,6 +175,7 @@ const CONVERSION_MAP = {
|
|
|
167
175
|
[CurrencyUnit.EUR]: toSatoshiConversion,
|
|
168
176
|
[CurrencyUnit.GBP]: toSatoshiConversion,
|
|
169
177
|
[CurrencyUnit.INR]: toSatoshiConversion,
|
|
178
|
+
[CurrencyUnit.USDT]: toSatoshiConversion,
|
|
170
179
|
},
|
|
171
180
|
[CurrencyUnit.USD]: standardUnitConversionObj,
|
|
172
181
|
[CurrencyUnit.MXN]: standardUnitConversionObj,
|
|
@@ -174,6 +183,7 @@ const CONVERSION_MAP = {
|
|
|
174
183
|
[CurrencyUnit.EUR]: standardUnitConversionObj,
|
|
175
184
|
[CurrencyUnit.GBP]: standardUnitConversionObj,
|
|
176
185
|
[CurrencyUnit.INR]: standardUnitConversionObj,
|
|
186
|
+
[CurrencyUnit.USDT]: standardUnitConversionObj,
|
|
177
187
|
};
|
|
178
188
|
|
|
179
189
|
export function convertCurrencyAmountValue(
|
|
@@ -241,6 +251,7 @@ export type CurrencyMap = {
|
|
|
241
251
|
[CurrencyUnit.EUR]: number;
|
|
242
252
|
[CurrencyUnit.GBP]: number;
|
|
243
253
|
[CurrencyUnit.INR]: number;
|
|
254
|
+
[CurrencyUnit.USDT]: number;
|
|
244
255
|
[CurrencyUnit.FUTURE_VALUE]: number;
|
|
245
256
|
formatted: {
|
|
246
257
|
sats: string;
|
|
@@ -258,6 +269,7 @@ export type CurrencyMap = {
|
|
|
258
269
|
[CurrencyUnit.EUR]: string;
|
|
259
270
|
[CurrencyUnit.GBP]: string;
|
|
260
271
|
[CurrencyUnit.INR]: string;
|
|
272
|
+
[CurrencyUnit.USDT]: string;
|
|
261
273
|
[CurrencyUnit.FUTURE_VALUE]: string;
|
|
262
274
|
};
|
|
263
275
|
isZero: boolean;
|
|
@@ -459,6 +471,7 @@ function convertCurrencyAmountValues(
|
|
|
459
471
|
mibtc: CurrencyUnit.MICROBITCOIN,
|
|
460
472
|
mlbtc: CurrencyUnit.MILLIBITCOIN,
|
|
461
473
|
nbtc: CurrencyUnit.NANOBITCOIN,
|
|
474
|
+
usdt: CurrencyUnit.USDT,
|
|
462
475
|
};
|
|
463
476
|
return Object.entries(namesToUnits).reduce(
|
|
464
477
|
(acc, [name, unit]) => {
|
|
@@ -505,8 +518,21 @@ export function mapCurrencyAmount(
|
|
|
505
518
|
* preferred_currency_unit on CurrencyAmount types: */
|
|
506
519
|
const conversionOverride = getPreferredConversionOverride(currencyAmountArg);
|
|
507
520
|
|
|
508
|
-
const {
|
|
509
|
-
|
|
521
|
+
const {
|
|
522
|
+
sats,
|
|
523
|
+
msats,
|
|
524
|
+
btc,
|
|
525
|
+
usd,
|
|
526
|
+
mxn,
|
|
527
|
+
php,
|
|
528
|
+
mibtc,
|
|
529
|
+
mlbtc,
|
|
530
|
+
nbtc,
|
|
531
|
+
eur,
|
|
532
|
+
gbp,
|
|
533
|
+
inr,
|
|
534
|
+
usdt,
|
|
535
|
+
} = convertCurrencyAmountValues(unit, value, unitsPerBtc, conversionOverride);
|
|
510
536
|
|
|
511
537
|
const mapWithCurrencyUnits = {
|
|
512
538
|
[CurrencyUnit.BITCOIN]: btc,
|
|
@@ -521,6 +547,7 @@ export function mapCurrencyAmount(
|
|
|
521
547
|
[CurrencyUnit.MICROBITCOIN]: mibtc,
|
|
522
548
|
[CurrencyUnit.MILLIBITCOIN]: mlbtc,
|
|
523
549
|
[CurrencyUnit.NANOBITCOIN]: nbtc,
|
|
550
|
+
[CurrencyUnit.USDT]: usdt,
|
|
524
551
|
[CurrencyUnit.FUTURE_VALUE]: NaN,
|
|
525
552
|
formatted: {
|
|
526
553
|
[CurrencyUnit.BITCOIN]: formatCurrencyStr({
|
|
@@ -571,6 +598,10 @@ export function mapCurrencyAmount(
|
|
|
571
598
|
value: inr,
|
|
572
599
|
unit: CurrencyUnit.INR,
|
|
573
600
|
}),
|
|
601
|
+
[CurrencyUnit.USDT]: formatCurrencyStr({
|
|
602
|
+
value: usdt,
|
|
603
|
+
unit: CurrencyUnit.USDT,
|
|
604
|
+
}),
|
|
574
605
|
[CurrencyUnit.FUTURE_VALUE]: "-",
|
|
575
606
|
},
|
|
576
607
|
};
|
|
@@ -651,6 +682,8 @@ export const abbrCurrencyUnit = (unit: CurrencyUnitType) => {
|
|
|
651
682
|
return "GBP";
|
|
652
683
|
case CurrencyUnit.INR:
|
|
653
684
|
return "INR";
|
|
685
|
+
case CurrencyUnit.USDT:
|
|
686
|
+
return "USDT";
|
|
654
687
|
}
|
|
655
688
|
return "Unsupported CurrencyUnit";
|
|
656
689
|
};
|
package/src/utils/environment.ts
CHANGED
|
@@ -14,3 +14,6 @@ export const isTest = isNode && process.env.NODE_ENV === "test";
|
|
|
14
14
|
|
|
15
15
|
/* https://github.com/holepunchto/which-runtime/blob/main/index.js */
|
|
16
16
|
export const isBare = typeof Bare !== "undefined";
|
|
17
|
+
|
|
18
|
+
export const isReactNative =
|
|
19
|
+
typeof navigator !== "undefined" && navigator.product === "ReactNative";
|