@talismn/util 0.5.0 → 0.5.1
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/dist/declarations/src/Prettify.d.ts +3 -0
- package/dist/declarations/src/classNames.d.ts +1 -0
- package/dist/declarations/src/getLoadable.d.ts +25 -0
- package/dist/declarations/src/index.d.ts +13 -17
- package/dist/declarations/src/isPromise.d.ts +1 -0
- package/dist/declarations/src/isSubject.d.ts +5 -0
- package/dist/declarations/src/replaySubjectFrom.d.ts +12 -0
- package/dist/declarations/src/splitSubject.d.ts +11 -0
- package/dist/declarations/src/validateHexString.d.ts +2 -3
- package/dist/talismn-util.cjs.dev.js +179 -180
- package/dist/talismn-util.cjs.prod.js +179 -180
- package/dist/talismn-util.esm.js +175 -172
- package/package.json +1 -7
- package/dist/declarations/src/blake2Concat.d.ts +0 -1
- package/dist/declarations/src/convertAddress.d.ts +0 -7
- package/dist/declarations/src/decodeAnyAddress.d.ts +0 -1
- package/dist/declarations/src/decodeSs58Format.d.ts +0 -1
- package/dist/declarations/src/encodeAnyAddress.d.ts +0 -1
- package/dist/declarations/src/isAddressEqual.d.ts +0 -1
- package/dist/declarations/src/isEthereumAddress.d.ts +0 -1
- package/dist/declarations/src/isValidSubstrateAddress.d.ts +0 -7
- package/dist/declarations/src/normalizeAddress.d.ts +0 -1
- package/dist/declarations/src/twox64Concat.d.ts +0 -1
@@ -1,9 +1,6 @@
|
|
1
1
|
'use strict';
|
2
2
|
|
3
|
-
var util = require('@polkadot/util');
|
4
|
-
var utilCrypto = require('@polkadot/util-crypto');
|
5
3
|
var tailwindMerge = require('tailwind-merge');
|
6
|
-
var keyring = require('@polkadot/keyring');
|
7
4
|
var rxjs = require('rxjs');
|
8
5
|
var BigNumber = require('bignumber.js');
|
9
6
|
|
@@ -45,54 +42,8 @@ const BigMath = {
|
|
45
42
|
}
|
46
43
|
};
|
47
44
|
|
48
|
-
const bitLength$1 = 128;
|
49
|
-
function blake2Concat(input) {
|
50
|
-
return util.u8aToHex(util.u8aConcat(utilCrypto.blake2AsU8a(input, bitLength$1), util.u8aToU8a(input)));
|
51
|
-
}
|
52
|
-
|
53
45
|
const classNames = tailwindMerge.twMerge;
|
54
|
-
|
55
|
-
function encodeAnyAddress(key, ss58Format) {
|
56
|
-
try {
|
57
|
-
return keyring.encodeAddress(key, ss58Format);
|
58
|
-
} catch (error) {
|
59
|
-
if (typeof key !== "string") throw error;
|
60
|
-
if (!utilCrypto.isEthereumAddress(key)) throw error;
|
61
|
-
return utilCrypto.ethereumEncode(key);
|
62
|
-
}
|
63
|
-
}
|
64
|
-
|
65
|
-
/**
|
66
|
-
*
|
67
|
-
* @param address substrate SS58 address
|
68
|
-
* @param prefix prefix used to format the address
|
69
|
-
* @returns address encoded with supplied prefix
|
70
|
-
*/
|
71
|
-
const convertAddress = (address, prefix) => {
|
72
|
-
return encodeAnyAddress(address, prefix ?? undefined);
|
73
|
-
};
|
74
|
-
|
75
|
-
function decodeAnyAddress(encoded, ignoreChecksum, ss58Format) {
|
76
|
-
try {
|
77
|
-
return keyring.decodeAddress(encoded, ignoreChecksum, ss58Format);
|
78
|
-
} catch (error) {
|
79
|
-
if (typeof encoded !== "string") throw error;
|
80
|
-
if (!utilCrypto.isEthereumAddress(encoded)) throw error;
|
81
|
-
return util.hexToU8a(encoded.slice("0x".length));
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
const decodeSs58Format = address => {
|
86
|
-
if (!address) return;
|
87
|
-
try {
|
88
|
-
utilCrypto.decodeAddress(address);
|
89
|
-
const decoded = utilCrypto.base58Decode(address);
|
90
|
-
const [,,, ss58Format] = utilCrypto.checkAddressChecksum(decoded);
|
91
|
-
return ss58Format;
|
92
|
-
} catch {
|
93
|
-
return; // invalid address
|
94
|
-
}
|
95
|
-
};
|
46
|
+
const cn = tailwindMerge.twMerge;
|
96
47
|
|
97
48
|
/**
|
98
49
|
* In TypeScript, a deferred promise refers to a pattern that involves creating a promise that can be
|
@@ -195,113 +146,57 @@ const formatPrice = (price, currency, compact) => {
|
|
195
146
|
}).format(price);
|
196
147
|
};
|
197
148
|
|
149
|
+
const CACHE = new Map();
|
150
|
+
|
151
|
+
/**
|
152
|
+
* When using react-rxjs hooks and state observables, the options are used as weak map keys.
|
153
|
+
* This means that if the options object is recreated on each render, the observable will be recreated as well.
|
154
|
+
* This utility function allows you to create a shared observable based on a namespace and arguments that, so react-rxjs can reuse the same observables
|
155
|
+
*
|
156
|
+
* @param namespace
|
157
|
+
* @param args
|
158
|
+
* @param createObservable
|
159
|
+
* @param serializer
|
160
|
+
* @returns
|
161
|
+
*/
|
162
|
+
const getSharedObservable = (namespace, args, createObservable, serializer = args => JSON.stringify(args)) => {
|
163
|
+
const cacheKey = `${namespace}:${serializer(args)}`;
|
164
|
+
if (CACHE.has(cacheKey)) return CACHE.get(cacheKey);
|
165
|
+
const obs = createObservable(args);
|
166
|
+
const sharedObs = obs.pipe(rxjs.shareReplay({
|
167
|
+
bufferSize: 1,
|
168
|
+
refCount: true
|
169
|
+
}));
|
170
|
+
CACHE.set(cacheKey, sharedObs);
|
171
|
+
return sharedObs;
|
172
|
+
};
|
173
|
+
|
198
174
|
function hasOwnProperty(obj, prop) {
|
199
175
|
if (typeof obj !== "object") return false;
|
200
176
|
if (obj === null) return false;
|
201
177
|
return prop in obj;
|
202
178
|
}
|
203
179
|
|
180
|
+
const isAbortError = error => {
|
181
|
+
return error instanceof Error && error.name === "AbortError";
|
182
|
+
};
|
183
|
+
|
204
184
|
function isArrayOf(array, func) {
|
205
185
|
if (array.length > 0 && array[0] instanceof func) return true;
|
206
186
|
return false;
|
207
187
|
}
|
208
188
|
|
209
|
-
const
|
210
|
-
|
211
|
-
const isBooleanTrue = x => !!x;
|
212
|
-
|
213
|
-
const isEthereumAddress = address => !!address && address.startsWith("0x") && address.length === 42;
|
214
|
-
|
215
|
-
/**
|
216
|
-
* Similar to isValidAddress but will not call isEthereumAddress under the hood
|
217
|
-
* @param address
|
218
|
-
* @param prefix if supplied, the method will also check the prefix
|
219
|
-
* @returns true if valid substrate (SS58) address, false otherwise
|
220
|
-
*/
|
221
|
-
const isValidSubstrateAddress = (address, prefix) => {
|
222
|
-
try {
|
223
|
-
// attempt to encode, it will throw an error if address is invalid
|
224
|
-
const encoded = keyring.encodeAddress(address, prefix ?? undefined);
|
225
|
-
|
226
|
-
//if a prefix is supplied, check that reencoding using this prefix matches the input address
|
227
|
-
if (prefix !== undefined) return address === encoded;
|
228
|
-
|
229
|
-
//if no prefix supplied, the fact that decoding + encoding succeded indicates that the address is valid
|
230
|
-
return true;
|
231
|
-
} catch (error) {
|
232
|
-
// input is not a substrate (SS58) address
|
233
|
-
return false;
|
234
|
-
}
|
235
|
-
};
|
236
|
-
|
237
|
-
function planckToTokens(planck, tokenDecimals) {
|
238
|
-
if (typeof planck !== "string" || typeof tokenDecimals !== "number") return;
|
239
|
-
const base = 10;
|
240
|
-
const exponent = -1 * tokenDecimals;
|
241
|
-
const multiplier = base ** exponent;
|
242
|
-
return new BigNumber__default.default(planck).multipliedBy(multiplier).toString(10);
|
243
|
-
}
|
244
|
-
|
245
|
-
const sleep = ms => new Promise(resolve => {
|
246
|
-
setTimeout(resolve, ms);
|
247
|
-
});
|
248
|
-
|
249
|
-
const throwAfter = (ms, reason) => new Promise((_, reject) => setTimeout(() => reject(new Error(reason)), ms));
|
250
|
-
|
251
|
-
function tokensToPlanck(tokens, tokenDecimals) {
|
252
|
-
if (typeof tokens !== "string" || typeof tokenDecimals !== "number") return;
|
253
|
-
const base = 10;
|
254
|
-
const exponent = tokenDecimals;
|
255
|
-
const multiplier = base ** exponent;
|
256
|
-
return new BigNumber__default.default(tokens).multipliedBy(multiplier).toString(10);
|
257
|
-
}
|
258
|
-
|
259
|
-
const bitLength = 64;
|
260
|
-
function twox64Concat(input) {
|
261
|
-
const inputAsU8a = typeof input === "string" ? input : new Uint8Array(input);
|
262
|
-
return util.u8aToHex(util.u8aConcat(utilCrypto.xxhashAsU8a(inputAsU8a, bitLength), util.u8aToU8a(inputAsU8a)));
|
263
|
-
}
|
264
|
-
|
265
|
-
/**
|
266
|
-
* @name validateHexString
|
267
|
-
* @description Checks if a string is a hex string. Required to account for type differences between different polkadot libraries
|
268
|
-
* @param {string} str - string to check
|
269
|
-
* @returns {HexString} - boolean
|
270
|
-
* @example
|
271
|
-
* validateHexString("0x1234") // "0x1234"
|
272
|
-
* validateHexString("1234") // Error: Expected a hex string
|
273
|
-
* validateHexString(1234) // Error: Expected a string
|
274
|
-
**/
|
275
|
-
const validateHexString = str => {
|
276
|
-
if (typeof str !== "string") {
|
277
|
-
throw new Error("Expected a string");
|
278
|
-
}
|
279
|
-
if (str.startsWith("0x")) {
|
280
|
-
return str;
|
281
|
-
}
|
282
|
-
throw new Error("Expected a hex string");
|
189
|
+
const isAscii = str => {
|
190
|
+
return [...str].every(char => char.charCodeAt(0) <= 127);
|
283
191
|
};
|
284
192
|
|
285
|
-
const
|
286
|
-
|
287
|
-
// Normalize an address in a way that it can be compared to other addresses that have also been normalized
|
288
|
-
const normalizeAddress = address => {
|
289
|
-
try {
|
290
|
-
if (!CACHE$1.has(address)) CACHE$1.set(address, encodeAnyAddress(address));
|
291
|
-
return CACHE$1.get(address);
|
292
|
-
} catch (cause) {
|
293
|
-
throw new Error(`Unable to normalize address: ${address}`, {
|
294
|
-
cause
|
295
|
-
});
|
296
|
-
}
|
297
|
-
};
|
193
|
+
const isBigInt = value => typeof value === "bigint";
|
298
194
|
|
299
|
-
const
|
300
|
-
return normalizeAddress(address1) === normalizeAddress(address2);
|
301
|
-
};
|
195
|
+
const isBooleanTrue = x => !!x;
|
302
196
|
|
303
|
-
const
|
304
|
-
|
197
|
+
const REGEX_HEX_STRING = /^0x[0-9a-fA-F]*$/;
|
198
|
+
const isHexString = value => {
|
199
|
+
return typeof value === "string" && REGEX_HEX_STRING.test(value);
|
305
200
|
};
|
306
201
|
|
307
202
|
/**
|
@@ -314,36 +209,33 @@ const isAscii = str => {
|
|
314
209
|
*/
|
315
210
|
const isNotNil = value => value !== null && value !== undefined;
|
316
211
|
|
317
|
-
|
212
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
213
|
+
const isPromise = value => !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
318
214
|
|
319
|
-
|
320
|
-
|
321
|
-
|
215
|
+
/**
|
216
|
+
* Tests to see if an object is an RxJS {@link Subject}.
|
217
|
+
*/
|
218
|
+
function isSubject(object) {
|
219
|
+
if (!object) return false;
|
220
|
+
if (object instanceof rxjs.Subject) return true;
|
221
|
+
return "asObservable" in object && isFn(object.asObservable) && "complete" in object && isFn(object.complete) && "error" in object && isFn(object.error) && "forEach" in object && isFn(object.forEach) && "next" in object && isFn(object.next) && "pipe" in object && isFn(object.pipe) && "subscribe" in object && isFn(object.subscribe) && "unsubscribe" in object && isFn(object.unsubscribe) && "closed" in object && isBool(object.closed) && "observed" in object && isBool(object.observed);
|
222
|
+
}
|
322
223
|
|
323
|
-
|
224
|
+
/**
|
225
|
+
* Returns `true` if `value` is a function.
|
226
|
+
*/
|
227
|
+
function isFn(value) {
|
228
|
+
return typeof value === "function";
|
229
|
+
}
|
324
230
|
|
325
231
|
/**
|
326
|
-
*
|
327
|
-
* This means that if the options object is recreated on each render, the observable will be recreated as well.
|
328
|
-
* This utility function allows you to create a shared observable based on a namespace and arguments that, so react-rxjs can reuse the same observables
|
329
|
-
*
|
330
|
-
* @param namespace
|
331
|
-
* @param args
|
332
|
-
* @param createObservable
|
333
|
-
* @param serializer
|
334
|
-
* @returns
|
232
|
+
* Returns `true` if `value` is a boolean.
|
335
233
|
*/
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
bufferSize: 1,
|
342
|
-
refCount: true
|
343
|
-
}));
|
344
|
-
CACHE.set(cacheKey, sharedObs);
|
345
|
-
return sharedObs;
|
346
|
-
};
|
234
|
+
function isBool(value) {
|
235
|
+
return typeof value === "boolean";
|
236
|
+
}
|
237
|
+
|
238
|
+
const isTruthy = value => Boolean(value);
|
347
239
|
|
348
240
|
/**
|
349
241
|
* An RxJS operator that keeps the source observable alive for a specified duration
|
@@ -379,9 +271,120 @@ const keepSourceSubscribed = (observable, ms) => {
|
|
379
271
|
return () => setTimeout(() => sub.unsubscribe(), ms);
|
380
272
|
};
|
381
273
|
|
382
|
-
|
383
|
-
|
384
|
-
|
274
|
+
function planckToTokens(planck, tokenDecimals) {
|
275
|
+
if (typeof planck !== "string" || typeof tokenDecimals !== "number") return;
|
276
|
+
const base = 10;
|
277
|
+
const exponent = -1 * tokenDecimals;
|
278
|
+
const multiplier = base ** exponent;
|
279
|
+
return new BigNumber__default.default(planck).multipliedBy(multiplier).toString(10);
|
280
|
+
}
|
281
|
+
|
282
|
+
/**
|
283
|
+
* Turns a value into a {@link ReplaySubject} of size 1.
|
284
|
+
*
|
285
|
+
* If the value is already a {@link ReplaySubject}, it will be returned as-is.
|
286
|
+
*
|
287
|
+
* If the value is a {@link Promise}, it will be awaited,
|
288
|
+
* and the awaited value will be published into the {@link ReplaySubject} when it becomes available.
|
289
|
+
*
|
290
|
+
* For any other type of value, it will be immediately published into the {@link ReplaySubject}.
|
291
|
+
*/
|
292
|
+
const replaySubjectFrom = initialValue => {
|
293
|
+
if (initialValue instanceof rxjs.ReplaySubject) return initialValue;
|
294
|
+
const subject = new rxjs.ReplaySubject(1);
|
295
|
+
|
296
|
+
// if initialValue is a promise, await it and then call `subject.next()` with the awaited value
|
297
|
+
if (isPromise(initialValue)) {
|
298
|
+
initialValue.then(value => subject.next(value), error => subject.error(error));
|
299
|
+
return subject;
|
300
|
+
}
|
301
|
+
|
302
|
+
// if initialValue is not a promise, immediately call `subject.next()` with the value
|
303
|
+
subject.next(initialValue);
|
304
|
+
return subject;
|
305
|
+
};
|
306
|
+
|
307
|
+
const sleep = ms => new Promise(resolve => {
|
308
|
+
setTimeout(resolve, ms);
|
309
|
+
});
|
310
|
+
|
311
|
+
/**
|
312
|
+
* Takes a subject and splits it into two parts:
|
313
|
+
*
|
314
|
+
* 1. A function to submit new values into the subject.
|
315
|
+
* 2. An observable for subscribing to new values from the subject.
|
316
|
+
*
|
317
|
+
* This can be helpful when, to avoid bugs, you want to expose only one
|
318
|
+
* of these parts to external code and keep the other part private.
|
319
|
+
*/
|
320
|
+
function splitSubject(subject) {
|
321
|
+
const next = value => subject.next(value);
|
322
|
+
const observable = subject.asObservable();
|
323
|
+
return [next, observable];
|
324
|
+
}
|
325
|
+
|
326
|
+
const throwAfter = (ms, reason) => new Promise((_, reject) => setTimeout(() => reject(new Error(reason)), ms));
|
327
|
+
|
328
|
+
function tokensToPlanck(tokens, tokenDecimals) {
|
329
|
+
if (typeof tokens !== "string" || typeof tokenDecimals !== "number") return;
|
330
|
+
const base = 10;
|
331
|
+
const exponent = tokenDecimals;
|
332
|
+
const multiplier = base ** exponent;
|
333
|
+
return new BigNumber__default.default(tokens).multipliedBy(multiplier).toString(10);
|
334
|
+
}
|
335
|
+
|
336
|
+
/**
|
337
|
+
* @name validateHexString
|
338
|
+
* @description Checks if a string is a hex string. Required to account for type differences between different polkadot libraries
|
339
|
+
* @param {string} str - string to check
|
340
|
+
* @returns {`0x${string}`} - boolean
|
341
|
+
* @example
|
342
|
+
* validateHexString("0x1234") // "0x1234"
|
343
|
+
* validateHexString("1234") // Error: Expected a hex string
|
344
|
+
* validateHexString(1234) // Error: Expected a string
|
345
|
+
**/
|
346
|
+
const validateHexString = str => {
|
347
|
+
if (typeof str !== "string") {
|
348
|
+
throw new Error("Expected a string");
|
349
|
+
}
|
350
|
+
if (str.startsWith("0x")) {
|
351
|
+
return str;
|
352
|
+
}
|
353
|
+
throw new Error("Expected a hex string");
|
354
|
+
};
|
355
|
+
|
356
|
+
// Designed to be serializable as it can be sent to the frontend
|
357
|
+
|
358
|
+
function getLoadable$(factory, options = {}) {
|
359
|
+
const {
|
360
|
+
getError,
|
361
|
+
refreshInterval
|
362
|
+
} = options;
|
363
|
+
const createLoadableStream = () => rxjs.from(factory()).pipe(rxjs.map(data => ({
|
364
|
+
status: "success",
|
365
|
+
data
|
366
|
+
})), rxjs.catchError(error => rxjs.of({
|
367
|
+
status: "error",
|
368
|
+
error: getError ? getError(error) : getGenericError(error)
|
369
|
+
})));
|
370
|
+
const source$ = refreshInterval ? rxjs.timer(0, refreshInterval).pipe(rxjs.switchMap(() => createLoadableStream())) : createLoadableStream();
|
371
|
+
return source$.pipe(rxjs.startWith({
|
372
|
+
status: "loading"
|
373
|
+
}));
|
374
|
+
}
|
375
|
+
const getGenericError = error => ({
|
376
|
+
name: "Error",
|
377
|
+
message: getGenericErrorMessage(error)
|
378
|
+
});
|
379
|
+
const getGenericErrorMessage = error => {
|
380
|
+
if (typeof error === "string") {
|
381
|
+
return error;
|
382
|
+
} else if (error instanceof Error) {
|
383
|
+
return error.message;
|
384
|
+
} else if (error && typeof error === "object" && "message" in error) {
|
385
|
+
return error.message;
|
386
|
+
}
|
387
|
+
return String(error) || "Unknown error";
|
385
388
|
};
|
386
389
|
|
387
390
|
exports.BigMath = BigMath;
|
@@ -389,33 +392,29 @@ exports.Deferred = Deferred;
|
|
389
392
|
exports.MAX_DECIMALS_FORMAT = MAX_DECIMALS_FORMAT;
|
390
393
|
exports.REGEX_HEX_STRING = REGEX_HEX_STRING;
|
391
394
|
exports.addTrailingSlash = addTrailingSlash;
|
392
|
-
exports.blake2Concat = blake2Concat;
|
393
395
|
exports.classNames = classNames;
|
394
|
-
exports.
|
395
|
-
exports.decodeAnyAddress = decodeAnyAddress;
|
396
|
-
exports.decodeSs58Format = decodeSs58Format;
|
397
|
-
exports.encodeAnyAddress = encodeAnyAddress;
|
396
|
+
exports.cn = cn;
|
398
397
|
exports.firstThenDebounce = firstThenDebounce;
|
399
398
|
exports.formatDecimals = formatDecimals;
|
400
399
|
exports.formatPrice = formatPrice;
|
400
|
+
exports.getLoadable$ = getLoadable$;
|
401
401
|
exports.getSharedObservable = getSharedObservable;
|
402
402
|
exports.hasOwnProperty = hasOwnProperty;
|
403
403
|
exports.isAbortError = isAbortError;
|
404
|
-
exports.isAddressEqual = isAddressEqual;
|
405
404
|
exports.isArrayOf = isArrayOf;
|
406
405
|
exports.isAscii = isAscii;
|
407
406
|
exports.isBigInt = isBigInt;
|
408
407
|
exports.isBooleanTrue = isBooleanTrue;
|
409
|
-
exports.isEthereumAddress = isEthereumAddress;
|
410
408
|
exports.isHexString = isHexString;
|
411
409
|
exports.isNotNil = isNotNil;
|
410
|
+
exports.isPromise = isPromise;
|
411
|
+
exports.isSubject = isSubject;
|
412
412
|
exports.isTruthy = isTruthy;
|
413
|
-
exports.isValidSubstrateAddress = isValidSubstrateAddress;
|
414
413
|
exports.keepAlive = keepAlive;
|
415
|
-
exports.normalizeAddress = normalizeAddress;
|
416
414
|
exports.planckToTokens = planckToTokens;
|
415
|
+
exports.replaySubjectFrom = replaySubjectFrom;
|
417
416
|
exports.sleep = sleep;
|
417
|
+
exports.splitSubject = splitSubject;
|
418
418
|
exports.throwAfter = throwAfter;
|
419
419
|
exports.tokensToPlanck = tokensToPlanck;
|
420
|
-
exports.twox64Concat = twox64Concat;
|
421
420
|
exports.validateHexString = validateHexString;
|