@lightsparkdev/core 1.4.3 → 1.4.4
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 +7 -0
- package/README.md +0 -2
- package/dist/{chunk-36QHRQJC.js → chunk-ADHQHZNM.js} +11 -9
- package/dist/chunk-VY7NND44.js +713 -0
- package/dist/{index-gUXiTlhb.d.cts → index-CFQtMxrx.d.cts} +2 -1
- package/dist/{index-gUXiTlhb.d.ts → index-CFQtMxrx.d.ts} +2 -1
- package/dist/index.cjs +2585 -2573
- 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 +3111 -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 +3 -0
- 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/environment.ts +3 -0
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LightsparkException_default,
|
|
3
|
+
b64decode,
|
|
4
|
+
b64encode,
|
|
5
|
+
createSha256Hash,
|
|
6
|
+
getLocalStorageConfigItem,
|
|
7
|
+
hexToBytes,
|
|
8
|
+
isBrowser,
|
|
9
|
+
isNode,
|
|
10
|
+
isTest
|
|
11
|
+
} from "./chunk-ADHQHZNM.js";
|
|
12
|
+
|
|
13
|
+
// src/auth/StubAuthProvider.ts
|
|
14
|
+
var StubAuthProvider = class {
|
|
15
|
+
addAuthHeaders(headers) {
|
|
16
|
+
return Promise.resolve(headers);
|
|
17
|
+
}
|
|
18
|
+
isAuthorized() {
|
|
19
|
+
return Promise.resolve(false);
|
|
20
|
+
}
|
|
21
|
+
addWsConnectionParams(params) {
|
|
22
|
+
return Promise.resolve(params);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/crypto/LightsparkSigningException.ts
|
|
27
|
+
var LightsparkSigningException = class extends LightsparkException_default {
|
|
28
|
+
constructor(message, extraInfo) {
|
|
29
|
+
super("SigningException", message, extraInfo);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var LightsparkSigningException_default = LightsparkSigningException;
|
|
33
|
+
|
|
34
|
+
// src/crypto/crypto.ts
|
|
35
|
+
var getCrypto = () => {
|
|
36
|
+
let cryptoImplPromise;
|
|
37
|
+
if (typeof crypto !== "undefined") {
|
|
38
|
+
cryptoImplPromise = Promise.resolve(crypto);
|
|
39
|
+
} else {
|
|
40
|
+
cryptoImplPromise = import("crypto").then((nodeCrypto) => {
|
|
41
|
+
let cryptoModule = nodeCrypto;
|
|
42
|
+
if (!nodeCrypto.subtle) {
|
|
43
|
+
cryptoModule = Object.assign({}, cryptoModule, {
|
|
44
|
+
subtle: nodeCrypto.webcrypto.subtle
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (!nodeCrypto.getRandomValues) {
|
|
48
|
+
cryptoModule = Object.assign({}, cryptoModule, {
|
|
49
|
+
getRandomValues: (array) => {
|
|
50
|
+
if (!array) {
|
|
51
|
+
return array;
|
|
52
|
+
}
|
|
53
|
+
const buffer = Buffer.from(array.buffer);
|
|
54
|
+
const view = new Uint8Array(buffer);
|
|
55
|
+
nodeCrypto.randomFillSync(view);
|
|
56
|
+
return array;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return cryptoModule;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return cryptoImplPromise;
|
|
64
|
+
};
|
|
65
|
+
var getRandomValues32 = async (arr) => {
|
|
66
|
+
if (typeof crypto !== "undefined") {
|
|
67
|
+
return crypto.getRandomValues(arr);
|
|
68
|
+
} else {
|
|
69
|
+
const cryptoImpl = await getCrypto();
|
|
70
|
+
return cryptoImpl.getRandomValues(arr);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var deriveKey = async (password, salt, iterations, algorithm, bit_len) => {
|
|
74
|
+
const enc = new TextEncoder();
|
|
75
|
+
const cryptoImpl = await getCrypto();
|
|
76
|
+
const password_key = await cryptoImpl.subtle.importKey(
|
|
77
|
+
"raw",
|
|
78
|
+
enc.encode(password),
|
|
79
|
+
"PBKDF2",
|
|
80
|
+
false,
|
|
81
|
+
["deriveBits", "deriveKey"]
|
|
82
|
+
);
|
|
83
|
+
const derived = await cryptoImpl.subtle.deriveBits(
|
|
84
|
+
{
|
|
85
|
+
name: "PBKDF2",
|
|
86
|
+
salt,
|
|
87
|
+
iterations,
|
|
88
|
+
hash: "SHA-256"
|
|
89
|
+
},
|
|
90
|
+
password_key,
|
|
91
|
+
bit_len
|
|
92
|
+
);
|
|
93
|
+
const key = await cryptoImpl.subtle.importKey(
|
|
94
|
+
"raw",
|
|
95
|
+
derived.slice(0, 32),
|
|
96
|
+
{ name: algorithm, length: 256 },
|
|
97
|
+
false,
|
|
98
|
+
["encrypt", "decrypt"]
|
|
99
|
+
);
|
|
100
|
+
const iv = derived.slice(32);
|
|
101
|
+
return [key, iv];
|
|
102
|
+
};
|
|
103
|
+
var decrypt = async (header_json, ciphertext, password) => {
|
|
104
|
+
let decoded = b64decode(ciphertext);
|
|
105
|
+
let header;
|
|
106
|
+
if (header_json === "AES_256_CBC_PBKDF2_5000_SHA256") {
|
|
107
|
+
header = {
|
|
108
|
+
v: 0,
|
|
109
|
+
i: 5e3
|
|
110
|
+
};
|
|
111
|
+
decoded = decoded.slice(8);
|
|
112
|
+
} else {
|
|
113
|
+
header = JSON.parse(header_json);
|
|
114
|
+
}
|
|
115
|
+
if (header.v < 0 || header.v > 4) {
|
|
116
|
+
throw new LightsparkException_default(
|
|
117
|
+
"DecryptionError",
|
|
118
|
+
`Unknown version ${header.v}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const cryptoImpl = await getCrypto();
|
|
122
|
+
const algorithm = header.v < 2 ? "AES-CBC" : "AES-GCM";
|
|
123
|
+
const bit_len = header.v < 4 ? 384 : 352;
|
|
124
|
+
const salt_len = header.v < 4 ? 8 : 16;
|
|
125
|
+
if (header.lsv === 2 || header.v === 3) {
|
|
126
|
+
const salt = decoded.slice(decoded.length - 8, decoded.length);
|
|
127
|
+
const nonce = decoded.slice(0, 12);
|
|
128
|
+
const cipherText = decoded.slice(12, decoded.length - 8);
|
|
129
|
+
const [
|
|
130
|
+
key
|
|
131
|
+
/* , _iv */
|
|
132
|
+
] = await deriveKey(
|
|
133
|
+
password,
|
|
134
|
+
salt,
|
|
135
|
+
header.i,
|
|
136
|
+
algorithm,
|
|
137
|
+
256
|
|
138
|
+
);
|
|
139
|
+
return await cryptoImpl.subtle.decrypt(
|
|
140
|
+
{ name: algorithm, iv: nonce.buffer },
|
|
141
|
+
key,
|
|
142
|
+
cipherText
|
|
143
|
+
);
|
|
144
|
+
} else {
|
|
145
|
+
const salt = decoded.slice(0, salt_len);
|
|
146
|
+
const encrypted = decoded.slice(salt_len);
|
|
147
|
+
const [key, iv] = await deriveKey(
|
|
148
|
+
password,
|
|
149
|
+
salt,
|
|
150
|
+
header.i,
|
|
151
|
+
algorithm,
|
|
152
|
+
bit_len
|
|
153
|
+
);
|
|
154
|
+
return await cryptoImpl.subtle.decrypt(
|
|
155
|
+
{ name: algorithm, iv },
|
|
156
|
+
key,
|
|
157
|
+
encrypted
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
async function decryptSecretWithNodePassword(cipher, encryptedSecret, nodePassword) {
|
|
162
|
+
let decryptedValue = null;
|
|
163
|
+
try {
|
|
164
|
+
decryptedValue = await decrypt(cipher, encryptedSecret, nodePassword);
|
|
165
|
+
} catch (ex) {
|
|
166
|
+
console.error(ex);
|
|
167
|
+
}
|
|
168
|
+
return decryptedValue;
|
|
169
|
+
}
|
|
170
|
+
var generateSigningKeyPair = async () => {
|
|
171
|
+
const cryptoImpl = await getCrypto();
|
|
172
|
+
return await cryptoImpl.subtle.generateKey(
|
|
173
|
+
/*algorithm:*/
|
|
174
|
+
{
|
|
175
|
+
name: "RSA-PSS",
|
|
176
|
+
modulusLength: 4096,
|
|
177
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
178
|
+
hash: "SHA-256"
|
|
179
|
+
},
|
|
180
|
+
/*extractable*/
|
|
181
|
+
true,
|
|
182
|
+
/*keyUsages*/
|
|
183
|
+
["sign", "verify"]
|
|
184
|
+
);
|
|
185
|
+
};
|
|
186
|
+
var serializeSigningKey = async (key, format) => {
|
|
187
|
+
const cryptoImpl = await getCrypto();
|
|
188
|
+
return await cryptoImpl.subtle.exportKey(
|
|
189
|
+
/*format*/
|
|
190
|
+
format,
|
|
191
|
+
/*key*/
|
|
192
|
+
key
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
var getNonce = async () => {
|
|
196
|
+
const nonceSt = await getRandomValues32(new Uint32Array(2));
|
|
197
|
+
const [upper, lower] = nonceSt;
|
|
198
|
+
const nonce = BigInt(upper) << 32n | BigInt(lower);
|
|
199
|
+
return Number(nonce);
|
|
200
|
+
};
|
|
201
|
+
var sign = async (keyOrAlias, data) => {
|
|
202
|
+
if (typeof keyOrAlias === "string") {
|
|
203
|
+
throw new LightsparkSigningException_default(
|
|
204
|
+
"Key alias not supported for default crypto."
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
const cryptoImpl = await getCrypto();
|
|
208
|
+
return await cryptoImpl.subtle.sign(
|
|
209
|
+
{
|
|
210
|
+
name: "RSA-PSS",
|
|
211
|
+
saltLength: 32
|
|
212
|
+
},
|
|
213
|
+
keyOrAlias,
|
|
214
|
+
data
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
var importPrivateSigningKey = async (keyData) => {
|
|
218
|
+
const cryptoImpl = await getCrypto();
|
|
219
|
+
return await cryptoImpl.subtle.importKey(
|
|
220
|
+
/*format*/
|
|
221
|
+
"pkcs8",
|
|
222
|
+
/*keyData*/
|
|
223
|
+
keyData,
|
|
224
|
+
/*algorithm*/
|
|
225
|
+
{
|
|
226
|
+
name: "RSA-PSS",
|
|
227
|
+
hash: "SHA-256"
|
|
228
|
+
},
|
|
229
|
+
/*extractable*/
|
|
230
|
+
true,
|
|
231
|
+
/*keyUsages*/
|
|
232
|
+
["sign"]
|
|
233
|
+
);
|
|
234
|
+
};
|
|
235
|
+
var DefaultCrypto = {
|
|
236
|
+
decryptSecretWithNodePassword,
|
|
237
|
+
generateSigningKeyPair,
|
|
238
|
+
serializeSigningKey,
|
|
239
|
+
getNonce,
|
|
240
|
+
sign,
|
|
241
|
+
importPrivateSigningKey
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// src/constants/index.ts
|
|
245
|
+
var ConfigKeys = {
|
|
246
|
+
LoggingEnabled: "lightspark-logging-enabled",
|
|
247
|
+
ConsoleToolsEnabled: "lightspark-console-tools-enabled"
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/Logger.ts
|
|
251
|
+
var LoggingLevel = /* @__PURE__ */ ((LoggingLevel2) => {
|
|
252
|
+
LoggingLevel2[LoggingLevel2["Trace"] = 0] = "Trace";
|
|
253
|
+
LoggingLevel2[LoggingLevel2["Info"] = 1] = "Info";
|
|
254
|
+
return LoggingLevel2;
|
|
255
|
+
})(LoggingLevel || {});
|
|
256
|
+
var Logger = class {
|
|
257
|
+
context;
|
|
258
|
+
loggingEnabled = false;
|
|
259
|
+
loggingLevel = 1 /* Info */;
|
|
260
|
+
constructor(loggerContext, getLoggingEnabled) {
|
|
261
|
+
this.context = loggerContext;
|
|
262
|
+
void this.updateLoggingEnabled(getLoggingEnabled);
|
|
263
|
+
}
|
|
264
|
+
setLevel(level) {
|
|
265
|
+
this.loggingLevel = level;
|
|
266
|
+
}
|
|
267
|
+
setEnabled(enabled, level = 1 /* Info */) {
|
|
268
|
+
this.loggingEnabled = enabled;
|
|
269
|
+
this.loggingLevel = level;
|
|
270
|
+
}
|
|
271
|
+
async updateLoggingEnabled(getLoggingEnabled) {
|
|
272
|
+
if (getLoggingEnabled) {
|
|
273
|
+
this.loggingEnabled = await getLoggingEnabled();
|
|
274
|
+
} else if (isTest) {
|
|
275
|
+
this.loggingEnabled = true;
|
|
276
|
+
} else if (isBrowser) {
|
|
277
|
+
try {
|
|
278
|
+
this.loggingEnabled = getLocalStorageConfigItem(
|
|
279
|
+
ConfigKeys.LoggingEnabled
|
|
280
|
+
);
|
|
281
|
+
} catch (e) {
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (this.loggingEnabled) {
|
|
285
|
+
console.log(`[${this.context}] Logging enabled`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
trace(message, ...rest) {
|
|
289
|
+
if (this.loggingEnabled && this.loggingLevel === 0 /* Trace */) {
|
|
290
|
+
console.log(`[${this.context}] ${message}`, ...rest);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
info(message, ...rest) {
|
|
294
|
+
if (this.loggingEnabled && this.loggingLevel <= 1 /* Info */) {
|
|
295
|
+
console.log(`[${this.context}] ${message}`, ...rest);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
var logger = new Logger("@lightsparkdev/core");
|
|
300
|
+
|
|
301
|
+
// ../../node_modules/auto-bind/index.js
|
|
302
|
+
var getAllProperties = (object) => {
|
|
303
|
+
const properties = /* @__PURE__ */ new Set();
|
|
304
|
+
do {
|
|
305
|
+
for (const key of Reflect.ownKeys(object)) {
|
|
306
|
+
properties.add([object, key]);
|
|
307
|
+
}
|
|
308
|
+
} while ((object = Reflect.getPrototypeOf(object)) && object !== Object.prototype);
|
|
309
|
+
return properties;
|
|
310
|
+
};
|
|
311
|
+
function autoBind(self, { include, exclude } = {}) {
|
|
312
|
+
const filter = (key) => {
|
|
313
|
+
const match = (pattern) => typeof pattern === "string" ? key === pattern : pattern.test(key);
|
|
314
|
+
if (include) {
|
|
315
|
+
return include.some(match);
|
|
316
|
+
}
|
|
317
|
+
if (exclude) {
|
|
318
|
+
return !exclude.some(match);
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
};
|
|
322
|
+
for (const [object, key] of getAllProperties(self.constructor.prototype)) {
|
|
323
|
+
if (key === "constructor" || !filter(key)) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(object, key);
|
|
327
|
+
if (descriptor && typeof descriptor.value === "function") {
|
|
328
|
+
self[key] = self[key].bind(self);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return self;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/requester/Requester.ts
|
|
335
|
+
import dayjs from "dayjs";
|
|
336
|
+
import utc from "dayjs/plugin/utc.js";
|
|
337
|
+
import { Observable } from "zen-observable-ts";
|
|
338
|
+
var DEFAULT_BASE_URL = "api.lightspark.com";
|
|
339
|
+
dayjs.extend(utc);
|
|
340
|
+
var Requester = class {
|
|
341
|
+
constructor(nodeKeyCache, schemaEndpoint, sdkUserAgent, authProvider = new StubAuthProvider(), baseUrl = DEFAULT_BASE_URL, cryptoImpl = DefaultCrypto, signingKey, fetchImpl = fetch) {
|
|
342
|
+
this.nodeKeyCache = nodeKeyCache;
|
|
343
|
+
this.schemaEndpoint = schemaEndpoint;
|
|
344
|
+
this.sdkUserAgent = sdkUserAgent;
|
|
345
|
+
this.authProvider = authProvider;
|
|
346
|
+
this.baseUrl = baseUrl;
|
|
347
|
+
this.cryptoImpl = cryptoImpl;
|
|
348
|
+
this.signingKey = signingKey;
|
|
349
|
+
this.fetchImpl = fetchImpl;
|
|
350
|
+
this.wsClient = new Promise((resolve) => {
|
|
351
|
+
this.resolveWsClient = resolve;
|
|
352
|
+
});
|
|
353
|
+
void this.initWsClient(baseUrl, authProvider);
|
|
354
|
+
autoBind(this);
|
|
355
|
+
}
|
|
356
|
+
wsClient;
|
|
357
|
+
resolveWsClient = null;
|
|
358
|
+
initWsClient(baseUrl, authProvider) {
|
|
359
|
+
return Promise.resolve(null);
|
|
360
|
+
}
|
|
361
|
+
async executeQuery(query) {
|
|
362
|
+
const data = await this.makeRawRequest(
|
|
363
|
+
query.queryPayload,
|
|
364
|
+
query.variables || {},
|
|
365
|
+
query.signingNodeId,
|
|
366
|
+
!!query.skipAuth
|
|
367
|
+
);
|
|
368
|
+
return query.constructObject(data);
|
|
369
|
+
}
|
|
370
|
+
subscribe(queryPayload, variables = {}) {
|
|
371
|
+
logger.trace(`Requester.subscribe variables`, variables);
|
|
372
|
+
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
373
|
+
const operationMatch = queryPayload.match(operationNameRegex);
|
|
374
|
+
if (!operationMatch || operationMatch.length < 3) {
|
|
375
|
+
throw new LightsparkException_default("InvalidQuery", "Invalid query payload");
|
|
376
|
+
}
|
|
377
|
+
const operationType = operationMatch[1];
|
|
378
|
+
logger.trace(`Requester.subscribe operationType`, operationType);
|
|
379
|
+
if (operationType == "mutation") {
|
|
380
|
+
throw new LightsparkException_default(
|
|
381
|
+
"InvalidQuery",
|
|
382
|
+
"Mutation queries should call makeRawRequest instead"
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
for (const key in variables) {
|
|
386
|
+
if (variables[key] === void 0) {
|
|
387
|
+
variables[key] = null;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const operation = operationMatch[2];
|
|
391
|
+
const bodyData = {
|
|
392
|
+
query: queryPayload,
|
|
393
|
+
variables,
|
|
394
|
+
operationName: operation
|
|
395
|
+
};
|
|
396
|
+
return new Observable((observer) => {
|
|
397
|
+
logger.trace(`Requester.subscribe observer`, observer);
|
|
398
|
+
let cleanup = null;
|
|
399
|
+
let canceled = false;
|
|
400
|
+
void (async () => {
|
|
401
|
+
try {
|
|
402
|
+
const wsClient = await this.wsClient;
|
|
403
|
+
if (!wsClient) {
|
|
404
|
+
throw new LightsparkException_default(
|
|
405
|
+
"WebSocketNotInitialized",
|
|
406
|
+
"WebSocket client is not initialized or is not available in the current environment."
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
if (!canceled) {
|
|
410
|
+
cleanup = wsClient.subscribe(bodyData, {
|
|
411
|
+
next: (data) => observer.next(data),
|
|
412
|
+
error: (err) => observer.error(err),
|
|
413
|
+
complete: () => observer.complete()
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
} catch (err) {
|
|
417
|
+
observer.error(err);
|
|
418
|
+
}
|
|
419
|
+
})();
|
|
420
|
+
return () => {
|
|
421
|
+
canceled = true;
|
|
422
|
+
if (cleanup) {
|
|
423
|
+
cleanup();
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
async makeRawRequest(queryPayload, variables = {}, signingNodeId = void 0, skipAuth = false) {
|
|
429
|
+
logger.trace(`Requester.makeRawRequest args`, {
|
|
430
|
+
queryPayload,
|
|
431
|
+
variables,
|
|
432
|
+
signingNodeId,
|
|
433
|
+
skipAuth
|
|
434
|
+
});
|
|
435
|
+
const operationNameRegex = /^\s*(query|mutation|subscription)\s+(\w+)/i;
|
|
436
|
+
const operationMatch = queryPayload.match(operationNameRegex);
|
|
437
|
+
if (!operationMatch || operationMatch.length < 3) {
|
|
438
|
+
throw new LightsparkException_default("InvalidQuery", "Invalid query payload");
|
|
439
|
+
}
|
|
440
|
+
const operationType = operationMatch[1];
|
|
441
|
+
if (operationType == "subscription") {
|
|
442
|
+
throw new LightsparkException_default(
|
|
443
|
+
"InvalidQuery",
|
|
444
|
+
"Subscription queries should call subscribe instead"
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
for (const key in variables) {
|
|
448
|
+
if (variables[key] === void 0) {
|
|
449
|
+
variables[key] = null;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const operation = operationMatch[2];
|
|
453
|
+
const payload = {
|
|
454
|
+
query: queryPayload,
|
|
455
|
+
variables,
|
|
456
|
+
operationName: operation
|
|
457
|
+
};
|
|
458
|
+
const browserUserAgent = typeof navigator !== "undefined" ? navigator.userAgent : "";
|
|
459
|
+
const sdkUserAgent = this.getSdkUserAgent();
|
|
460
|
+
const baseHeaders = {
|
|
461
|
+
"Content-Type": "application/json",
|
|
462
|
+
"X-Lightspark-SDK": sdkUserAgent,
|
|
463
|
+
"User-Agent": browserUserAgent || sdkUserAgent,
|
|
464
|
+
"X-GraphQL-Operation": operation
|
|
465
|
+
};
|
|
466
|
+
const headers = skipAuth ? baseHeaders : await this.authProvider.addAuthHeaders(baseHeaders);
|
|
467
|
+
let bodyData = await this.addSigningDataIfNeeded(
|
|
468
|
+
payload,
|
|
469
|
+
headers,
|
|
470
|
+
signingNodeId
|
|
471
|
+
);
|
|
472
|
+
if (bodyData.length > 1024 && typeof CompressionStream != "undefined") {
|
|
473
|
+
bodyData = await compress(bodyData);
|
|
474
|
+
headers["Content-Encoding"] = "deflate";
|
|
475
|
+
}
|
|
476
|
+
let urlWithProtocol = this.baseUrl;
|
|
477
|
+
if (!urlWithProtocol.startsWith("https://") && !urlWithProtocol.startsWith("http://")) {
|
|
478
|
+
urlWithProtocol = `https://${urlWithProtocol}`;
|
|
479
|
+
}
|
|
480
|
+
const url = `${urlWithProtocol}/${this.schemaEndpoint}`;
|
|
481
|
+
logger.trace(`Requester.makeRawRequest`, {
|
|
482
|
+
url,
|
|
483
|
+
operationName: operation,
|
|
484
|
+
variables,
|
|
485
|
+
headers
|
|
486
|
+
});
|
|
487
|
+
const response = await this.fetchImpl(url, {
|
|
488
|
+
method: "POST",
|
|
489
|
+
headers,
|
|
490
|
+
body: bodyData
|
|
491
|
+
});
|
|
492
|
+
if (!response.ok) {
|
|
493
|
+
throw new LightsparkException_default(
|
|
494
|
+
"RequestFailed",
|
|
495
|
+
`Request ${operation} failed. ${response.statusText}`
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
const responseJson = await response.json();
|
|
499
|
+
const data = responseJson.data;
|
|
500
|
+
if (!data) {
|
|
501
|
+
let firstErrorName = void 0;
|
|
502
|
+
if (Array.isArray(responseJson.errors) && responseJson.errors.length > 0) {
|
|
503
|
+
const firstError = responseJson.errors[0];
|
|
504
|
+
firstErrorName = firstError["extensions"]?.["error_name"];
|
|
505
|
+
}
|
|
506
|
+
throw new LightsparkException_default(
|
|
507
|
+
"RequestFailed",
|
|
508
|
+
`Request ${operation} failed. ${JSON.stringify(responseJson.errors)}`,
|
|
509
|
+
{ errorName: firstErrorName }
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
return data;
|
|
513
|
+
}
|
|
514
|
+
getSdkUserAgent() {
|
|
515
|
+
const platform = isNode ? "NodeJS" : "Browser";
|
|
516
|
+
const platformVersion = isNode ? process.version : "";
|
|
517
|
+
return `${this.sdkUserAgent} ${platform}/${platformVersion}`;
|
|
518
|
+
}
|
|
519
|
+
stripProtocol(url) {
|
|
520
|
+
return url.replace(/.*?:\/\//g, "");
|
|
521
|
+
}
|
|
522
|
+
async addSigningDataIfNeeded(queryPayload, headers, signingNodeId) {
|
|
523
|
+
if (!signingNodeId) {
|
|
524
|
+
return new TextEncoder().encode(JSON.stringify(queryPayload));
|
|
525
|
+
}
|
|
526
|
+
const query = queryPayload.query;
|
|
527
|
+
const variables = queryPayload.variables;
|
|
528
|
+
const operationName = queryPayload.operationName;
|
|
529
|
+
const nonce = await this.cryptoImpl.getNonce();
|
|
530
|
+
const expiration = dayjs.utc().add(1, "hour").format();
|
|
531
|
+
const payload = {
|
|
532
|
+
query,
|
|
533
|
+
variables,
|
|
534
|
+
operationName,
|
|
535
|
+
nonce,
|
|
536
|
+
expires_at: expiration
|
|
537
|
+
};
|
|
538
|
+
const key = this.signingKey ?? this.nodeKeyCache.getKey(signingNodeId);
|
|
539
|
+
if (!key) {
|
|
540
|
+
throw new LightsparkSigningException_default(
|
|
541
|
+
"Missing node of encrypted_signing_private_key"
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
const encodedPayload = new TextEncoder().encode(JSON.stringify(payload));
|
|
545
|
+
const signedPayload = await key.sign(encodedPayload);
|
|
546
|
+
const encodedSignedPayload = b64encode(signedPayload);
|
|
547
|
+
headers["X-Lightspark-Signing"] = JSON.stringify({
|
|
548
|
+
v: "1",
|
|
549
|
+
signature: encodedSignedPayload
|
|
550
|
+
});
|
|
551
|
+
return encodedPayload;
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
async function compress(data) {
|
|
555
|
+
const stream = new Blob([data]).stream();
|
|
556
|
+
const compressedStream = stream.pipeThrough(new CompressionStream("deflate"));
|
|
557
|
+
const reader = compressedStream.getReader();
|
|
558
|
+
const chunks = [];
|
|
559
|
+
let done, value;
|
|
560
|
+
while (!done) {
|
|
561
|
+
({ done, value } = await reader.read());
|
|
562
|
+
chunks.push(value);
|
|
563
|
+
}
|
|
564
|
+
const blob = new Blob(chunks);
|
|
565
|
+
return new Uint8Array(await blob.arrayBuffer());
|
|
566
|
+
}
|
|
567
|
+
var Requester_default = Requester;
|
|
568
|
+
|
|
569
|
+
// src/auth/LightsparkAuthException.ts
|
|
570
|
+
var LightsparkAuthException = class extends LightsparkException_default {
|
|
571
|
+
constructor(message, extraInfo) {
|
|
572
|
+
super("AuthException", message, extraInfo);
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
var LightsparkAuthException_default = LightsparkAuthException;
|
|
576
|
+
|
|
577
|
+
// src/crypto/KeyOrAlias.ts
|
|
578
|
+
var KeyOrAlias = {
|
|
579
|
+
key: (key) => ({ key }),
|
|
580
|
+
alias: (alias) => ({ alias })
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
// src/crypto/types.ts
|
|
584
|
+
var SigningKeyType = /* @__PURE__ */ ((SigningKeyType2) => {
|
|
585
|
+
SigningKeyType2["RSASigningKey"] = "RSASigningKey";
|
|
586
|
+
SigningKeyType2["Secp256k1SigningKey"] = "Secp256k1SigningKey";
|
|
587
|
+
return SigningKeyType2;
|
|
588
|
+
})(SigningKeyType || {});
|
|
589
|
+
|
|
590
|
+
// src/crypto/SigningKey.ts
|
|
591
|
+
import secp256k1 from "secp256k1";
|
|
592
|
+
function isAlias(key) {
|
|
593
|
+
return "alias" in key;
|
|
594
|
+
}
|
|
595
|
+
var SigningKey = class {
|
|
596
|
+
type;
|
|
597
|
+
constructor(type) {
|
|
598
|
+
this.type = type;
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
var RSASigningKey = class extends SigningKey {
|
|
602
|
+
constructor(privateKey, cryptoImpl) {
|
|
603
|
+
super("RSASigningKey" /* RSASigningKey */);
|
|
604
|
+
this.privateKey = privateKey;
|
|
605
|
+
this.cryptoImpl = cryptoImpl;
|
|
606
|
+
}
|
|
607
|
+
async sign(data) {
|
|
608
|
+
const key = isAlias(this.privateKey) ? this.privateKey.alias : this.privateKey;
|
|
609
|
+
return this.cryptoImpl.sign(key, data);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
var Secp256k1SigningKey = class extends SigningKey {
|
|
613
|
+
constructor(privateKey) {
|
|
614
|
+
super("Secp256k1SigningKey" /* Secp256k1SigningKey */);
|
|
615
|
+
this.privateKey = privateKey;
|
|
616
|
+
}
|
|
617
|
+
async sign(data) {
|
|
618
|
+
const keyBytes = new Uint8Array(hexToBytes(this.privateKey));
|
|
619
|
+
const hash = await createSha256Hash(data);
|
|
620
|
+
const signResult = secp256k1.ecdsaSign(hash, keyBytes);
|
|
621
|
+
return secp256k1.signatureExport(signResult.signature);
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
// src/crypto/NodeKeyCache.ts
|
|
626
|
+
var NodeKeyCache = class {
|
|
627
|
+
constructor(cryptoImpl = DefaultCrypto) {
|
|
628
|
+
this.cryptoImpl = cryptoImpl;
|
|
629
|
+
this.idToKey = /* @__PURE__ */ new Map();
|
|
630
|
+
autoBind(this);
|
|
631
|
+
}
|
|
632
|
+
idToKey;
|
|
633
|
+
async loadKey(id, keyOrAlias, signingKeyType) {
|
|
634
|
+
let signingKey;
|
|
635
|
+
if (keyOrAlias.alias !== void 0) {
|
|
636
|
+
switch (signingKeyType) {
|
|
637
|
+
case "RSASigningKey" /* RSASigningKey */:
|
|
638
|
+
signingKey = new RSASigningKey(
|
|
639
|
+
{ alias: keyOrAlias.alias },
|
|
640
|
+
this.cryptoImpl
|
|
641
|
+
);
|
|
642
|
+
break;
|
|
643
|
+
default:
|
|
644
|
+
throw new LightsparkSigningException_default(
|
|
645
|
+
`Aliases are not supported for signing key type ${signingKeyType}`
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
this.idToKey.set(id, signingKey);
|
|
649
|
+
return signingKey;
|
|
650
|
+
}
|
|
651
|
+
try {
|
|
652
|
+
if (signingKeyType === "Secp256k1SigningKey" /* Secp256k1SigningKey */) {
|
|
653
|
+
signingKey = new Secp256k1SigningKey(keyOrAlias.key);
|
|
654
|
+
} else {
|
|
655
|
+
const decoded = b64decode(this.stripPemTags(keyOrAlias.key));
|
|
656
|
+
const cryptoKeyOrAlias = await this.cryptoImpl.importPrivateSigningKey(decoded);
|
|
657
|
+
const key = typeof cryptoKeyOrAlias === "string" ? { alias: cryptoKeyOrAlias } : cryptoKeyOrAlias;
|
|
658
|
+
signingKey = new RSASigningKey(key, this.cryptoImpl);
|
|
659
|
+
}
|
|
660
|
+
this.idToKey.set(id, signingKey);
|
|
661
|
+
return signingKey;
|
|
662
|
+
} catch (e) {
|
|
663
|
+
console.log("Error importing key: ", e);
|
|
664
|
+
}
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
getKey(id) {
|
|
668
|
+
return this.idToKey.get(id);
|
|
669
|
+
}
|
|
670
|
+
hasKey(id) {
|
|
671
|
+
return this.idToKey.has(id);
|
|
672
|
+
}
|
|
673
|
+
stripPemTags(pem) {
|
|
674
|
+
return pem.replace(/-----BEGIN (.*)-----/, "").replace(/-----END (.*)----/, "");
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
var NodeKeyCache_default = NodeKeyCache;
|
|
678
|
+
|
|
679
|
+
// src/ServerEnvironment.ts
|
|
680
|
+
var ServerEnvironment = /* @__PURE__ */ ((ServerEnvironment2) => {
|
|
681
|
+
ServerEnvironment2["PRODUCTION"] = "production";
|
|
682
|
+
ServerEnvironment2["DEV"] = "dev";
|
|
683
|
+
return ServerEnvironment2;
|
|
684
|
+
})(ServerEnvironment || {});
|
|
685
|
+
var apiDomainForEnvironment = (environment) => {
|
|
686
|
+
switch (environment) {
|
|
687
|
+
case "dev" /* DEV */:
|
|
688
|
+
return "api.dev.dev.sparkinfra.net";
|
|
689
|
+
case "production" /* PRODUCTION */:
|
|
690
|
+
return "api.lightspark.com";
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
var ServerEnvironment_default = ServerEnvironment;
|
|
694
|
+
|
|
695
|
+
export {
|
|
696
|
+
StubAuthProvider,
|
|
697
|
+
LightsparkSigningException_default,
|
|
698
|
+
DefaultCrypto,
|
|
699
|
+
ConfigKeys,
|
|
700
|
+
LoggingLevel,
|
|
701
|
+
Logger,
|
|
702
|
+
logger,
|
|
703
|
+
Requester_default,
|
|
704
|
+
LightsparkAuthException_default,
|
|
705
|
+
KeyOrAlias,
|
|
706
|
+
SigningKeyType,
|
|
707
|
+
SigningKey,
|
|
708
|
+
RSASigningKey,
|
|
709
|
+
Secp256k1SigningKey,
|
|
710
|
+
NodeKeyCache_default,
|
|
711
|
+
apiDomainForEnvironment,
|
|
712
|
+
ServerEnvironment_default
|
|
713
|
+
};
|