@lightsparkdev/core 0.1.3
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/.prettierrc +1 -0
- package/.turbo/turbo-build.log +14 -0
- package/CHANGELOG.md +19 -0
- package/LICENSE +201 -0
- package/README.md +11 -0
- package/dist/index.cjs +663 -0
- package/dist/index.d.ts +152 -0
- package/dist/index.js +602 -0
- package/package.json +63 -0
- package/src/LightsparkException.ts +16 -0
- package/src/ServerEnvironment.ts +17 -0
- package/src/auth/AuthProvider.ts +7 -0
- package/src/auth/LightsparkAuthException.ts +11 -0
- package/src/auth/StubAuthProvider.ts +16 -0
- package/src/auth/index.ts +5 -0
- package/src/crypto/LightsparkSigningException.ts +11 -0
- package/src/crypto/NodeKeyCache.ts +46 -0
- package/src/crypto/crypto.ts +258 -0
- package/src/crypto/index.ts +5 -0
- package/src/index.ts +11 -0
- package/src/requester/Query.ts +17 -0
- package/src/requester/Requester.ts +226 -0
- package/src/requester/index.ts +4 -0
- package/src/utils/base64.ts +15 -0
- package/src/utils/currency.ts +119 -0
- package/src/utils/environment.ts +7 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/types.ts +23 -0
- package/tsconfig.json +35 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
// src/LightsparkException.ts
|
|
2
|
+
var LightsparkException = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
message;
|
|
5
|
+
extraInfo;
|
|
6
|
+
constructor(code, message, extraInfo) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.message = message;
|
|
10
|
+
this.extraInfo = extraInfo;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var LightsparkException_default = LightsparkException;
|
|
14
|
+
|
|
15
|
+
// src/auth/LightsparkAuthException.ts
|
|
16
|
+
var LightsparkAuthException = class extends LightsparkException_default {
|
|
17
|
+
constructor(message, extraInfo) {
|
|
18
|
+
super("AuthException", message, extraInfo);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var LightsparkAuthException_default = LightsparkAuthException;
|
|
22
|
+
|
|
23
|
+
// src/auth/StubAuthProvider.ts
|
|
24
|
+
var StubAuthProvider = class {
|
|
25
|
+
async addAuthHeaders(headers) {
|
|
26
|
+
return headers;
|
|
27
|
+
}
|
|
28
|
+
async isAuthorized() {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
addWsConnectionParams(params) {
|
|
32
|
+
return params;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/utils/base64.ts
|
|
37
|
+
var b64decode = (encoded) => {
|
|
38
|
+
return Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0));
|
|
39
|
+
};
|
|
40
|
+
var urlsafe_b64decode = (encoded) => {
|
|
41
|
+
return b64decode(encoded.replace(/_/g, "/").replace(/-/g, "+"));
|
|
42
|
+
};
|
|
43
|
+
var b64encode = (data) => {
|
|
44
|
+
return btoa(
|
|
45
|
+
String.fromCharCode.apply(null, Array.from(new Uint8Array(data)))
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/crypto/LightsparkSigningException.ts
|
|
50
|
+
var LightsparkSigningException = class extends LightsparkException_default {
|
|
51
|
+
constructor(message, extraInfo) {
|
|
52
|
+
super("SigningException", message, extraInfo);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var LightsparkSigningException_default = LightsparkSigningException;
|
|
56
|
+
|
|
57
|
+
// src/crypto/crypto.ts
|
|
58
|
+
var ITERATIONS = 5e5;
|
|
59
|
+
function getCrypto() {
|
|
60
|
+
let cryptoImplPromise;
|
|
61
|
+
if (typeof crypto !== "undefined") {
|
|
62
|
+
cryptoImplPromise = Promise.resolve(crypto);
|
|
63
|
+
} else {
|
|
64
|
+
cryptoImplPromise = import("crypto").then((nodeCrypto) => {
|
|
65
|
+
return nodeCrypto;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return cryptoImplPromise;
|
|
69
|
+
}
|
|
70
|
+
var getRandomValues = async (arr) => {
|
|
71
|
+
if (typeof crypto !== "undefined") {
|
|
72
|
+
return crypto.getRandomValues(arr);
|
|
73
|
+
} else {
|
|
74
|
+
const cryptoImpl2 = await getCrypto();
|
|
75
|
+
return cryptoImpl2.getRandomValues(arr);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var getRandomValues32 = async (arr) => {
|
|
79
|
+
if (typeof crypto !== "undefined") {
|
|
80
|
+
return crypto.getRandomValues(arr);
|
|
81
|
+
} else {
|
|
82
|
+
const cryptoImpl2 = await getCrypto();
|
|
83
|
+
return cryptoImpl2.getRandomValues(arr);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var deriveKey = async (password, salt, iterations, algorithm, bit_len) => {
|
|
87
|
+
const enc = new TextEncoder();
|
|
88
|
+
const cryptoImpl2 = await getCrypto();
|
|
89
|
+
const password_key = await cryptoImpl2.subtle.importKey(
|
|
90
|
+
"raw",
|
|
91
|
+
enc.encode(password),
|
|
92
|
+
"PBKDF2",
|
|
93
|
+
false,
|
|
94
|
+
["deriveBits", "deriveKey"]
|
|
95
|
+
);
|
|
96
|
+
const derived = await cryptoImpl2.subtle.deriveBits(
|
|
97
|
+
{
|
|
98
|
+
name: "PBKDF2",
|
|
99
|
+
salt,
|
|
100
|
+
iterations,
|
|
101
|
+
hash: "SHA-256"
|
|
102
|
+
},
|
|
103
|
+
password_key,
|
|
104
|
+
bit_len
|
|
105
|
+
);
|
|
106
|
+
const key = await cryptoImpl2.subtle.importKey(
|
|
107
|
+
"raw",
|
|
108
|
+
derived.slice(0, 32),
|
|
109
|
+
{ name: algorithm, length: 256 },
|
|
110
|
+
false,
|
|
111
|
+
["encrypt", "decrypt"]
|
|
112
|
+
);
|
|
113
|
+
const iv = derived.slice(32);
|
|
114
|
+
return [key, iv];
|
|
115
|
+
};
|
|
116
|
+
var encrypt = async (plaintext, password, salt) => {
|
|
117
|
+
if (!salt) {
|
|
118
|
+
salt = new Uint8Array(16);
|
|
119
|
+
getRandomValues(salt);
|
|
120
|
+
}
|
|
121
|
+
const [key, iv] = await deriveKey(password, salt, ITERATIONS, "AES-GCM", 352);
|
|
122
|
+
const cryptoImpl2 = await getCrypto();
|
|
123
|
+
const encrypted = new Uint8Array(
|
|
124
|
+
await cryptoImpl2.subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext)
|
|
125
|
+
);
|
|
126
|
+
const output = new Uint8Array(salt.byteLength + encrypted.byteLength);
|
|
127
|
+
output.set(salt);
|
|
128
|
+
output.set(encrypted, salt.byteLength);
|
|
129
|
+
const header = {
|
|
130
|
+
v: 4,
|
|
131
|
+
i: ITERATIONS
|
|
132
|
+
};
|
|
133
|
+
return [JSON.stringify(header), b64encode(output)];
|
|
134
|
+
};
|
|
135
|
+
var decrypt = async (header_json, ciphertext, password) => {
|
|
136
|
+
var decoded = b64decode(ciphertext);
|
|
137
|
+
var header;
|
|
138
|
+
if (header_json === "AES_256_CBC_PBKDF2_5000_SHA256") {
|
|
139
|
+
header = {
|
|
140
|
+
v: 0,
|
|
141
|
+
i: 5e3
|
|
142
|
+
};
|
|
143
|
+
decoded = decoded.slice(8);
|
|
144
|
+
} else {
|
|
145
|
+
header = JSON.parse(header_json);
|
|
146
|
+
}
|
|
147
|
+
if (header.v < 0 || header.v > 4) {
|
|
148
|
+
throw new LightsparkException_default(
|
|
149
|
+
"DecryptionError",
|
|
150
|
+
"Unknown version ".concat(header.v)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const cryptoImpl2 = await getCrypto();
|
|
154
|
+
const algorithm = header.v < 2 ? "AES-CBC" : "AES-GCM";
|
|
155
|
+
const bit_len = header.v < 4 ? 384 : 352;
|
|
156
|
+
const salt_len = header.v < 4 ? 8 : 16;
|
|
157
|
+
if (header.lsv === 2 || header.v === 3) {
|
|
158
|
+
const salt = decoded.slice(decoded.length - 8, decoded.length);
|
|
159
|
+
const nonce = decoded.slice(0, 12);
|
|
160
|
+
const cipherText = decoded.slice(12, decoded.length - 8);
|
|
161
|
+
const [key, _iv] = await deriveKey(
|
|
162
|
+
password,
|
|
163
|
+
salt,
|
|
164
|
+
header.i,
|
|
165
|
+
algorithm,
|
|
166
|
+
256
|
|
167
|
+
);
|
|
168
|
+
return await cryptoImpl2.subtle.decrypt(
|
|
169
|
+
{ name: algorithm, iv: nonce.buffer },
|
|
170
|
+
key,
|
|
171
|
+
cipherText
|
|
172
|
+
);
|
|
173
|
+
} else {
|
|
174
|
+
const salt = decoded.slice(0, salt_len);
|
|
175
|
+
const encrypted = decoded.slice(salt_len);
|
|
176
|
+
const [key, iv] = await deriveKey(
|
|
177
|
+
password,
|
|
178
|
+
salt,
|
|
179
|
+
header.i,
|
|
180
|
+
algorithm,
|
|
181
|
+
bit_len
|
|
182
|
+
);
|
|
183
|
+
return await cryptoImpl2.subtle.decrypt(
|
|
184
|
+
{ name: algorithm, iv },
|
|
185
|
+
key,
|
|
186
|
+
encrypted
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
async function decryptSecretWithNodePassword(cipher, encryptedSecret, nodePassword) {
|
|
191
|
+
let decryptedValue = null;
|
|
192
|
+
try {
|
|
193
|
+
decryptedValue = await decrypt(cipher, encryptedSecret, nodePassword);
|
|
194
|
+
} catch (ex) {
|
|
195
|
+
console.error(ex);
|
|
196
|
+
}
|
|
197
|
+
return decryptedValue;
|
|
198
|
+
}
|
|
199
|
+
function decode(arrBuff) {
|
|
200
|
+
const dec = new TextDecoder();
|
|
201
|
+
return dec.decode(arrBuff);
|
|
202
|
+
}
|
|
203
|
+
var generateSigningKeyPair = async () => {
|
|
204
|
+
const cryptoImpl2 = await getCrypto();
|
|
205
|
+
return await cryptoImpl2.subtle.generateKey(
|
|
206
|
+
/*algorithm:*/
|
|
207
|
+
{
|
|
208
|
+
name: "RSA-PSS",
|
|
209
|
+
modulusLength: 4096,
|
|
210
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
211
|
+
hash: "SHA-256"
|
|
212
|
+
},
|
|
213
|
+
/*extractable*/
|
|
214
|
+
true,
|
|
215
|
+
/*keyUsages*/
|
|
216
|
+
["sign", "verify"]
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
var serializeSigningKey = async (key, format) => {
|
|
220
|
+
const cryptoImpl2 = await getCrypto();
|
|
221
|
+
return await cryptoImpl2.subtle.exportKey(
|
|
222
|
+
/*format*/
|
|
223
|
+
format,
|
|
224
|
+
/*key*/
|
|
225
|
+
key
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
var encryptWithNodeKey = async (key, data) => {
|
|
229
|
+
const enc = new TextEncoder();
|
|
230
|
+
const encoded = enc.encode(data);
|
|
231
|
+
const encrypted = await cryptoImpl.subtle.encrypt(
|
|
232
|
+
/*algorithm:*/
|
|
233
|
+
{
|
|
234
|
+
name: "RSA-OAEP"
|
|
235
|
+
},
|
|
236
|
+
/*key*/
|
|
237
|
+
key,
|
|
238
|
+
/*data*/
|
|
239
|
+
encoded
|
|
240
|
+
);
|
|
241
|
+
return b64encode(encrypted);
|
|
242
|
+
};
|
|
243
|
+
var loadNodeEncryptionKey = async (rawPublicKey) => {
|
|
244
|
+
const encoded = b64decode(rawPublicKey);
|
|
245
|
+
const cryptoImpl2 = await getCrypto();
|
|
246
|
+
return await cryptoImpl2.subtle.importKey(
|
|
247
|
+
/*format*/
|
|
248
|
+
"spki",
|
|
249
|
+
/*keyData*/
|
|
250
|
+
encoded,
|
|
251
|
+
/*algorithm:*/
|
|
252
|
+
{
|
|
253
|
+
name: "RSA-OAEP",
|
|
254
|
+
hash: "SHA-256"
|
|
255
|
+
},
|
|
256
|
+
/*extractable*/
|
|
257
|
+
true,
|
|
258
|
+
/*keyUsages*/
|
|
259
|
+
["encrypt"]
|
|
260
|
+
);
|
|
261
|
+
};
|
|
262
|
+
var getNonce = async () => {
|
|
263
|
+
const nonceSt = await getRandomValues32(new Uint32Array(1));
|
|
264
|
+
return Number(nonceSt);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// src/crypto/NodeKeyCache.ts
|
|
268
|
+
import autoBind from "auto-bind";
|
|
269
|
+
var NodeKeyCache = class {
|
|
270
|
+
idToKey;
|
|
271
|
+
constructor() {
|
|
272
|
+
this.idToKey = /* @__PURE__ */ new Map();
|
|
273
|
+
autoBind(this);
|
|
274
|
+
}
|
|
275
|
+
async loadKey(id, rawKey) {
|
|
276
|
+
const decoded = b64decode(rawKey);
|
|
277
|
+
try {
|
|
278
|
+
const cryptoImpl2 = await getCrypto();
|
|
279
|
+
const key = await cryptoImpl2.subtle.importKey(
|
|
280
|
+
"pkcs8",
|
|
281
|
+
decoded,
|
|
282
|
+
{
|
|
283
|
+
name: "RSA-PSS",
|
|
284
|
+
hash: "SHA-256"
|
|
285
|
+
},
|
|
286
|
+
true,
|
|
287
|
+
["sign"]
|
|
288
|
+
);
|
|
289
|
+
this.idToKey.set(id, key);
|
|
290
|
+
return key;
|
|
291
|
+
} catch (e) {
|
|
292
|
+
console.log("Error importing key: ", e);
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
getKey(id) {
|
|
297
|
+
return this.idToKey.get(id);
|
|
298
|
+
}
|
|
299
|
+
hasKey(id) {
|
|
300
|
+
return this.idToKey.has(id);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
var NodeKeyCache_default = NodeKeyCache;
|
|
304
|
+
|
|
305
|
+
// src/requester/Requester.ts
|
|
306
|
+
import autoBind2 from "auto-bind";
|
|
307
|
+
import dayjs from "dayjs";
|
|
308
|
+
import utc from "dayjs/plugin/utc.js";
|
|
309
|
+
import { createClient } from "graphql-ws";
|
|
310
|
+
import NodeWebSocket from "ws";
|
|
311
|
+
import { Observable } from "zen-observable-ts";
|
|
312
|
+
|
|
313
|
+
// src/utils/environment.ts
|
|
314
|
+
var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
315
|
+
var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
316
|
+
|
|
317
|
+
// src/requester/Requester.ts
|
|
318
|
+
var DEFAULT_BASE_URL = "api.lightspark.com";
|
|
319
|
+
var LIGHTSPARK_BETA_HEADER_KEY = "X-Lightspark-Beta";
|
|
320
|
+
var LIGHTSPARK_BETA_HEADER_VALUE = "z2h0BBYxTA83cjW7fi8QwWtBPCzkQKiemcuhKY08LOo";
|
|
321
|
+
dayjs.extend(utc);
|
|
322
|
+
var Requester = class {
|
|
323
|
+
constructor(nodeKeyCache, schemaEndpoint, authProvider = new StubAuthProvider(), baseUrl = DEFAULT_BASE_URL) {
|
|
324
|
+
this.nodeKeyCache = nodeKeyCache;
|
|
325
|
+
this.schemaEndpoint = schemaEndpoint;
|
|
326
|
+
this.authProvider = authProvider;
|
|
327
|
+
this.baseUrl = baseUrl;
|
|
328
|
+
let websocketImpl;
|
|
329
|
+
if (typeof WebSocket === "undefined" && typeof window === "undefined") {
|
|
330
|
+
websocketImpl = NodeWebSocket;
|
|
331
|
+
}
|
|
332
|
+
this.wsClient = createClient({
|
|
333
|
+
url: `wss://${this.baseUrl}/${this.schemaEndpoint}`,
|
|
334
|
+
connectionParams: authProvider.addWsConnectionParams({}),
|
|
335
|
+
webSocketImpl: websocketImpl
|
|
336
|
+
});
|
|
337
|
+
autoBind2(this);
|
|
338
|
+
}
|
|
339
|
+
wsClient;
|
|
340
|
+
async executeQuery(query) {
|
|
341
|
+
const data = await this.makeRawRequest(
|
|
342
|
+
query.queryPayload,
|
|
343
|
+
query.variables || {},
|
|
344
|
+
query.signingNodeId
|
|
345
|
+
);
|
|
346
|
+
return query.constructObject(data);
|
|
347
|
+
}
|
|
348
|
+
subscribe(queryPayload, variables = {}) {
|
|
349
|
+
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
350
|
+
const operationMatch = queryPayload.match(operationNameRegex);
|
|
351
|
+
if (!operationMatch || operationMatch.length < 3) {
|
|
352
|
+
throw new LightsparkException_default("InvalidQuery", "Invalid query payload");
|
|
353
|
+
}
|
|
354
|
+
const operationType = operationMatch[1];
|
|
355
|
+
if (operationType == "mutation") {
|
|
356
|
+
throw new LightsparkException_default(
|
|
357
|
+
"InvalidQuery",
|
|
358
|
+
"Mutation queries should call makeRawRequest instead"
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
for (const key in variables) {
|
|
362
|
+
if (variables[key] === void 0) {
|
|
363
|
+
variables[key] = null;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const operation = operationMatch[2];
|
|
367
|
+
let bodyData = {
|
|
368
|
+
query: queryPayload,
|
|
369
|
+
variables,
|
|
370
|
+
operationName: operation
|
|
371
|
+
};
|
|
372
|
+
return new Observable(
|
|
373
|
+
(observer) => this.wsClient.subscribe(bodyData, {
|
|
374
|
+
next: (data) => observer.next(data),
|
|
375
|
+
error: (err) => observer.error(err),
|
|
376
|
+
complete: () => observer.complete()
|
|
377
|
+
})
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
async makeRawRequest(queryPayload, variables = {}, signingNodeId = void 0) {
|
|
381
|
+
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
382
|
+
const operationMatch = queryPayload.match(operationNameRegex);
|
|
383
|
+
if (!operationMatch || operationMatch.length < 3) {
|
|
384
|
+
throw new LightsparkException_default("InvalidQuery", "Invalid query payload");
|
|
385
|
+
}
|
|
386
|
+
const operationType = operationMatch[1];
|
|
387
|
+
if (operationType == "subscription") {
|
|
388
|
+
throw new LightsparkException_default(
|
|
389
|
+
"InvalidQuery",
|
|
390
|
+
"Subscription queries should call subscribe instead"
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
for (const key in variables) {
|
|
394
|
+
if (variables[key] === void 0) {
|
|
395
|
+
variables[key] = null;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const operation = operationMatch[2];
|
|
399
|
+
let bodyData = {
|
|
400
|
+
query: queryPayload,
|
|
401
|
+
variables,
|
|
402
|
+
operationName: operation
|
|
403
|
+
};
|
|
404
|
+
const browserUserAgent = typeof navigator !== "undefined" ? navigator.userAgent : "";
|
|
405
|
+
const sdkUserAgent = this.getSdkUserAgent();
|
|
406
|
+
const headers = await this.authProvider.addAuthHeaders({
|
|
407
|
+
"Content-Type": "application/json",
|
|
408
|
+
[LIGHTSPARK_BETA_HEADER_KEY]: LIGHTSPARK_BETA_HEADER_VALUE,
|
|
409
|
+
"X-Lightspark-SDK": sdkUserAgent,
|
|
410
|
+
"User-Agent": browserUserAgent || sdkUserAgent
|
|
411
|
+
});
|
|
412
|
+
bodyData = await this.addSigningDataIfNeeded(
|
|
413
|
+
bodyData,
|
|
414
|
+
headers,
|
|
415
|
+
signingNodeId
|
|
416
|
+
);
|
|
417
|
+
const response = await fetch(
|
|
418
|
+
`https://${this.baseUrl}/${this.schemaEndpoint}`,
|
|
419
|
+
{
|
|
420
|
+
method: "POST",
|
|
421
|
+
headers,
|
|
422
|
+
body: JSON.stringify(bodyData)
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
if (!response.ok) {
|
|
426
|
+
throw new LightsparkException_default(
|
|
427
|
+
"RequestFailed",
|
|
428
|
+
`Request ${operation} failed. ${response.statusText}`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
const responseJson = await response.json();
|
|
432
|
+
const data = responseJson.data;
|
|
433
|
+
if (!data) {
|
|
434
|
+
throw new LightsparkException_default(
|
|
435
|
+
"RequestFailed",
|
|
436
|
+
`Request ${operation} failed. ${JSON.stringify(responseJson.errors)}`
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
return data;
|
|
440
|
+
}
|
|
441
|
+
getSdkUserAgent() {
|
|
442
|
+
const platform = isNode ? "NodeJS" : "Browser";
|
|
443
|
+
const platformVersion = isNode ? process.version : "";
|
|
444
|
+
const sdkVersion = "1.0.4";
|
|
445
|
+
return `lightspark-js-sdk/${sdkVersion} ${platform}/${platformVersion}`;
|
|
446
|
+
}
|
|
447
|
+
async addSigningDataIfNeeded(queryPayload, headers, signingNodeId) {
|
|
448
|
+
if (!signingNodeId) {
|
|
449
|
+
return queryPayload;
|
|
450
|
+
}
|
|
451
|
+
const query = queryPayload.query;
|
|
452
|
+
const variables = queryPayload.variables;
|
|
453
|
+
const operationName = queryPayload.operationName;
|
|
454
|
+
const nonce = await getNonce();
|
|
455
|
+
const expiration = dayjs.utc().add(1, "hour").format();
|
|
456
|
+
const payload = {
|
|
457
|
+
query,
|
|
458
|
+
variables,
|
|
459
|
+
operationName,
|
|
460
|
+
nonce,
|
|
461
|
+
expires_at: expiration
|
|
462
|
+
};
|
|
463
|
+
const key = await this.nodeKeyCache.getKey(signingNodeId);
|
|
464
|
+
if (!key) {
|
|
465
|
+
throw new LightsparkSigningException_default(
|
|
466
|
+
"Missing node of encrypted_signing_private_key"
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
const encodedPayload = new TextEncoder().encode(JSON.stringify(payload));
|
|
470
|
+
const cryptoImpl2 = await getCrypto();
|
|
471
|
+
const signedPayload = await cryptoImpl2.subtle.sign(
|
|
472
|
+
{
|
|
473
|
+
name: "RSA-PSS",
|
|
474
|
+
saltLength: 32
|
|
475
|
+
},
|
|
476
|
+
key,
|
|
477
|
+
encodedPayload
|
|
478
|
+
);
|
|
479
|
+
const encodedSignedPayload = b64encode(signedPayload);
|
|
480
|
+
headers["X-Lightspark-Signing"] = JSON.stringify({
|
|
481
|
+
v: "1",
|
|
482
|
+
signature: encodedSignedPayload
|
|
483
|
+
});
|
|
484
|
+
return payload;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
var Requester_default = Requester;
|
|
488
|
+
|
|
489
|
+
// src/ServerEnvironment.ts
|
|
490
|
+
var ServerEnvironment = /* @__PURE__ */ ((ServerEnvironment2) => {
|
|
491
|
+
ServerEnvironment2["PRODUCTION"] = "production";
|
|
492
|
+
ServerEnvironment2["DEV"] = "dev";
|
|
493
|
+
return ServerEnvironment2;
|
|
494
|
+
})(ServerEnvironment || {});
|
|
495
|
+
var apiDomainForEnvironment = (environment) => {
|
|
496
|
+
switch (environment) {
|
|
497
|
+
case "dev" /* DEV */:
|
|
498
|
+
return "api.dev.dev.sparkinfra.net";
|
|
499
|
+
case "production" /* PRODUCTION */:
|
|
500
|
+
return "api.lightspark.com";
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
var ServerEnvironment_default = ServerEnvironment;
|
|
504
|
+
|
|
505
|
+
// src/utils/currency.ts
|
|
506
|
+
var CONVERSION_MAP = {
|
|
507
|
+
["BITCOIN" /* BITCOIN */]: {
|
|
508
|
+
["BITCOIN" /* BITCOIN */]: (v) => v,
|
|
509
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: (v) => v * 1e6,
|
|
510
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: (v) => v * 1e3,
|
|
511
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: (v) => v * 1e11,
|
|
512
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: (v) => v * 1e9,
|
|
513
|
+
["SATOSHI" /* SATOSHI */]: (v) => v * 1e8
|
|
514
|
+
},
|
|
515
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: {
|
|
516
|
+
["BITCOIN" /* BITCOIN */]: (v) => Math.round(v / 1e6),
|
|
517
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: (v) => v,
|
|
518
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: (v) => Math.round(v / 1e3),
|
|
519
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: (v) => v * 1e5,
|
|
520
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: (v) => v * 1e3,
|
|
521
|
+
["SATOSHI" /* SATOSHI */]: (v) => v * 100
|
|
522
|
+
},
|
|
523
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: {
|
|
524
|
+
["BITCOIN" /* BITCOIN */]: (v) => Math.round(v / 1e3),
|
|
525
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: (v) => v * 1e3,
|
|
526
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: (v) => v,
|
|
527
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: (v) => v * 1e8,
|
|
528
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: (v) => v * 1e6,
|
|
529
|
+
["SATOSHI" /* SATOSHI */]: (v) => v * 1e5
|
|
530
|
+
},
|
|
531
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: {
|
|
532
|
+
["BITCOIN" /* BITCOIN */]: (v) => Math.round(v / 1e11),
|
|
533
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: (v) => Math.round(v / 1e5),
|
|
534
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: (v) => Math.round(v / 1e8),
|
|
535
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: (v) => v,
|
|
536
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: (v) => Math.round(v / 100),
|
|
537
|
+
["SATOSHI" /* SATOSHI */]: (v) => Math.round(v / 1e3)
|
|
538
|
+
},
|
|
539
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: {
|
|
540
|
+
["BITCOIN" /* BITCOIN */]: (v) => Math.round(v / 1e9),
|
|
541
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: (v) => Math.round(v / 1e3),
|
|
542
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: (v) => Math.round(v / 1e6),
|
|
543
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: (v) => v * 100,
|
|
544
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: (v) => v,
|
|
545
|
+
["SATOSHI" /* SATOSHI */]: (v) => Math.round(v / 10)
|
|
546
|
+
},
|
|
547
|
+
["SATOSHI" /* SATOSHI */]: {
|
|
548
|
+
["BITCOIN" /* BITCOIN */]: (v) => Math.round(v / 1e8),
|
|
549
|
+
["MICROBITCOIN" /* MICROBITCOIN */]: (v) => Math.round(v / 100),
|
|
550
|
+
["MILLIBITCOIN" /* MILLIBITCOIN */]: (v) => Math.round(v / 1e5),
|
|
551
|
+
["MILLISATOSHI" /* MILLISATOSHI */]: (v) => v * 1e3,
|
|
552
|
+
["NANOBITCOIN" /* NANOBITCOIN */]: (v) => v * 10,
|
|
553
|
+
["SATOSHI" /* SATOSHI */]: (v) => v
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
var convertCurrencyAmount = (from, toUnit) => {
|
|
557
|
+
const conversionFn = CONVERSION_MAP[from.originalUnit][toUnit];
|
|
558
|
+
if (!conversionFn) {
|
|
559
|
+
throw new LightsparkException_default(
|
|
560
|
+
"CurrencyError",
|
|
561
|
+
`Cannot convert from ${from.originalUnit} to ${toUnit}`
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
return {
|
|
565
|
+
...from,
|
|
566
|
+
preferredCurrencyUnit: toUnit,
|
|
567
|
+
preferredCurrencyValueApprox: conversionFn(from.originalValue),
|
|
568
|
+
preferredCurrencyValueRounded: conversionFn(from.originalValue)
|
|
569
|
+
};
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// src/utils/types.ts
|
|
573
|
+
var isType = (typename) => (node) => {
|
|
574
|
+
return node?.__typename === typename;
|
|
575
|
+
};
|
|
576
|
+
export {
|
|
577
|
+
LightsparkAuthException_default as LightsparkAuthException,
|
|
578
|
+
LightsparkException_default as LightsparkException,
|
|
579
|
+
LightsparkSigningException_default as LightsparkSigningException,
|
|
580
|
+
NodeKeyCache_default as NodeKeyCache,
|
|
581
|
+
Requester_default as Requester,
|
|
582
|
+
ServerEnvironment_default as ServerEnvironment,
|
|
583
|
+
StubAuthProvider,
|
|
584
|
+
apiDomainForEnvironment,
|
|
585
|
+
b64decode,
|
|
586
|
+
b64encode,
|
|
587
|
+
convertCurrencyAmount,
|
|
588
|
+
decode,
|
|
589
|
+
decrypt,
|
|
590
|
+
decryptSecretWithNodePassword,
|
|
591
|
+
encrypt,
|
|
592
|
+
encryptWithNodeKey,
|
|
593
|
+
generateSigningKeyPair,
|
|
594
|
+
getCrypto,
|
|
595
|
+
getNonce,
|
|
596
|
+
isBrowser,
|
|
597
|
+
isNode,
|
|
598
|
+
isType,
|
|
599
|
+
loadNodeEncryptionKey,
|
|
600
|
+
serializeSigningKey,
|
|
601
|
+
urlsafe_b64decode
|
|
602
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lightsparkdev/core",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Lightspark JS SDK",
|
|
5
|
+
"author": "Lightspark Inc.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"lightspark",
|
|
8
|
+
"bitcoin",
|
|
9
|
+
"lightning",
|
|
10
|
+
"payments",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/lightsparkdev/js-sdk",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/lightsparkdev/js-sdk.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/lightsparkdev/js-sdk/issues"
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"module": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=14.16"
|
|
27
|
+
},
|
|
28
|
+
"browser": {
|
|
29
|
+
"crypto": false
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
33
|
+
"dev": "yarn build -- --watch",
|
|
34
|
+
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
|
35
|
+
"lint": "npx prettier --check ./src",
|
|
36
|
+
"format": "npx prettier --write ./src",
|
|
37
|
+
"test": "tsc --noEmit --project tsconfig-test.json && jest --no-cache --runInBand --bail",
|
|
38
|
+
"type-check": "tsc --noEmit",
|
|
39
|
+
"postversion": "yarn build"
|
|
40
|
+
},
|
|
41
|
+
"license": "Apache-2.0",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@openid/appauth": "^1.3.1",
|
|
44
|
+
"auto-bind": "^5.0.1",
|
|
45
|
+
"crypto": "^1.0.1",
|
|
46
|
+
"crypto-browserify": "^3.12.0",
|
|
47
|
+
"dayjs": "^1.11.7",
|
|
48
|
+
"graphql": "^16.6.0",
|
|
49
|
+
"graphql-ws": "^5.11.3",
|
|
50
|
+
"ws": "^8.12.1",
|
|
51
|
+
"zen-observable-ts": "^1.1.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/crypto-js": "^4.1.1",
|
|
55
|
+
"@types/ws": "^8.5.4",
|
|
56
|
+
"jest": "^29.4.1",
|
|
57
|
+
"prettier": "^2.8.4",
|
|
58
|
+
"prettier-plugin-organize-imports": "^3.2.2",
|
|
59
|
+
"ts-jest": "^29.0.5",
|
|
60
|
+
"tsup": "^6.7.0",
|
|
61
|
+
"typescript": "^4.9.5"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
|
|
2
|
+
|
|
3
|
+
class LightsparkException extends Error {
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
extraInfo: any;
|
|
7
|
+
|
|
8
|
+
constructor(code: string, message: string, extraInfo?: any) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.message = message;
|
|
12
|
+
this.extraInfo = extraInfo;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default LightsparkException;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
enum ServerEnvironment {
|
|
2
|
+
PRODUCTION = "production",
|
|
3
|
+
DEV = "dev",
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const apiDomainForEnvironment = (
|
|
7
|
+
environment: ServerEnvironment
|
|
8
|
+
): string => {
|
|
9
|
+
switch (environment) {
|
|
10
|
+
case ServerEnvironment.DEV:
|
|
11
|
+
return "api.dev.dev.sparkinfra.net";
|
|
12
|
+
case ServerEnvironment.PRODUCTION:
|
|
13
|
+
return "api.lightspark.com";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default ServerEnvironment;
|