@talismn/util 1.1.0 → 2.0.0

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/index.js CHANGED
@@ -1,493 +1,937 @@
1
- "use strict";
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
7
  var __getProtoOf = Object.getPrototypeOf;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from2, except, desc) => {
13
- if (from2 && typeof from2 === "object" || typeof from2 === "function") {
14
- for (let key of __getOwnPropNames(from2))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- BigMath: () => BigMath,
34
- Deferred: () => Deferred,
35
- MAX_DECIMALS_FORMAT: () => MAX_DECIMALS_FORMAT,
36
- REGEX_HEX_STRING: () => REGEX_HEX_STRING,
37
- addTrailingSlash: () => addTrailingSlash,
38
- firstThenDebounce: () => firstThenDebounce,
39
- formatDecimals: () => formatDecimals,
40
- formatPrice: () => formatPrice,
41
- getLoadable$: () => getLoadable$,
42
- getLoadableQuery$: () => getLoadableQuery$,
43
- getQuery$: () => getQuery$,
44
- getSharedObservable: () => getSharedObservable,
45
- hasOwnProperty: () => hasOwnProperty,
46
- isAbortError: () => isAbortError,
47
- isArrayOf: () => isArrayOf,
48
- isAscii: () => isAscii,
49
- isBigInt: () => isBigInt,
50
- isBooleanTrue: () => isBooleanTrue,
51
- isErrorOfName: () => isErrorOfName,
52
- isHexString: () => isHexString,
53
- isNotNil: () => isNotNil,
54
- isPromise: () => isPromise,
55
- isSubject: () => isSubject,
56
- isTruthy: () => isTruthy,
57
- keepAlive: () => keepAlive,
58
- planckToTokens: () => planckToTokens,
59
- replaySubjectFrom: () => replaySubjectFrom,
60
- sleep: () => sleep,
61
- splitSubject: () => splitSubject,
62
- stripHexPrefix: () => stripHexPrefix,
63
- throwAfter: () => throwAfter,
64
- tokensToPlanck: () => tokensToPlanck,
65
- validateHexString: () => validateHexString
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let bignumber_js = require("bignumber.js");
25
+ bignumber_js = __toESM(bignumber_js);
26
+ let lodash_es = require("lodash-es");
27
+ let rxjs = require("rxjs");
28
+ //#region src/configureBigNumber.ts
29
+ bignumber_js.default.set({ STRICT: false });
30
+ var configureBigNumber_default = bignumber_js.default;
31
+ //#endregion
32
+ //#region src/addTrailingSlash.ts
33
+ const addTrailingSlash = (url) => {
34
+ if (url.endsWith("/")) return url;
35
+ return `${url}/`;
36
+ };
37
+ //#endregion
38
+ //#region src/assert.ts
39
+ /**
40
+ * @name assert
41
+ * @description Throws an Error with the given message if the condition is falsy.
42
+ * @example
43
+ * assert(chain, "Chain not found")
44
+ **/
45
+ function assert(condition, message) {
46
+ if (condition) return;
47
+ throw new Error(typeof message === "function" ? message() : message);
48
+ }
49
+ //#endregion
50
+ //#region src/BigMath.ts
51
+ /**
52
+ * Javascript's `Math` library for `BigInt`.
53
+ * Taken from https://stackoverflow.com/questions/51867270/is-there-a-library-similar-to-math-that-supports-javascript-bigint/64953280#64953280
54
+ */
55
+ const BigMath = {
56
+ abs(x) {
57
+ return x < 0n ? -x : x;
58
+ },
59
+ sign(x) {
60
+ if (x === 0n) return 0n;
61
+ return x < 0n ? -1n : 1n;
62
+ },
63
+ min(value, ...values) {
64
+ for (const v of values) if (v < value) value = v;
65
+ return value;
66
+ },
67
+ max(value, ...values) {
68
+ for (const v of values) if (v > value) value = v;
69
+ return value;
70
+ }
71
+ };
72
+ //#endregion
73
+ //#region src/isHexString.ts
74
+ const REGEX_HEX_STRING = /^0x[0-9a-fA-F]*$/;
75
+ const isHexString = (value) => {
76
+ return typeof value === "string" && REGEX_HEX_STRING.test(value);
77
+ };
78
+ //#endregion
79
+ //#region src/bytes.ts
80
+ /**
81
+ * Byte / hex primitives, drop-in equivalents of the `@polkadot/util` helpers we used to depend on.
82
+ * Semantics intentionally match polkadot-js for migration safety.
83
+ */
84
+ const hexToU8a = (hex) => {
85
+ if (!hex) return /* @__PURE__ */ new Uint8Array();
86
+ const value = hex.startsWith("0x") ? hex.slice(2) : hex;
87
+ const padded = value.length % 2 ? `${value}0` : value;
88
+ const result = new Uint8Array(padded.length / 2);
89
+ for (let i = 0; i < result.length; i++) result[i] = parseInt(padded.substring(i * 2, i * 2 + 2), 16);
90
+ return result;
91
+ };
92
+ const u8aToHex = (value) => {
93
+ if (!value?.length) return "0x";
94
+ let hex = "";
95
+ for (const byte of value) hex += byte.toString(16).padStart(2, "0");
96
+ return `0x${hex}`;
97
+ };
98
+ const stringToU8a = (value) => value ? new TextEncoder().encode(value) : /* @__PURE__ */ new Uint8Array();
99
+ const u8aToString = (value) => value?.length ? new TextDecoder("utf-8").decode(value) : "";
100
+ const hexToString = (hex) => u8aToString(hexToU8a(hex));
101
+ const hexToNumber = (hex) => hex ? parseInt(hex, 16) : NaN;
102
+ const numberToU8a = (value) => {
103
+ let hex = (value ?? 0).toString(16);
104
+ if (hex.length % 2) hex = `0${hex}`;
105
+ return hexToU8a(hex);
106
+ };
107
+ /** Coerces hex strings, utf-8 strings, number arrays and buffers to Uint8Array (polkadot-js semantics) */
108
+ const u8aToU8a = (value) => {
109
+ if (!value) return /* @__PURE__ */ new Uint8Array();
110
+ if (value instanceof Uint8Array) return value;
111
+ if (Array.isArray(value)) return new Uint8Array(value);
112
+ return isHexString(value) ? hexToU8a(value) : stringToU8a(value);
113
+ };
114
+ const u8aConcat = (...items) => {
115
+ const chunks = items.map((item) => u8aToU8a(item));
116
+ const result = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.length, 0));
117
+ let offset = 0;
118
+ for (const chunk of chunks) {
119
+ result.set(chunk, offset);
120
+ offset += chunk.length;
121
+ }
122
+ return result;
123
+ };
124
+ const u8aEq = (a, b) => {
125
+ const u8aa = u8aToU8a(a);
126
+ const u8ab = u8aToU8a(b);
127
+ if (u8aa.length !== u8ab.length) return false;
128
+ return u8aa.every((byte, i) => byte === u8ab[i]);
129
+ };
130
+ const u8aCmp = (a, b) => {
131
+ const u8aa = u8aToU8a(a);
132
+ const u8ab = u8aToU8a(b);
133
+ for (let i = 0; i < Math.max(u8aa.length, u8ab.length); i++) {
134
+ const byteA = u8aa[i] ?? 0;
135
+ const byteB = u8ab[i] ?? 0;
136
+ if (byteA !== byteB) return byteA < byteB ? -1 : 1;
137
+ }
138
+ return u8aa.length === u8ab.length ? 0 : u8aa.length < u8ab.length ? -1 : 1;
139
+ };
140
+ /**
141
+ * Tests if the input is printable ASCII (code points 32-126). Hex strings are decoded to bytes
142
+ * first, other strings are checked character-wise (polkadot-js `isAscii` semantics).
143
+ */
144
+ const isAsciiPrintable = (value) => {
145
+ if (value == null) return false;
146
+ return (typeof value === "string" && !isHexString(value) ? stringToU8a(value) : u8aToU8a(value)).every((b) => b >= 32 && b <= 126);
147
+ };
148
+ const U8A_WRAP_PREFIX = stringToU8a("<Bytes>");
149
+ const U8A_WRAP_POSTFIX = stringToU8a("</Bytes>");
150
+ const u8aIsWrapped = (value) => value.length >= U8A_WRAP_PREFIX.length + U8A_WRAP_POSTFIX.length && u8aEq(value.subarray(0, U8A_WRAP_PREFIX.length), U8A_WRAP_PREFIX) && u8aEq(value.subarray(value.length - U8A_WRAP_POSTFIX.length), U8A_WRAP_POSTFIX);
151
+ /** Wraps bytes with `<Bytes>...</Bytes>` for raw-message signing, unless already wrapped */
152
+ const u8aWrapBytes = (value) => {
153
+ const u8a = u8aToU8a(value);
154
+ return u8aIsWrapped(u8a) ? u8a : u8aConcat(U8A_WRAP_PREFIX, u8a, U8A_WRAP_POSTFIX);
155
+ };
156
+ const u8aUnwrapBytes = (value) => {
157
+ const u8a = u8aToU8a(value);
158
+ return u8aIsWrapped(u8a) ? u8a.subarray(U8A_WRAP_PREFIX.length, u8a.length - U8A_WRAP_POSTFIX.length) : u8a;
159
+ };
160
+ //#endregion
161
+ //#region src/jsActivityHook.ts
162
+ const reportJsActivity = (label, durationMs) => {
163
+ const record = globalThis.__recordJsActivity;
164
+ if (record) record(label, durationMs);
165
+ };
166
+ //#endregion
167
+ //#region src/yieldToEventLoop.ts
168
+ const yieldToEventLoop = () => {
169
+ if (typeof MessageChannel !== "undefined") return new Promise((resolve) => {
170
+ const channel = new MessageChannel();
171
+ const port1 = channel.port1;
172
+ const port2 = channel.port2;
173
+ port1.onmessage = () => {
174
+ port1.close();
175
+ port2.close();
176
+ resolve();
177
+ };
178
+ port2.postMessage(null);
179
+ });
180
+ return new Promise((resolve) => setTimeout(resolve, 0));
181
+ };
182
+ //#endregion
183
+ //#region src/timeSlicer.ts
184
+ /**
185
+ * Default CPU budget for a single synchronous slice of chunked work.
186
+ * ~50-60% of a 60fps frame, leaving the rest for the host (user interactions, rendering).
187
+ */
188
+ const DEFAULT_TIME_SLICE_BUDGET_MS = 10;
189
+ /**
190
+ * Creates an AbortError-style error without relying on DOMException (not available on Hermes).
191
+ * Recognized by `isAbortError` from this package.
192
+ */
193
+ const newAbortError = () => Object.assign(/* @__PURE__ */ new Error("Aborted"), { name: "AbortError" });
194
+ const defaultNow = typeof performance !== "undefined" ? () => performance.now() : () => Date.now();
195
+ /**
196
+ * Tracks a time budget for cooperative scheduling: run synchronous work until the budget
197
+ * for the current slice is exhausted, then yield the thread back to the host event loop
198
+ * before continuing.
199
+ *
200
+ * A single slicer can be shared across multiple phases of work so the budget spans them.
201
+ */
202
+ const createTimeSlicer = ({ budgetMs = 10, signal, now = defaultNow, label } = {}) => {
203
+ let sliceStart = now();
204
+ const throwIfAborted = () => {
205
+ if (signal?.aborted) throw newAbortError();
206
+ };
207
+ const shouldYield = () => now() - sliceStart >= budgetMs;
208
+ const doYield = async () => {
209
+ const elapsed = now() - sliceStart;
210
+ if (elapsed >= budgetMs * 3) reportJsActivity(`timeSlicer over-budget slice${label ? ` (${label})` : ""}`, elapsed);
211
+ await yieldToEventLoop();
212
+ sliceStart = now();
213
+ throwIfAborted();
214
+ };
215
+ return {
216
+ signal,
217
+ shouldYield,
218
+ yield: doYield,
219
+ yieldIfNeeded: () => {
220
+ throwIfAborted();
221
+ return shouldYield() ? doYield() : void 0;
222
+ },
223
+ throwIfAborted
224
+ };
225
+ };
226
+ //#endregion
227
+ //#region src/chunkedArray.ts
228
+ const getSlicer = (options) => options?.slicer ?? createTimeSlicer({
229
+ budgetMs: options?.budgetMs,
230
+ signal: options?.signal,
231
+ label: options?.label
66
232
  });
67
- module.exports = __toCommonJS(index_exports);
68
-
69
- // src/configureBigNumber.ts
70
- var import_bignumber = __toESM(require("bignumber.js"));
71
- import_bignumber.default.set({ STRICT: false });
72
- var configureBigNumber_default = import_bignumber.default;
73
-
74
- // src/addTrailingSlash.ts
75
- var addTrailingSlash = (url) => {
76
- if (url.endsWith("/")) {
77
- return url;
78
- }
79
- return `${url}/`;
233
+ /**
234
+ * `Array.prototype.forEach`, chunked: iterates synchronously until the time budget is
235
+ * exhausted, then yields the thread to the host event loop before continuing.
236
+ *
237
+ * Errors thrown by `fn` reject the promise; aborting rejects with an AbortError at the
238
+ * next between-items check point.
239
+ */
240
+ const forEachWithYield = async (items, fn, options) => {
241
+ const slicer = getSlicer(options);
242
+ for (let i = 0; i < items.length; i++) {
243
+ const yielded = slicer.yieldIfNeeded();
244
+ if (yielded) await yielded;
245
+ fn(items[i], i);
246
+ }
247
+ const yielded = slicer.yieldIfNeeded();
248
+ if (yielded) await yielded;
80
249
  };
81
-
82
- // src/BigMath.ts
83
- var BigMath = {
84
- abs(x) {
85
- return x < 0n ? -x : x;
86
- },
87
- sign(x) {
88
- if (x === 0n) return 0n;
89
- return x < 0n ? -1n : 1n;
90
- },
91
- // TODO: Improve our babel/tsc config to let us use the `**` operator on bigint values.
92
- // Error thrown: Exponentiation cannot be performed on 'bigint' values unless the 'target' option is set to 'es2016' or later. ts(2791)
93
- // pow(base: bigint, exponent: bigint) {
94
- // return base ** exponent
95
- // },
96
- min(value, ...values) {
97
- for (const v of values) if (v < value) value = v;
98
- return value;
99
- },
100
- max(value, ...values) {
101
- for (const v of values) if (v > value) value = v;
102
- return value;
103
- }
250
+ /** `Array.prototype.map`, chunked (see forEachWithYield for semantics) */
251
+ const mapWithYield = async (items, fn, options) => {
252
+ const results = new Array(items.length);
253
+ await forEachWithYield(items, (item, i) => results[i] = fn(item, i), options);
254
+ return results;
104
255
  };
105
-
106
- // src/deferred.ts
256
+ /** lodash `keyBy`, chunked (see forEachWithYield for semantics) */
257
+ const keyByWithYield = async (items, keyFn, options) => {
258
+ const result = {};
259
+ await forEachWithYield(items, (item, i) => result[keyFn(item, i)] = item, options);
260
+ return result;
261
+ };
262
+ /**
263
+ * Chunked equivalent of lodash `isEqual(a, b)` for arrays: `a === b` fast path, length
264
+ * check, then per-item `a[i] === b[i] || isItemEqual(a[i], b[i])` within the time budget.
265
+ * The result is identical to `isEqual(a, b)`.
266
+ */
267
+ const arrayItemsEqualWithYield = async (a, b, options) => {
268
+ if (a === b) return true;
269
+ if (!a || !b) return false;
270
+ if (a.length !== b.length) return false;
271
+ const isItemEqual = options?.isItemEqual ?? lodash_es.isEqual;
272
+ const slicer = getSlicer(options);
273
+ for (let i = 0; i < a.length; i++) {
274
+ const yielded = slicer.yieldIfNeeded();
275
+ if (yielded) await yielded;
276
+ if (a[i] !== b[i] && !isItemEqual(a[i], b[i])) return false;
277
+ }
278
+ return true;
279
+ };
280
+ //#endregion
281
+ //#region src/deferred.ts
282
+ /**
283
+ * In TypeScript, a deferred promise refers to a pattern that involves creating a promise that can be
284
+ * resolved or rejected at a later point in time, typically by code outside of the current function scope.
285
+ *
286
+ * This pattern is often used when dealing with asynchronous operations that involve multiple steps or when
287
+ * the result of an operation cannot be immediately determined.
288
+ */
107
289
  function Deferred() {
108
- let resolve;
109
- let reject;
110
- let isPending = true;
111
- let isResolved = false;
112
- let isRejected = false;
113
- const promise = new Promise((innerResolve, innerReject) => {
114
- resolve = (value) => {
115
- isPending = false;
116
- isResolved = true;
117
- innerResolve(value);
118
- };
119
- reject = (reason) => {
120
- isPending = false;
121
- isRejected = true;
122
- innerReject(reason);
123
- };
124
- });
125
- return {
126
- promise,
127
- resolve,
128
- reject,
129
- isPending: () => isPending,
130
- isResolved: () => isResolved,
131
- isRejected: () => isRejected
132
- };
290
+ let resolve;
291
+ let reject;
292
+ let isPending = true;
293
+ let isResolved = false;
294
+ let isRejected = false;
295
+ return {
296
+ promise: new Promise((innerResolve, innerReject) => {
297
+ resolve = (value) => {
298
+ isPending = false;
299
+ isResolved = true;
300
+ innerResolve(value);
301
+ };
302
+ reject = (reason) => {
303
+ isPending = false;
304
+ isRejected = true;
305
+ innerReject(reason);
306
+ };
307
+ }),
308
+ resolve,
309
+ reject,
310
+ isPending: () => isPending,
311
+ isResolved: () => isResolved,
312
+ isRejected: () => isRejected
313
+ };
133
314
  }
134
-
135
- // src/firstThenDebounce.ts
136
- var import_rxjs = require("rxjs");
137
- var firstThenDebounce = (timeout) => (source) => (0, import_rxjs.concat)(source.pipe((0, import_rxjs.take)(1)), source.pipe((0, import_rxjs.skip)(1)).pipe((0, import_rxjs.debounceTime)(timeout)));
138
-
139
- // src/formatDecimals.ts
140
- var MIN_DIGITS = 4;
141
- var MAX_DECIMALS_FORMAT = 12;
142
- var formatDecimals = (num, digits = MIN_DIGITS, options = {}, locale = "en-US") => {
143
- if (num === null || num === void 0) return "";
144
- if (digits < MIN_DIGITS) digits = MIN_DIGITS;
145
- const value = new configureBigNumber_default(num);
146
- const minDisplayVal = 1 / 10 ** digits;
147
- if (value.gt(0) && value.lt(minDisplayVal)) return `< ${formatDecimals(minDisplayVal)}`;
148
- const flooredValue = value.integerValue();
149
- const intDigits = flooredValue.isEqualTo(0) ? 0 : flooredValue.toString().length;
150
- let truncatedValue = value;
151
- const excessFractionDigitsPow10 = new configureBigNumber_default(10).pow(
152
- digits > intDigits ? digits - intDigits : 0
153
- );
154
- truncatedValue = truncatedValue.multipliedBy(excessFractionDigitsPow10).integerValue().dividedBy(excessFractionDigitsPow10);
155
- const excessIntegerDigits = new configureBigNumber_default(intDigits > digits ? intDigits - digits : 0);
156
- const excessIntegerDigitsPow10 = new configureBigNumber_default(10).pow(excessIntegerDigits);
157
- if (excessIntegerDigits.gt(0))
158
- truncatedValue = truncatedValue.dividedBy(excessIntegerDigitsPow10).integerValue().multipliedBy(excessIntegerDigitsPow10);
159
- return Intl.NumberFormat(locale, {
160
- // compact notation (K, M, B) if above 9999
161
- notation: truncatedValue.abs().gt(9999) ? "compact" : "standard",
162
- // NOTE: possible values are from `0` to `21`
163
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#maximumsignificantdigits
164
- maximumSignificantDigits: Math.max(1, Math.min(digits + (truncatedValue.lt(1) ? 1 : 0), 21)),
165
- ...options
166
- }).format(truncatedValue.toNumber());
315
+ //#endregion
316
+ //#region src/firstThenDebounce.ts
317
+ /**
318
+ * An rxjs operator which:
319
+ *
320
+ * 1. Emits the first value it receives from the source observable, then:
321
+ * 2. Debounces any future values by `timeout` ms.
322
+ */
323
+ const firstThenDebounce = (timeout) => (source) => (0, rxjs.concat)(source.pipe((0, rxjs.take)(1)), source.pipe((0, rxjs.skip)(1)).pipe((0, rxjs.debounceTime)(timeout)));
324
+ //#endregion
325
+ //#region src/formatDecimals.ts
326
+ const MIN_DIGITS = 4;
327
+ const MAX_DECIMALS_FORMAT = 12;
328
+ /**
329
+ * Custom decimal number formatting for Talisman
330
+ * note that the NumberFormat().format() call is the ressource heavy part, it's not worth trying to optimize other parts
331
+ * @param num input number
332
+ * @param digits number of significant digits to display
333
+ * @param locale locale used to format the number
334
+ * @param options formatting options
335
+ * @returns the formatted value
336
+ */
337
+ const formatDecimals = (num, digits = MIN_DIGITS, options = {}, locale = "en-US") => {
338
+ if (num === null || num === void 0) return "";
339
+ if (digits < MIN_DIGITS) digits = MIN_DIGITS;
340
+ const value = new configureBigNumber_default(num);
341
+ const minDisplayVal = 1 / 10 ** digits;
342
+ if (value.gt(0) && value.lt(minDisplayVal)) return `< ${formatDecimals(minDisplayVal)}`;
343
+ const flooredValue = value.integerValue();
344
+ const intDigits = flooredValue.isEqualTo(0) ? 0 : flooredValue.toString().length;
345
+ let truncatedValue = value;
346
+ const excessFractionDigitsPow10 = new configureBigNumber_default(10).pow(digits > intDigits ? digits - intDigits : 0);
347
+ truncatedValue = truncatedValue.multipliedBy(excessFractionDigitsPow10).integerValue().dividedBy(excessFractionDigitsPow10);
348
+ const excessIntegerDigits = new configureBigNumber_default(intDigits > digits ? intDigits - digits : 0);
349
+ const excessIntegerDigitsPow10 = new configureBigNumber_default(10).pow(excessIntegerDigits);
350
+ if (excessIntegerDigits.gt(0)) truncatedValue = truncatedValue.dividedBy(excessIntegerDigitsPow10).integerValue().multipliedBy(excessIntegerDigitsPow10);
351
+ return Intl.NumberFormat(locale, {
352
+ notation: truncatedValue.abs().gt(9999) ? "compact" : "standard",
353
+ maximumSignificantDigits: Math.max(1, Math.min(digits + (truncatedValue.lt(1) ? 1 : 0), 21)),
354
+ ...options
355
+ }).format(truncatedValue.toNumber());
167
356
  };
168
-
169
- // src/formatPrice.ts
170
- var formatPrice = (price, currency, compact) => {
171
- return Intl.NumberFormat(void 0, {
172
- style: "currency",
173
- currency,
174
- currencyDisplay: currency === "usd" ? "narrowSymbol" : "symbol",
175
- minimumSignificantDigits: 3,
176
- maximumSignificantDigits: compact ? price < 1 ? 3 : 4 : void 0,
177
- roundingPriority: compact ? "auto" : "morePrecision",
178
- notation: compact ? "compact" : "standard"
179
- }).format(price);
357
+ //#endregion
358
+ //#region src/formatPrice.ts
359
+ const formatPrice = (price, currency, compact) => {
360
+ return Intl.NumberFormat(void 0, {
361
+ style: "currency",
362
+ currency,
363
+ currencyDisplay: currency === "usd" ? "narrowSymbol" : "symbol",
364
+ minimumSignificantDigits: 3,
365
+ maximumSignificantDigits: compact ? price < 1 ? 3 : 4 : void 0,
366
+ roundingPriority: compact ? "auto" : "morePrecision",
367
+ notation: compact ? "compact" : "standard"
368
+ }).format(price);
180
369
  };
181
-
182
- // src/getLoadable.ts
183
- var import_rxjs2 = require("rxjs");
370
+ //#endregion
371
+ //#region src/getLoadable.ts
184
372
  function getLoadable$(factory, options = {}) {
185
- const { getError, refreshInterval } = options;
186
- const createLoadableStream = () => (0, import_rxjs2.from)(factory()).pipe(
187
- (0, import_rxjs2.map)(
188
- (data) => ({
189
- status: "success",
190
- data
191
- })
192
- ),
193
- (0, import_rxjs2.catchError)(
194
- (error) => (0, import_rxjs2.of)({
195
- status: "error",
196
- error: getError ? getError(error) : getGenericError(error)
197
- })
198
- )
199
- );
200
- const source$ = refreshInterval ? (0, import_rxjs2.timer)(0, refreshInterval).pipe((0, import_rxjs2.switchMap)(() => createLoadableStream())) : createLoadableStream();
201
- return source$.pipe(
202
- (0, import_rxjs2.startWith)({
203
- status: "loading"
204
- })
205
- );
373
+ const { getError, refreshInterval } = options;
374
+ const createLoadableStream = () => (0, rxjs.from)(factory()).pipe((0, rxjs.map)((data) => ({
375
+ status: "success",
376
+ data
377
+ })), (0, rxjs.catchError)((error) => (0, rxjs.of)({
378
+ status: "error",
379
+ error: getError ? getError(error) : getGenericError(error)
380
+ })));
381
+ return (refreshInterval ? (0, rxjs.timer)(0, refreshInterval).pipe((0, rxjs.switchMap)(() => createLoadableStream())) : createLoadableStream()).pipe((0, rxjs.startWith)({ status: "loading" }));
206
382
  }
207
- var getGenericError = (error) => ({
208
- name: "Error",
209
- message: getGenericErrorMessage(error)
383
+ const getGenericError = (error) => ({
384
+ name: "Error",
385
+ message: getGenericErrorMessage(error)
210
386
  });
211
- var getGenericErrorMessage = (error) => {
212
- if (typeof error === "string") {
213
- return error;
214
- } else if (error instanceof Error) {
215
- return error.message;
216
- } else if (error && typeof error === "object" && "message" in error) {
217
- return error.message;
218
- }
219
- return String(error) || "Unknown error";
387
+ const getGenericErrorMessage = (error) => {
388
+ if (typeof error === "string") return error;
389
+ else if (error instanceof Error) return error.message;
390
+ else if (error && typeof error === "object" && "message" in error) return error.message;
391
+ return String(error) || "Unknown error";
220
392
  };
221
-
222
- // src/getLoadableQuery.ts
223
- var import_rxjs5 = require("rxjs");
224
-
225
- // src/getQuery.ts
226
- var import_lodash_es = require("lodash-es");
227
- var import_rxjs4 = require("rxjs");
228
-
229
- // src/getSharedObservable.ts
230
- var import_rxjs3 = require("rxjs");
231
- var CACHE = /* @__PURE__ */ new Map();
232
- var getSharedObservable = (namespace, args, createObservable, serializer = (args2) => JSON.stringify(args2)) => {
233
- const cacheKey = `${namespace}:${serializer(args)}`;
234
- if (CACHE.has(cacheKey)) return CACHE.get(cacheKey);
235
- const obs = createObservable(args);
236
- const sharedObs = obs.pipe((0, import_rxjs3.shareReplay)({ bufferSize: 1, refCount: true }));
237
- CACHE.set(cacheKey, sharedObs);
238
- return sharedObs;
393
+ //#endregion
394
+ //#region src/getSharedObservable.ts
395
+ const CACHE = /* @__PURE__ */ new Map();
396
+ /**
397
+ * How long an entry survives with no subscribers before being dropped. Long enough
398
+ * for quick unmount/remount cycles (navigation, react-rxjs Subscribe boundaries) to
399
+ * reuse the entry, short enough that abandoned scopes (e.g. superseded balance
400
+ * subscriptions after networks/accounts change) don't accumulate forever.
401
+ */
402
+ const CLEANUP_DELAY_MS = 6e4;
403
+ /**
404
+ * When using react-rxjs hooks and state observables, the options are used as weak map keys.
405
+ * This means that if the options object is recreated on each render, the observable will be recreated as well.
406
+ * 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
407
+ *
408
+ * Entries are reference-counted: an entry with no subscribers for CLEANUP_DELAY_MS is
409
+ * removed from the cache (its shareReplay source is already torn down by refCount at
410
+ * that point — only the replay buffer and the entry itself are dropped).
411
+ *
412
+ * @param namespace
413
+ * @param args
414
+ * @param createObservable
415
+ * @param serializer
416
+ * @returns
417
+ */
418
+ const getSharedObservable = (namespace, args, createObservable, serializer = (args) => JSON.stringify(args)) => {
419
+ const cacheKey = `${namespace}:${serializer(args)}`;
420
+ const cached = CACHE.get(cacheKey);
421
+ if (cached) return cached.observable;
422
+ const sharedObs = createObservable(args).pipe((0, rxjs.shareReplay)({
423
+ bufferSize: 1,
424
+ refCount: true
425
+ }));
426
+ const scheduleCleanup = (entry) => {
427
+ if (entry.cleanupTimer) clearTimeout(entry.cleanupTimer);
428
+ entry.cleanupTimer = setTimeout(() => {
429
+ if (entry.refCount === 0 && CACHE.get(cacheKey) === entry) CACHE.delete(cacheKey);
430
+ }, CLEANUP_DELAY_MS);
431
+ };
432
+ const entry = {
433
+ observable: null,
434
+ refCount: 0,
435
+ cleanupTimer: null
436
+ };
437
+ entry.observable = new rxjs.Observable((subscriber) => {
438
+ entry.refCount++;
439
+ if (entry.cleanupTimer) {
440
+ clearTimeout(entry.cleanupTimer);
441
+ entry.cleanupTimer = null;
442
+ }
443
+ const subscription = sharedObs.subscribe(subscriber);
444
+ return () => {
445
+ subscription.unsubscribe();
446
+ entry.refCount--;
447
+ if (entry.refCount === 0) scheduleCleanup(entry);
448
+ };
449
+ });
450
+ CACHE.set(cacheKey, entry);
451
+ scheduleCleanup(entry);
452
+ return entry.observable;
239
453
  };
240
-
241
- // src/getQuery.ts
242
- var getQuery$ = ({
243
- namespace,
244
- args,
245
- queryFn,
246
- defaultValue,
247
- refreshInterval,
248
- serializer = (args2) => JSON.stringify(args2)
249
- }) => {
250
- return getSharedObservable(
251
- namespace,
252
- args,
253
- () => new import_rxjs4.Observable((subscriber) => {
254
- const controller = new AbortController();
255
- const result = new import_rxjs4.BehaviorSubject({
256
- status: "loading",
257
- data: defaultValue,
258
- error: void 0
259
- });
260
- const sub = result.pipe((0, import_rxjs4.distinctUntilChanged)(import_lodash_es.isEqual)).subscribe(subscriber);
261
- let timeout = null;
262
- const run = () => {
263
- if (controller.signal.aborted) return;
264
- queryFn(args, controller.signal).then((data) => {
265
- if (controller.signal.aborted) return;
266
- result.next({ status: "loaded", data, error: void 0 });
267
- }).catch((error) => {
268
- if (controller.signal.aborted) return;
269
- result.next({ status: "error", data: void 0, error });
270
- }).finally(() => {
271
- if (controller.signal.aborted) return;
272
- if (refreshInterval) timeout = setTimeout(run, refreshInterval);
273
- });
274
- };
275
- run();
276
- return () => {
277
- sub.unsubscribe();
278
- if (timeout) clearTimeout(timeout);
279
- controller.abort(new Error("getQuery$ unsubscribed"));
280
- };
281
- }).pipe((0, import_rxjs4.shareReplay)({ refCount: true, bufferSize: 1 })),
282
- serializer
283
- );
454
+ //#endregion
455
+ //#region src/getQuery.ts
456
+ /**
457
+ * Creates a shared observable for executing queries with caching, loading states, and automatic refresh capabilities.
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * const userQuery$ = getQuery$({
462
+ * namespace: 'users',
463
+ * args: { userId: 123 },
464
+ * queryFn: async ({ userId }) => fetchUser(userId),
465
+ * defaultValue: null,
466
+ * refreshInterval: 30000
467
+ * });
468
+ *
469
+ * userQuery$.subscribe(result => {
470
+ * if (result.status === 'loaded') {
471
+ * console.log(result.data);
472
+ * }
473
+ * });
474
+ * ```
475
+ *
476
+ * @deprecated use getLoadableQuery$ instead
477
+ */
478
+ const getQuery$ = ({ namespace, args, queryFn, defaultValue, refreshInterval, serializer = (args) => JSON.stringify(args) }) => {
479
+ return getSharedObservable(namespace, args, () => new rxjs.Observable((subscriber) => {
480
+ const controller = new AbortController();
481
+ const result = new rxjs.BehaviorSubject({
482
+ status: "loading",
483
+ data: defaultValue,
484
+ error: void 0
485
+ });
486
+ const sub = result.pipe((0, rxjs.distinctUntilChanged)(lodash_es.isEqual)).subscribe(subscriber);
487
+ let timeout = null;
488
+ const run = () => {
489
+ if (controller.signal.aborted) return;
490
+ queryFn(args, controller.signal).then((data) => {
491
+ if (controller.signal.aborted) return;
492
+ result.next({
493
+ status: "loaded",
494
+ data,
495
+ error: void 0
496
+ });
497
+ }).catch((error) => {
498
+ if (controller.signal.aborted) return;
499
+ result.next({
500
+ status: "error",
501
+ data: void 0,
502
+ error
503
+ });
504
+ }).finally(() => {
505
+ if (controller.signal.aborted) return;
506
+ if (refreshInterval) timeout = setTimeout(run, refreshInterval);
507
+ });
508
+ };
509
+ run();
510
+ return () => {
511
+ sub.unsubscribe();
512
+ if (timeout) clearTimeout(timeout);
513
+ controller.abort(/* @__PURE__ */ new Error("getQuery$ unsubscribed"));
514
+ };
515
+ }).pipe((0, rxjs.shareReplay)({
516
+ refCount: true,
517
+ bufferSize: 1
518
+ })), serializer);
284
519
  };
285
-
286
- // src/getLoadableQuery.ts
287
- var getLoadableQuery$ = (params) => {
288
- const initial = params.defaultValue === void 0 ? [] : [{ status: "loading", data: params.defaultValue }];
289
- return getQuery$(params).pipe(
290
- (0, import_rxjs5.map)((val) => {
291
- switch (val.status) {
292
- case "loading":
293
- return { status: "loading", data: val.data };
294
- case "loaded":
295
- return { status: "success", data: val.data };
296
- case "error": {
297
- const err = val.error;
298
- return {
299
- status: "error",
300
- error: {
301
- name: err?.name ?? "QueryError",
302
- message: err?.message ?? "Failed to execute query"
303
- }
304
- };
305
- }
306
- }
307
- }),
308
- (0, import_rxjs5.startWith)(...initial)
309
- );
520
+ //#endregion
521
+ //#region src/getLoadableQuery.ts
522
+ /**
523
+ * Thin wrapper around getQuery$ that returns Loadable<T> and optionally
524
+ * primes the stream with a loading state using the provided default value.
525
+ *
526
+ * TODO: consolidate with getQuery$
527
+ */
528
+ const getLoadableQuery$ = (params) => {
529
+ const initial = params.defaultValue === void 0 ? [] : [{
530
+ status: "loading",
531
+ data: params.defaultValue
532
+ }];
533
+ return getQuery$(params).pipe((0, rxjs.map)((val) => {
534
+ switch (val.status) {
535
+ case "loading": return {
536
+ status: "loading",
537
+ data: val.data
538
+ };
539
+ case "loaded": return {
540
+ status: "success",
541
+ data: val.data
542
+ };
543
+ case "error": {
544
+ const err = val.error;
545
+ return {
546
+ status: "error",
547
+ error: {
548
+ name: err?.name ?? "QueryError",
549
+ message: err?.message ?? "Failed to execute query"
550
+ }
551
+ };
552
+ }
553
+ }
554
+ }), (0, rxjs.startWith)(...initial));
310
555
  };
311
-
312
- // src/hasOwnProperty.ts
556
+ //#endregion
557
+ //#region src/hasOwnProperty.ts
313
558
  function hasOwnProperty(obj, prop) {
314
- if (typeof obj !== "object") return false;
315
- if (obj === null) return false;
316
- return prop in obj;
559
+ if (typeof obj !== "object") return false;
560
+ if (obj === null) return false;
561
+ return prop in obj;
317
562
  }
318
-
319
- // src/isAbortError.ts
320
- var isAbortError = (error) => {
321
- return error instanceof Error && error.name === "AbortError";
563
+ //#endregion
564
+ //#region src/isAbortError.ts
565
+ const isAbortError = (error) => {
566
+ return error instanceof Error && error.name === "AbortError";
322
567
  };
323
-
324
- // src/isArrayOf.ts
568
+ //#endregion
569
+ //#region src/isArrayOf.ts
325
570
  function isArrayOf(array, func) {
326
- if (array.length > 0 && array[0] instanceof func) return true;
327
- return false;
571
+ if (array.length > 0 && array[0] instanceof func) return true;
572
+ return false;
328
573
  }
329
-
330
- // src/isAscii.ts
331
- var isAscii = (str) => {
332
- return [...str].every((char) => char.charCodeAt(0) <= 127);
574
+ //#endregion
575
+ //#region src/isAscii.ts
576
+ const isAscii = (str) => {
577
+ return [...str].every((char) => char.charCodeAt(0) <= 127);
333
578
  };
334
-
335
- // src/isBigInt.ts
336
- var isBigInt = (value) => typeof value === "bigint";
337
-
338
- // src/isBooleanTrue.ts
339
- var isBooleanTrue = (x) => !!x;
340
-
341
- // src/isErrorOfName.ts
342
- var isErrorOfName = (error, ...names) => error instanceof Error && names.includes(error.name);
343
-
344
- // src/isHexString.ts
345
- var REGEX_HEX_STRING = /^0x[0-9a-fA-F]*$/;
346
- var isHexString = (value) => {
347
- return typeof value === "string" && REGEX_HEX_STRING.test(value);
348
- };
349
-
350
- // src/isNotNil.ts
351
- var isNotNil = (value) => value !== null && value !== void 0;
352
-
353
- // src/isPromise.ts
354
- var isPromise = (value) => !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
355
-
356
- // src/isSubject.ts
357
- var import_rxjs6 = require("rxjs");
579
+ //#endregion
580
+ //#region src/isBigInt.ts
581
+ const isBigInt = (value) => typeof value === "bigint";
582
+ //#endregion
583
+ //#region src/isBooleanTrue.ts
584
+ const isBooleanTrue = (x) => !!x;
585
+ //#endregion
586
+ //#region src/isErrorOfName.ts
587
+ /**
588
+ * Robust replacement for `error instanceof SomeErrorClass` when the class comes from a
589
+ * package that gets bundled into multiple chunks/contexts (e.g. viem, @solana/web3.js).
590
+ *
591
+ * `instanceof` returns `false` whenever the error originates from a different bundled copy of
592
+ * the module than the imported class reference — which silently broke Solana transfers (see
593
+ * apps/extension/src/__tests__/no-instanceof-bundled-class.test.ts). An error's `.name` is
594
+ * stable across copies, *provided the class sets it explicitly* (viem does:
595
+ * `super({ name: 'ContractFunctionExecutionError' })`). For classes that don't set `.name`,
596
+ * duck-type the shape instead.
597
+ */
598
+ const isErrorOfName = (error, ...names) => error instanceof Error && names.includes(error.name);
599
+ //#endregion
600
+ //#region src/isNotNil.ts
601
+ /**
602
+ * WARNING: This function only checks against null or undefined, it does not coerce the value.
603
+ * ie: false and 0 are considered not nil
604
+ * Use isTruthy instead for a regular coercion check.
605
+ *
606
+ * @param value
607
+ * @returns whether the value is neither null nor undefined
608
+ */
609
+ const isNotNil = (value) => value !== null && value !== void 0;
610
+ //#endregion
611
+ //#region src/isPromise.ts
612
+ const isPromise = (value) => !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
613
+ //#endregion
614
+ //#region src/isSubject.ts
615
+ /**
616
+ * Tests to see if an object is an RxJS {@link Subject}.
617
+ */
358
618
  function isSubject(object) {
359
- if (!object) return false;
360
- if (object instanceof import_rxjs6.Subject) return true;
361
- 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);
619
+ if (!object) return false;
620
+ if (object instanceof rxjs.Subject) return true;
621
+ 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);
362
622
  }
623
+ /**
624
+ * Returns `true` if `value` is a function.
625
+ */
363
626
  function isFn(value) {
364
- return typeof value === "function";
627
+ return typeof value === "function";
365
628
  }
629
+ /**
630
+ * Returns `true` if `value` is a boolean.
631
+ */
366
632
  function isBool(value) {
367
- return typeof value === "boolean";
633
+ return typeof value === "boolean";
368
634
  }
369
-
370
- // src/isTruthy.ts
371
- var isTruthy = (value) => Boolean(value);
372
-
373
- // src/keepAlive.ts
374
- var import_rxjs7 = require("rxjs");
375
- var keepAlive = (timeout) => {
376
- let release;
377
- return (source) => source.pipe(
378
- (0, import_rxjs7.tap)({
379
- subscribe: () => {
380
- release = keepSourceSubscribed(source, timeout);
381
- },
382
- unsubscribe: () => {
383
- release?.();
384
- }
385
- }),
386
- (0, import_rxjs7.shareReplay)({ refCount: true, bufferSize: 1 })
387
- );
388
- };
389
- var keepSourceSubscribed = (observable, ms) => {
390
- const sub = observable.subscribe();
391
- return () => setTimeout(() => sub.unsubscribe(), ms);
635
+ //#endregion
636
+ //#region src/isTruthy.ts
637
+ const isTruthy = (value) => Boolean(value);
638
+ //#endregion
639
+ //#region src/keepAlive.ts
640
+ /**
641
+ * An RxJS operator that keeps the source observable alive for a specified duration
642
+ * after all subscribers have unsubscribed. This prevents expensive re-subscriptions
643
+ * when subscribers come and go frequently.
644
+ *
645
+ * @param keepAliveMs - Duration in milliseconds to keep the source alive after last unsubscription
646
+ * @returns MonoTypeOperatorFunction that can be used in pipe()
647
+ *
648
+ * @example
649
+ * ```typescript
650
+ * const data$ = expensive_api_call$.pipe(
651
+ * keepAlive(3000) // Keep alive for 3 seconds
652
+ * );
653
+ * ```
654
+ */
655
+ const keepAlive = (timeout) => {
656
+ let release;
657
+ return (source) => source.pipe((0, rxjs.tap)({
658
+ subscribe: () => {
659
+ release = keepSourceSubscribed(source, timeout);
660
+ },
661
+ unsubscribe: () => {
662
+ release?.();
663
+ }
664
+ }), (0, rxjs.shareReplay)({
665
+ refCount: true,
666
+ bufferSize: 1
667
+ }));
392
668
  };
393
-
394
- // src/planckToTokens.ts
669
+ const keepSourceSubscribed = (observable, ms) => {
670
+ const sub = observable.subscribe();
671
+ return () => setTimeout(() => sub.unsubscribe(), ms);
672
+ };
673
+ //#endregion
674
+ //#region src/lruMap.ts
675
+ /**
676
+ * A Map with a maximum size and least-recently-used eviction.
677
+ *
678
+ * Reads refresh recency; when an insert would exceed `maxSize`, the
679
+ * least-recently-used entry is evicted. Intended for long-lived in-memory
680
+ * caches that would otherwise grow without bound.
681
+ */
682
+ var LruMap = class {
683
+ #map = /* @__PURE__ */ new Map();
684
+ #maxSize;
685
+ constructor(maxSize) {
686
+ if (maxSize < 1) throw new Error("LruMap maxSize must be >= 1");
687
+ this.#maxSize = maxSize;
688
+ }
689
+ get(key) {
690
+ if (!this.#map.has(key)) return void 0;
691
+ const value = this.#map.get(key);
692
+ this.#map.delete(key);
693
+ this.#map.set(key, value);
694
+ return value;
695
+ }
696
+ set(key, value) {
697
+ if (this.#map.has(key)) this.#map.delete(key);
698
+ else if (this.#map.size >= this.#maxSize) {
699
+ const oldest = this.#map.keys().next();
700
+ if (!oldest.done) this.#map.delete(oldest.value);
701
+ }
702
+ this.#map.set(key, value);
703
+ return this;
704
+ }
705
+ has(key) {
706
+ return this.#map.has(key);
707
+ }
708
+ delete(key) {
709
+ return this.#map.delete(key);
710
+ }
711
+ clear() {
712
+ this.#map.clear();
713
+ }
714
+ get size() {
715
+ return this.#map.size;
716
+ }
717
+ };
718
+ //#endregion
719
+ //#region src/mapChunked.ts
720
+ const runChunkedProject = (project, options, value, index) => new rxjs.Observable((subscriber) => {
721
+ const controller = new AbortController();
722
+ project(value, {
723
+ slicer: createTimeSlicer({
724
+ budgetMs: options?.budgetMs,
725
+ signal: controller.signal,
726
+ label: options?.label
727
+ }),
728
+ signal: controller.signal
729
+ }, index).then((result) => {
730
+ if (!controller.signal.aborted) subscriber.next(result);
731
+ subscriber.complete();
732
+ }, (error) => {
733
+ if (isAbortError(error)) subscriber.complete();
734
+ else subscriber.error(error);
735
+ });
736
+ return () => controller.abort();
737
+ });
738
+ /**
739
+ * `switchMap` for time-sliced (chunked) async work — latest-wins: a new upstream value or
740
+ * an unsubscription aborts the in-flight `project` via `ctx.signal` / the shared slicer,
741
+ * so cancelled work stops burning CPU at its next yield check point and its result is
742
+ * never emitted.
743
+ *
744
+ * Non-abort errors thrown by `project` error the stream (same as a throwing sync `map`).
745
+ *
746
+ * Note: pipelines using this operator already emit asynchronously (macrotask), so adding
747
+ * `observeOn(asyncScheduler)` downstream is redundant and only adds latency.
748
+ */
749
+ const switchMapChunked = (project, options) => (0, rxjs.switchMap)((value, index) => runChunkedProject(project, options, value, index));
750
+ /**
751
+ * `concatMap` variant of switchMapChunked — ordered: upstream values queue and are
752
+ * processed one at a time; a new value does NOT cancel in-flight work (unsubscription
753
+ * still aborts it).
754
+ */
755
+ const concatMapChunked = (project, options) => (0, rxjs.concatMap)((value, index) => runChunkedProject(project, options, value, index));
756
+ //#endregion
757
+ //#region src/planckToTokens.ts
395
758
  function planckToTokens(planck, tokenDecimals) {
396
- if (typeof planck !== "string" || typeof tokenDecimals !== "number") return;
397
- const base = 10;
398
- const exponent = -1 * tokenDecimals;
399
- const multiplier = base ** exponent;
400
- return new configureBigNumber_default(planck).multipliedBy(multiplier).toString(10);
759
+ if (typeof planck !== "string" || typeof tokenDecimals !== "number") return;
760
+ const multiplier = 10 ** (-1 * tokenDecimals);
761
+ return new configureBigNumber_default(planck).multipliedBy(multiplier).toString(10);
401
762
  }
402
-
403
- // src/replaySubjectFrom.ts
404
- var import_rxjs8 = require("rxjs");
405
- var replaySubjectFrom = (initialValue) => {
406
- if (initialValue instanceof import_rxjs8.ReplaySubject) return initialValue;
407
- const subject = new import_rxjs8.ReplaySubject(1);
408
- if (isPromise(initialValue)) {
409
- initialValue.then(
410
- (value) => subject.next(value),
411
- (error) => subject.error(error)
412
- );
413
- return subject;
414
- }
415
- subject.next(initialValue);
416
- return subject;
763
+ //#endregion
764
+ //#region src/replaySubjectFrom.ts
765
+ /**
766
+ * Turns a value into a {@link ReplaySubject} of size 1.
767
+ *
768
+ * If the value is already a {@link ReplaySubject}, it will be returned as-is.
769
+ *
770
+ * If the value is a {@link Promise}, it will be awaited,
771
+ * and the awaited value will be published into the {@link ReplaySubject} when it becomes available.
772
+ *
773
+ * For any other type of value, it will be immediately published into the {@link ReplaySubject}.
774
+ */
775
+ const replaySubjectFrom = (initialValue) => {
776
+ if (initialValue instanceof rxjs.ReplaySubject) return initialValue;
777
+ const subject = new rxjs.ReplaySubject(1);
778
+ if (isPromise(initialValue)) {
779
+ initialValue.then((value) => subject.next(value), (error) => subject.error(error));
780
+ return subject;
781
+ }
782
+ subject.next(initialValue);
783
+ return subject;
417
784
  };
418
-
419
- // src/sleep.ts
420
- var sleep = (ms) => new Promise((resolve) => {
421
- if (process.env.NODE_ENV === "test") resolve();
422
- else setTimeout(resolve, ms);
785
+ //#endregion
786
+ //#region src/sleep.ts
787
+ const sleep = (ms) => new Promise((resolve) => {
788
+ if (process.env.NODE_ENV === "test") resolve();
789
+ else setTimeout(resolve, ms);
423
790
  });
424
-
425
- // src/splitSubject.ts
791
+ //#endregion
792
+ //#region src/splitSubject.ts
793
+ /**
794
+ * Takes a subject and splits it into two parts:
795
+ *
796
+ * 1. A function to submit new values into the subject.
797
+ * 2. An observable for subscribing to new values from the subject.
798
+ *
799
+ * This can be helpful when, to avoid bugs, you want to expose only one
800
+ * of these parts to external code and keep the other part private.
801
+ */
426
802
  function splitSubject(subject) {
427
- const next = (value) => subject.next(value);
428
- const observable = subject.asObservable();
429
- return [next, observable];
803
+ const next = (value) => subject.next(value);
804
+ return [next, subject.asObservable()];
430
805
  }
431
-
432
- // src/stripHexPrefix.ts
433
- var stripHexPrefix = (str) => str.startsWith("0x") ? str.slice(2) : str;
434
-
435
- // src/throwAfter.ts
436
- var throwAfter = (ms, reason) => new Promise((_, reject) => setTimeout(() => reject(new Error(reason)), ms));
437
-
438
- // src/tokensToPlanck.ts
806
+ //#endregion
807
+ //#region src/stripHexPrefix.ts
808
+ /**
809
+ * @name stripHexPrefix
810
+ * @description Removes a leading `0x` prefix from a string, if present.
811
+ * @param {string} str - string to strip
812
+ * @returns {string} - the string without its leading `0x` prefix
813
+ * @example
814
+ * stripHexPrefix("0x1234") // "1234"
815
+ * stripHexPrefix("1234") // "1234"
816
+ **/
817
+ const stripHexPrefix = (str) => str.startsWith("0x") ? str.slice(2) : str;
818
+ //#endregion
819
+ //#region src/throwAfter.ts
820
+ const throwAfter = (ms, reason) => new Promise((_, reject) => setTimeout(() => reject(new Error(reason)), ms));
821
+ //#endregion
822
+ //#region src/tokensToPlanck.ts
439
823
  function tokensToPlanck(tokens, tokenDecimals) {
440
- if (typeof tokens !== "string" || typeof tokenDecimals !== "number") return;
441
- const base = 10;
442
- const exponent = tokenDecimals;
443
- const multiplier = base ** exponent;
444
- return new configureBigNumber_default(tokens).multipliedBy(multiplier).toString(10);
824
+ if (typeof tokens !== "string" || typeof tokenDecimals !== "number") return;
825
+ const multiplier = 10 ** tokenDecimals;
826
+ return new configureBigNumber_default(tokens).multipliedBy(multiplier).toString(10);
445
827
  }
828
+ //#endregion
829
+ //#region src/validateArrayWithYield.ts
830
+ /**
831
+ * Validates every item of an array within a cooperative time budget, yielding the thread
832
+ * to the host event loop whenever the budget for the current slice is exhausted.
833
+ *
834
+ * Like `z.array(schema).safeParse`, ALL items are validated and all failures collected
835
+ * (no fail-fast) — pass e.g. `(item) => SomeSchema.safeParse(item)` as `parseItem`.
836
+ * Zod-agnostic on purpose: this package has no zod dependency.
837
+ */
838
+ const validateArrayWithYield = async (items, parseItem, options) => {
839
+ const data = new Array(items.length);
840
+ const errors = [];
841
+ await forEachWithYield(items, (item, index) => {
842
+ const result = parseItem(item, index);
843
+ if (result.success) data[index] = result.data;
844
+ else errors.push({
845
+ index,
846
+ error: result.error
847
+ });
848
+ }, options);
849
+ return errors.length ? {
850
+ success: false,
851
+ errors
852
+ } : {
853
+ success: true,
854
+ data
855
+ };
856
+ };
857
+ //#endregion
858
+ //#region src/validateHexString.ts
859
+ /**
860
+ * @name validateHexString
861
+ * @description Checks if a string is a hex string. Required to account for type differences between different polkadot libraries
862
+ * @param {string} str - string to check
863
+ * @returns {`0x${string}`} - boolean
864
+ * @example
865
+ * validateHexString("0x1234") // "0x1234"
866
+ * validateHexString("1234") // Error: Expected a hex string
867
+ * validateHexString(1234) // Error: Expected a string
868
+ **/
869
+ const validateHexString = (str) => {
870
+ if (typeof str !== "string") throw new Error("Expected a string");
871
+ if (str.startsWith("0x")) return str;
872
+ throw new Error("Expected a hex string");
873
+ };
874
+ //#endregion
875
+ exports.BigMath = BigMath;
876
+ exports.DEFAULT_TIME_SLICE_BUDGET_MS = DEFAULT_TIME_SLICE_BUDGET_MS;
877
+ exports.Deferred = Deferred;
878
+ exports.LruMap = LruMap;
879
+ exports.MAX_DECIMALS_FORMAT = MAX_DECIMALS_FORMAT;
880
+ exports.REGEX_HEX_STRING = REGEX_HEX_STRING;
881
+ exports.addTrailingSlash = addTrailingSlash;
882
+ exports.arrayItemsEqualWithYield = arrayItemsEqualWithYield;
883
+ exports.assert = assert;
884
+ exports.concatMapChunked = concatMapChunked;
885
+ exports.createTimeSlicer = createTimeSlicer;
886
+ exports.firstThenDebounce = firstThenDebounce;
887
+ exports.forEachWithYield = forEachWithYield;
888
+ exports.formatDecimals = formatDecimals;
889
+ exports.formatPrice = formatPrice;
890
+ exports.getLoadable$ = getLoadable$;
891
+ exports.getLoadableQuery$ = getLoadableQuery$;
892
+ exports.getQuery$ = getQuery$;
893
+ exports.getSharedObservable = getSharedObservable;
894
+ exports.hasOwnProperty = hasOwnProperty;
895
+ exports.hexToNumber = hexToNumber;
896
+ exports.hexToString = hexToString;
897
+ exports.hexToU8a = hexToU8a;
898
+ exports.isAbortError = isAbortError;
899
+ exports.isArrayOf = isArrayOf;
900
+ exports.isAscii = isAscii;
901
+ exports.isAsciiPrintable = isAsciiPrintable;
902
+ exports.isBigInt = isBigInt;
903
+ exports.isBooleanTrue = isBooleanTrue;
904
+ exports.isErrorOfName = isErrorOfName;
905
+ exports.isHexString = isHexString;
906
+ exports.isNotNil = isNotNil;
907
+ exports.isPromise = isPromise;
908
+ exports.isSubject = isSubject;
909
+ exports.isTruthy = isTruthy;
910
+ exports.keepAlive = keepAlive;
911
+ exports.keyByWithYield = keyByWithYield;
912
+ exports.mapWithYield = mapWithYield;
913
+ exports.newAbortError = newAbortError;
914
+ exports.numberToU8a = numberToU8a;
915
+ exports.planckToTokens = planckToTokens;
916
+ exports.replaySubjectFrom = replaySubjectFrom;
917
+ exports.reportJsActivity = reportJsActivity;
918
+ exports.sleep = sleep;
919
+ exports.splitSubject = splitSubject;
920
+ exports.stringToU8a = stringToU8a;
921
+ exports.stripHexPrefix = stripHexPrefix;
922
+ exports.switchMapChunked = switchMapChunked;
923
+ exports.throwAfter = throwAfter;
924
+ exports.tokensToPlanck = tokensToPlanck;
925
+ exports.u8aCmp = u8aCmp;
926
+ exports.u8aConcat = u8aConcat;
927
+ exports.u8aEq = u8aEq;
928
+ exports.u8aToHex = u8aToHex;
929
+ exports.u8aToString = u8aToString;
930
+ exports.u8aToU8a = u8aToU8a;
931
+ exports.u8aUnwrapBytes = u8aUnwrapBytes;
932
+ exports.u8aWrapBytes = u8aWrapBytes;
933
+ exports.validateArrayWithYield = validateArrayWithYield;
934
+ exports.validateHexString = validateHexString;
935
+ exports.yieldToEventLoop = yieldToEventLoop;
446
936
 
447
- // src/validateHexString.ts
448
- var validateHexString = (str) => {
449
- if (typeof str !== "string") {
450
- throw new Error("Expected a string");
451
- }
452
- if (str.startsWith("0x")) {
453
- return str;
454
- }
455
- throw new Error("Expected a hex string");
456
- };
457
- // Annotate the CommonJS export names for ESM import in node:
458
- 0 && (module.exports = {
459
- BigMath,
460
- Deferred,
461
- MAX_DECIMALS_FORMAT,
462
- REGEX_HEX_STRING,
463
- addTrailingSlash,
464
- firstThenDebounce,
465
- formatDecimals,
466
- formatPrice,
467
- getLoadable$,
468
- getLoadableQuery$,
469
- getQuery$,
470
- getSharedObservable,
471
- hasOwnProperty,
472
- isAbortError,
473
- isArrayOf,
474
- isAscii,
475
- isBigInt,
476
- isBooleanTrue,
477
- isErrorOfName,
478
- isHexString,
479
- isNotNil,
480
- isPromise,
481
- isSubject,
482
- isTruthy,
483
- keepAlive,
484
- planckToTokens,
485
- replaySubjectFrom,
486
- sleep,
487
- splitSubject,
488
- stripHexPrefix,
489
- throwAfter,
490
- tokensToPlanck,
491
- validateHexString
492
- });
493
937
  //# sourceMappingURL=index.js.map