@lotics/app-sdk 0.120.2 → 0.120.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -185,28 +185,651 @@ function bandOf(tiers, figure) {
185
185
  return { min: tiers[at - 1] ?? null, max: tiers[at] ?? null };
186
186
  }
187
187
 
188
- // ../shared/src/utils.ts
189
- function decimalPlaces(value) {
190
- if (Number.isInteger(value)) return 0;
191
- const [mantissa = "", exponent = "0"] = String(value).split("e");
192
- const fraction = mantissa.split(".")[1]?.length ?? 0;
193
- return Math.max(0, fraction - Number(exponent));
188
+ // ../../node_modules/big.js/big.mjs
189
+ var DP = 20;
190
+ var RM = 1;
191
+ var MAX_DP = 1e6;
192
+ var MAX_POWER = 1e6;
193
+ var NE = -7;
194
+ var PE = 21;
195
+ var STRICT = false;
196
+ var NAME = "[big.js] ";
197
+ var INVALID = NAME + "Invalid ";
198
+ var INVALID_DP = INVALID + "decimal places";
199
+ var INVALID_RM = INVALID + "rounding mode";
200
+ var DIV_BY_ZERO = NAME + "Division by zero";
201
+ var P = {};
202
+ var UNDEFINED = void 0;
203
+ var NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i;
204
+ function _Big_() {
205
+ function Big2(n) {
206
+ var x = this;
207
+ if (!(x instanceof Big2)) {
208
+ return n === UNDEFINED && arguments.length === 0 ? _Big_() : new Big2(n);
209
+ }
210
+ if (n instanceof Big2) {
211
+ x.s = n.s;
212
+ x.e = n.e;
213
+ x.c = n.c.slice();
214
+ } else {
215
+ if (typeof n !== "string") {
216
+ if (Big2.strict === true && typeof n !== "bigint") {
217
+ throw TypeError(INVALID + "value");
218
+ }
219
+ n = n === 0 && 1 / n < 0 ? "-0" : String(n);
220
+ }
221
+ parse(x, n);
222
+ }
223
+ x.constructor = Big2;
224
+ }
225
+ Big2.prototype = P;
226
+ Big2.DP = DP;
227
+ Big2.RM = RM;
228
+ Big2.NE = NE;
229
+ Big2.PE = PE;
230
+ Big2.strict = STRICT;
231
+ Big2.roundDown = 0;
232
+ Big2.roundHalfUp = 1;
233
+ Big2.roundHalfEven = 2;
234
+ Big2.roundUp = 3;
235
+ return Big2;
236
+ }
237
+ function parse(x, n) {
238
+ var e, i, nl;
239
+ if (!NUMERIC.test(n)) {
240
+ throw Error(INVALID + "number");
241
+ }
242
+ x.s = n.charAt(0) == "-" ? (n = n.slice(1), -1) : 1;
243
+ if ((e = n.indexOf(".")) > -1) n = n.replace(".", "");
244
+ if ((i = n.search(/e/i)) > 0) {
245
+ if (e < 0) e = i;
246
+ e += +n.slice(i + 1);
247
+ n = n.substring(0, i);
248
+ } else if (e < 0) {
249
+ e = n.length;
250
+ }
251
+ nl = n.length;
252
+ for (i = 0; i < nl && n.charAt(i) == "0"; ) ++i;
253
+ if (i == nl) {
254
+ x.c = [x.e = 0];
255
+ } else {
256
+ for (; nl > 0 && n.charAt(--nl) == "0"; ) ;
257
+ x.e = e - i - 1;
258
+ x.c = [];
259
+ for (e = 0; i <= nl; ) x.c[e++] = +n.charAt(i++);
260
+ }
261
+ return x;
262
+ }
263
+ function round(x, sd, rm, more) {
264
+ var xc = x.c;
265
+ if (rm === UNDEFINED) rm = x.constructor.RM;
266
+ if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) {
267
+ throw Error(INVALID_RM);
268
+ }
269
+ if (sd < 1) {
270
+ more = rm === 3 && (more || !!xc[0]) || sd === 0 && (rm === 1 && xc[0] >= 5 || rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED)));
271
+ xc.length = 1;
272
+ if (more) {
273
+ x.e = x.e - sd + 1;
274
+ xc[0] = 1;
275
+ } else {
276
+ xc[0] = x.e = 0;
277
+ }
278
+ } else if (sd < xc.length) {
279
+ more = rm === 1 && xc[sd] >= 5 || rm === 2 && (xc[sd] > 5 || xc[sd] === 5 && (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) || rm === 3 && (more || !!xc[0]);
280
+ xc.length = sd;
281
+ if (more) {
282
+ for (; ++xc[--sd] > 9; ) {
283
+ xc[sd] = 0;
284
+ if (sd === 0) {
285
+ ++x.e;
286
+ xc.unshift(1);
287
+ break;
288
+ }
289
+ }
290
+ }
291
+ for (sd = xc.length; !xc[--sd]; ) xc.pop();
292
+ }
293
+ return x;
294
+ }
295
+ function stringify(x, doExponential, isNonzero) {
296
+ var e = x.e, s = x.c.join(""), n = s.length;
297
+ if (doExponential) {
298
+ s = s.charAt(0) + (n > 1 ? "." + s.slice(1) : "") + (e < 0 ? "e" : "e+") + e;
299
+ } else if (e < 0) {
300
+ for (; ++e; ) s = "0" + s;
301
+ s = "0." + s;
302
+ } else if (e > 0) {
303
+ if (++e > n) {
304
+ for (e -= n; e--; ) s += "0";
305
+ } else if (e < n) {
306
+ s = s.slice(0, e) + "." + s.slice(e);
307
+ }
308
+ } else if (n > 1) {
309
+ s = s.charAt(0) + "." + s.slice(1);
310
+ }
311
+ return x.s < 0 && isNonzero ? "-" + s : s;
312
+ }
313
+ P.abs = function() {
314
+ var x = new this.constructor(this);
315
+ x.s = 1;
316
+ return x;
317
+ };
318
+ P.cmp = function(y) {
319
+ var isneg, x = this, xc = x.c, yc = (y = new x.constructor(y)).c, i = x.s, j = y.s, k = x.e, l = y.e;
320
+ if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i;
321
+ if (i != j) return i;
322
+ isneg = i < 0;
323
+ if (k != l) return k > l ^ isneg ? 1 : -1;
324
+ j = (k = xc.length) < (l = yc.length) ? k : l;
325
+ for (i = -1; ++i < j; ) {
326
+ if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1;
327
+ }
328
+ return k == l ? 0 : k > l ^ isneg ? 1 : -1;
329
+ };
330
+ P.div = function(y) {
331
+ var x = this, Big2 = x.constructor, a = x.c, b = (y = new Big2(y)).c, k = x.s == y.s ? 1 : -1, dp = Big2.DP;
332
+ if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
333
+ throw Error(INVALID_DP);
334
+ }
335
+ if (!b[0]) {
336
+ throw Error(DIV_BY_ZERO);
337
+ }
338
+ if (!a[0]) {
339
+ y.s = k;
340
+ y.c = [y.e = 0];
341
+ return y;
342
+ }
343
+ var bl, bt, n, cmp, ri, bz = b.slice(), ai = bl = b.length, al = a.length, r = a.slice(0, bl), rl = r.length, q = y, qc = q.c = [], qi = 0, p = dp + (q.e = x.e - y.e) + 1;
344
+ q.s = k;
345
+ k = p < 0 ? 0 : p;
346
+ bz.unshift(0);
347
+ for (; rl++ < bl; ) r.push(0);
348
+ do {
349
+ for (n = 0; n < 10; n++) {
350
+ if (bl != (rl = r.length)) {
351
+ cmp = bl > rl ? 1 : -1;
352
+ } else {
353
+ for (ri = -1, cmp = 0; ++ri < bl; ) {
354
+ if (b[ri] != r[ri]) {
355
+ cmp = b[ri] > r[ri] ? 1 : -1;
356
+ break;
357
+ }
358
+ }
359
+ }
360
+ if (cmp < 0) {
361
+ for (bt = rl == bl ? b : bz; rl; ) {
362
+ if (r[--rl] < bt[rl]) {
363
+ ri = rl;
364
+ for (; ri && !r[--ri]; ) r[ri] = 9;
365
+ --r[ri];
366
+ r[rl] += 10;
367
+ }
368
+ r[rl] -= bt[rl];
369
+ }
370
+ for (; !r[0]; ) r.shift();
371
+ } else {
372
+ break;
373
+ }
374
+ }
375
+ qc[qi++] = cmp ? n : ++n;
376
+ if (r[0] && cmp) r[rl] = a[ai] || 0;
377
+ else r = [a[ai]];
378
+ } while ((ai++ < al || r[0] !== UNDEFINED) && k--);
379
+ if (!qc[0] && qi != 1) {
380
+ qc.shift();
381
+ q.e--;
382
+ p--;
383
+ }
384
+ if (qi > p) round(q, p, Big2.RM, r[0] !== UNDEFINED);
385
+ return q;
386
+ };
387
+ P.eq = function(y) {
388
+ return this.cmp(y) === 0;
389
+ };
390
+ P.gt = function(y) {
391
+ return this.cmp(y) > 0;
392
+ };
393
+ P.gte = function(y) {
394
+ return this.cmp(y) > -1;
395
+ };
396
+ P.lt = function(y) {
397
+ return this.cmp(y) < 0;
398
+ };
399
+ P.lte = function(y) {
400
+ return this.cmp(y) < 1;
401
+ };
402
+ P.minus = P.sub = function(y) {
403
+ var i, j, t, xlty, x = this, Big2 = x.constructor, a = x.s, b = (y = new Big2(y)).s;
404
+ if (a != b) {
405
+ y.s = -b;
406
+ return x.plus(y);
407
+ }
408
+ var xc = x.c.slice(), xe = x.e, yc = y.c, ye = y.e;
409
+ if (!xc[0] || !yc[0]) {
410
+ if (yc[0]) {
411
+ y.s = -b;
412
+ } else if (xc[0]) {
413
+ y = new Big2(x);
414
+ } else {
415
+ y.s = 1;
416
+ }
417
+ return y;
418
+ }
419
+ if (a = xe - ye) {
420
+ if (xlty = a < 0) {
421
+ a = -a;
422
+ t = xc;
423
+ } else {
424
+ ye = xe;
425
+ t = yc;
426
+ }
427
+ t.reverse();
428
+ for (b = a; b--; ) t.push(0);
429
+ t.reverse();
430
+ } else {
431
+ j = ((xlty = xc.length < yc.length) ? xc : yc).length;
432
+ for (a = b = 0; b < j; b++) {
433
+ if (xc[b] != yc[b]) {
434
+ xlty = xc[b] < yc[b];
435
+ break;
436
+ }
437
+ }
438
+ }
439
+ if (xlty) {
440
+ t = xc;
441
+ xc = yc;
442
+ yc = t;
443
+ y.s = -y.s;
444
+ }
445
+ if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--; ) xc[i++] = 0;
446
+ for (b = i; j > a; ) {
447
+ if (xc[--j] < yc[j]) {
448
+ for (i = j; i && !xc[--i]; ) xc[i] = 9;
449
+ --xc[i];
450
+ xc[j] += 10;
451
+ }
452
+ xc[j] -= yc[j];
453
+ }
454
+ for (; xc[--b] === 0; ) xc.pop();
455
+ for (; xc[0] === 0; ) {
456
+ xc.shift();
457
+ --ye;
458
+ }
459
+ if (!xc[0]) {
460
+ y.s = 1;
461
+ xc = [ye = 0];
462
+ }
463
+ y.c = xc;
464
+ y.e = ye;
465
+ return y;
466
+ };
467
+ P.mod = function(y) {
468
+ var ygtx, x = this, Big2 = x.constructor, a = x.s, b = (y = new Big2(y)).s;
469
+ if (!y.c[0]) {
470
+ throw Error(DIV_BY_ZERO);
471
+ }
472
+ x.s = y.s = 1;
473
+ ygtx = y.cmp(x) == 1;
474
+ x.s = a;
475
+ y.s = b;
476
+ if (ygtx) return new Big2(x);
477
+ a = Big2.DP;
478
+ b = Big2.RM;
479
+ Big2.DP = Big2.RM = 0;
480
+ x = x.div(y);
481
+ Big2.DP = a;
482
+ Big2.RM = b;
483
+ return this.minus(x.times(y));
484
+ };
485
+ P.neg = function() {
486
+ var x = new this.constructor(this);
487
+ x.s = -x.s;
488
+ return x;
489
+ };
490
+ P.plus = P.add = function(y) {
491
+ var e, k, t, x = this, Big2 = x.constructor;
492
+ y = new Big2(y);
493
+ if (x.s != y.s) {
494
+ y.s = -y.s;
495
+ return x.minus(y);
496
+ }
497
+ var xe = x.e, xc = x.c, ye = y.e, yc = y.c;
498
+ if (!xc[0] || !yc[0]) {
499
+ if (!yc[0]) {
500
+ if (xc[0]) {
501
+ y = new Big2(x);
502
+ } else {
503
+ y.s = x.s;
504
+ }
505
+ }
506
+ return y;
507
+ }
508
+ xc = xc.slice();
509
+ if (e = xe - ye) {
510
+ if (e > 0) {
511
+ ye = xe;
512
+ t = yc;
513
+ } else {
514
+ e = -e;
515
+ t = xc;
516
+ }
517
+ t.reverse();
518
+ for (; e--; ) t.push(0);
519
+ t.reverse();
520
+ }
521
+ if (xc.length - yc.length < 0) {
522
+ t = yc;
523
+ yc = xc;
524
+ xc = t;
525
+ }
526
+ e = yc.length;
527
+ for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0;
528
+ if (k) {
529
+ xc.unshift(k);
530
+ ++ye;
531
+ }
532
+ for (e = xc.length; xc[--e] === 0; ) xc.pop();
533
+ y.c = xc;
534
+ y.e = ye;
535
+ return y;
536
+ };
537
+ P.pow = function(n) {
538
+ var x = this, one = new x.constructor("1"), y = one, isneg = n < 0;
539
+ if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) {
540
+ throw Error(INVALID + "exponent");
541
+ }
542
+ if (isneg) n = -n;
543
+ for (; ; ) {
544
+ if (n & 1) y = y.times(x);
545
+ n >>= 1;
546
+ if (!n) break;
547
+ x = x.times(x);
548
+ }
549
+ return isneg ? one.div(y) : y;
550
+ };
551
+ P.prec = function(sd, rm) {
552
+ if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
553
+ throw Error(INVALID + "precision");
554
+ }
555
+ return round(new this.constructor(this), sd, rm);
556
+ };
557
+ P.round = function(dp, rm) {
558
+ if (dp === UNDEFINED) dp = 0;
559
+ else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP) {
560
+ throw Error(INVALID_DP);
561
+ }
562
+ return round(new this.constructor(this), dp + this.e + 1, rm);
563
+ };
564
+ P.sqrt = function() {
565
+ var r, c, t, x = this, Big2 = x.constructor, s = x.s, e = x.e, half = new Big2("0.5");
566
+ if (!x.c[0]) return new Big2(x);
567
+ if (s < 0) {
568
+ throw Error(NAME + "No square root");
569
+ }
570
+ s = Math.sqrt(+stringify(x, true, true));
571
+ if (s === 0 || s === 1 / 0) {
572
+ c = x.c.join("");
573
+ if (!(c.length + e & 1)) c += "0";
574
+ s = Math.sqrt(c);
575
+ e = ((e + 1) / 2 | 0) - (e < 0 || e & 1);
576
+ r = new Big2((s == 1 / 0 ? "5e" : (s = s.toExponential()).slice(0, s.indexOf("e") + 1)) + e);
577
+ } else {
578
+ r = new Big2(s + "");
579
+ }
580
+ e = r.e + (Big2.DP += 4);
581
+ do {
582
+ t = r;
583
+ r = half.times(t.plus(x.div(t)));
584
+ } while (t.c.slice(0, e).join("") !== r.c.slice(0, e).join(""));
585
+ return round(r, (Big2.DP -= 4) + r.e + 1, Big2.RM);
586
+ };
587
+ P.times = P.mul = function(y) {
588
+ var c, x = this, Big2 = x.constructor, xc = x.c, yc = (y = new Big2(y)).c, a = xc.length, b = yc.length, i = x.e, j = y.e;
589
+ y.s = x.s == y.s ? 1 : -1;
590
+ if (!xc[0] || !yc[0]) {
591
+ y.c = [y.e = 0];
592
+ return y;
593
+ }
594
+ y.e = i + j;
595
+ if (a < b) {
596
+ c = xc;
597
+ xc = yc;
598
+ yc = c;
599
+ j = a;
600
+ a = b;
601
+ b = j;
602
+ }
603
+ for (c = new Array(j = a + b); j--; ) c[j] = 0;
604
+ for (i = b; i--; ) {
605
+ b = 0;
606
+ for (j = a + i; j > i; ) {
607
+ b = c[j] + yc[i] * xc[j - i - 1] + b;
608
+ c[j--] = b % 10;
609
+ b = b / 10 | 0;
610
+ }
611
+ c[j] = b;
612
+ }
613
+ if (b) ++y.e;
614
+ else c.shift();
615
+ for (i = c.length; !c[--i]; ) c.pop();
616
+ y.c = c;
617
+ return y;
618
+ };
619
+ P.toExponential = function(dp, rm) {
620
+ var x = this, n = x.c[0];
621
+ if (dp !== UNDEFINED) {
622
+ if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
623
+ throw Error(INVALID_DP);
624
+ }
625
+ x = round(new x.constructor(x), ++dp, rm);
626
+ for (; x.c.length < dp; ) x.c.push(0);
627
+ }
628
+ return stringify(x, true, !!n);
629
+ };
630
+ P.toFixed = function(dp, rm) {
631
+ var x = this, n = x.c[0];
632
+ if (dp !== UNDEFINED) {
633
+ if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
634
+ throw Error(INVALID_DP);
635
+ }
636
+ x = round(new x.constructor(x), dp + x.e + 1, rm);
637
+ for (dp = dp + x.e + 1; x.c.length < dp; ) x.c.push(0);
638
+ }
639
+ return stringify(x, false, !!n);
640
+ };
641
+ P.toJSON = P.toString = function() {
642
+ var x = this, Big2 = x.constructor;
643
+ return stringify(x, x.e <= Big2.NE || x.e >= Big2.PE, !!x.c[0]);
644
+ };
645
+ if (typeof Symbol !== "undefined") {
646
+ P[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")] = P.toJSON;
647
+ }
648
+ P.toNumber = function() {
649
+ var n = +stringify(this, true, true);
650
+ if (this.constructor.strict === true && !this.eq(n.toString())) {
651
+ throw Error(NAME + "Imprecise conversion");
652
+ }
653
+ return n;
654
+ };
655
+ P.toPrecision = function(sd, rm) {
656
+ var x = this, Big2 = x.constructor, n = x.c[0];
657
+ if (sd !== UNDEFINED) {
658
+ if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
659
+ throw Error(INVALID + "precision");
660
+ }
661
+ x = round(new Big2(x), sd, rm);
662
+ for (; x.c.length < sd; ) x.c.push(0);
663
+ }
664
+ return stringify(x, sd <= x.e || x.e <= Big2.NE || x.e >= Big2.PE, !!n);
665
+ };
666
+ P.valueOf = function() {
667
+ var x = this, Big2 = x.constructor;
668
+ if (Big2.strict === true) {
669
+ throw Error(NAME + "valueOf disallowed");
670
+ }
671
+ return stringify(x, x.e <= Big2.NE || x.e >= Big2.PE, true);
672
+ };
673
+ var Big = _Big_();
674
+ var big_default = Big;
675
+
676
+ // ../shared/src/decimal.ts
677
+ var DIVISION_DIGITS = 24;
678
+ var ROUNDING_PLACES = 1e6;
679
+ var POWER_DIGITS = 300;
680
+ var SIGNIFICANT_DIGITS = 15;
681
+ var SHORT_DIGITS = 12;
682
+ var WHOLE_DIGITS_LIMIT = 10 ** SIGNIFICANT_DIGITS;
683
+ var DIVISION_SCALES = [10, 100, 1e3, 1e4, 1e5, 1e6];
684
+ var Decimal = big_default();
685
+ Decimal.DP = DIVISION_DIGITS;
686
+ Decimal.RM = big_default.roundDown;
687
+ var QUOTIENT_STEP = new Decimal(`1e-${DIVISION_DIGITS}`);
688
+ function takesFloat(left, right) {
689
+ return !Number.isFinite(left) || !Number.isFinite(right) || left === 0 || right === 0;
690
+ }
691
+ function isExactInteger(left, right, result) {
692
+ return Number.isSafeInteger(left) && Number.isSafeInteger(right) && Number.isSafeInteger(result);
693
+ }
694
+ function isInexact(value, decimal) {
695
+ return decimal.c.length > SHORT_DIGITS && !Number.isSafeInteger(value);
696
+ }
697
+ function settled(result, inexact) {
698
+ if (!inexact) return result;
699
+ const reading = result.prec(SIGNIFICANT_DIGITS, big_default.roundHalfUp);
700
+ return reading.c.length <= SHORT_DIGITS ? reading : result;
701
+ }
702
+ function addDecimal(left, right) {
703
+ const float = left + right;
704
+ if (takesFloat(left, right) || isExactInteger(left, right, float)) return float;
705
+ const augend = new Decimal(left);
706
+ const addend = new Decimal(right);
707
+ return settled(augend.plus(addend), isInexact(left, augend) || isInexact(right, addend)).toNumber();
708
+ }
709
+ function subtractDecimal(left, right) {
710
+ const float = left - right;
711
+ if (takesFloat(left, right) || isExactInteger(left, right, float)) return float;
712
+ const minuend = new Decimal(left);
713
+ const subtrahend = new Decimal(right);
714
+ return settled(minuend.minus(subtrahend), isInexact(left, minuend) || isInexact(right, subtrahend)).toNumber();
715
+ }
716
+ function multiplyDecimal(left, right) {
717
+ return product(left, right, true);
718
+ }
719
+ function multiplyExactly(left, right) {
720
+ return product(left, right, false);
721
+ }
722
+ function product(left, right, settles) {
723
+ const float = left * right;
724
+ if (takesFloat(left, right) || isExactInteger(left, right, float)) return float;
725
+ const multiplicand = new Decimal(left);
726
+ const multiplier = new Decimal(right);
727
+ return settled(multiplicand.times(multiplier), settles && (isInexact(left, multiplicand) || isInexact(right, multiplier))).toNumber();
728
+ }
729
+ function divideDecimal(left, right) {
730
+ if (takesFloat(left, right) || Number.isSafeInteger(left) && Number.isSafeInteger(right)) return left / right;
731
+ const scaled = scaledQuotient(left, right);
732
+ if (scaled !== void 0) return scaled;
733
+ const dividend = new Decimal(left);
734
+ const divisor = new Decimal(right);
735
+ return quotient(dividend, divisor, isInexact(left, dividend) || isInexact(right, divisor));
736
+ }
737
+ function scaledQuotient(left, right) {
738
+ for (const scale2 of DIVISION_SCALES) {
739
+ const dividend = Math.round(left * scale2);
740
+ if (Math.abs(dividend) >= WHOLE_DIGITS_LIMIT || dividend / scale2 !== left) continue;
741
+ const divisor = Math.round(right * scale2);
742
+ if (Math.abs(divisor) < WHOLE_DIGITS_LIMIT && divisor / scale2 === right) return dividend / divisor;
743
+ }
744
+ return void 0;
745
+ }
746
+ function moduloDecimal(left, right) {
747
+ if (takesFloat(left, right)) return left % right;
748
+ const remainder = new Decimal(left).mod(right);
749
+ if (remainder.eq(0)) return left < 0 ? -0 : 0;
750
+ return remainder.toNumber();
751
+ }
752
+ function readAtSignificantDigits(value) {
753
+ if (Number.isInteger(value) || !Number.isFinite(value)) return value;
754
+ if (Math.abs(value) >= WHOLE_DIGITS_LIMIT) return Math.sign(value) * Math.round(Math.abs(value));
755
+ return Number(value.toPrecision(SIGNIFICANT_DIGITS));
756
+ }
757
+ function compareDecimal(left, right) {
758
+ if (left === right) return 0;
759
+ if (Number.isNaN(left) || Number.isNaN(right)) return NaN;
760
+ const leftRead = readAtSignificantDigits(left);
761
+ const rightRead = readAtSignificantDigits(right);
762
+ if (leftRead === rightRead) return 0;
763
+ return leftRead < rightRead ? -1 : 1;
194
764
  }
195
765
  function sumDecimal(values, divisor = 1) {
196
- const float = values.reduce((total2, value) => total2 + value, 0) / divisor;
197
- if (!values.every(Number.isFinite)) return float;
198
- const factor = 10 ** values.reduce((places, value) => Math.max(places, decimalPlaces(value)), 0);
199
- const scaled = values.map((value) => Math.round(value * factor));
200
- const total = scaled.reduce((sum, value) => sum + value, 0);
201
- const exact = Number.isSafeInteger(total) && scaled.every((one, index) => Number.isSafeInteger(one) && one / factor === values[index]);
202
- return exact ? total / (factor * divisor) : float;
766
+ if (!values.every(Number.isFinite) || !Number.isFinite(divisor) || divisor === 0) {
767
+ return values.reduce((total2, value) => total2 + value, 0) / divisor;
768
+ }
769
+ const { total, inexact } = isWithinSafeIntegers(values) ? { total: new Decimal(values.reduce((sum, value) => sum + value, 0)), inexact: false } : totalOf(values);
770
+ if (total.eq(0)) return 0;
771
+ if (divisor === 1) return total.toNumber();
772
+ const by = new Decimal(divisor);
773
+ return quotient(total, by, inexact || isInexact(divisor, by));
774
+ }
775
+ function totalOf(values) {
776
+ let total = new Decimal(0);
777
+ let inexact = false;
778
+ for (const value of values) {
779
+ const term = new Decimal(value);
780
+ inexact ||= isInexact(value, term);
781
+ total = total.plus(term);
782
+ }
783
+ return { total: settled(total, inexact), inexact };
784
+ }
785
+ function isWithinSafeIntegers(values) {
786
+ return values.every(Number.isSafeInteger) && values.reduce((magnitude, value) => magnitude + Math.abs(value), 0) <= Number.MAX_SAFE_INTEGER;
203
787
  }
204
- function sample(arr) {
205
- if (arr.length === 0) return void 0;
206
- return arr[Math.floor(Math.random() * arr.length)];
788
+ function roundDecimal(value, places) {
789
+ if (!Number.isFinite(value) || value === 0 || !Number.isInteger(places) || Math.abs(places) > ROUNDING_PLACES) {
790
+ const multiplier = Math.pow(10, places);
791
+ return Math.sign(value) * Math.round(Math.abs(value) * multiplier) / multiplier;
792
+ }
793
+ const rounded = new Decimal(value).round(places, big_default.roundHalfUp);
794
+ if (rounded.eq(0)) return value < 0 ? -0 : 0;
795
+ return rounded.toNumber();
796
+ }
797
+ function percentOf(part, total) {
798
+ return roundDecimal(divideDecimal(multiplyDecimal(part, 100), total), 0);
799
+ }
800
+ function fixedDecimal(value, places) {
801
+ if (!Number.isFinite(value) || Math.abs(value) >= 1e21) return value.toFixed(places);
802
+ return new Decimal(value).toFixed(places, big_default.roundHalfUp);
803
+ }
804
+ function powerDecimal(base, exponent) {
805
+ const float = Math.pow(base, exponent);
806
+ if (takesFloat(base, exponent) || !Number.isInteger(exponent)) return float;
807
+ const decimal = new Decimal(base);
808
+ if (decimal.c.length * Math.abs(exponent) > POWER_DIGITS) return float;
809
+ const inexact = isInexact(base, decimal);
810
+ const power = settled(decimal.pow(Math.abs(exponent)), inexact);
811
+ return exponent > 0 ? power.toNumber() : quotient(new Decimal(1), power, inexact);
812
+ }
813
+ function quotient(dividend, divisor, inexact) {
814
+ const sign = dividend.s === divisor.s ? 1 : -1;
815
+ const numerator = coefficientOf(dividend);
816
+ const denominator = coefficientOf(divisor);
817
+ for (let carried = 0; ; carried = carried * 2 + DIVISION_DIGITS) {
818
+ const scaled = new Decimal(`${numerator.digits}e${carried}`);
819
+ const low = scaled.div(denominator.digits);
820
+ const exponent = numerator.exponent - denominator.exponent - carried;
821
+ if (inexact) {
822
+ const short = settled(low, true);
823
+ if (short !== low) return sign * Number(`${short.toFixed()}e${exponent}`);
824
+ }
825
+ const lowNumber = Number(`${low.toFixed()}e${exponent}`);
826
+ const highNumber = Number(`${low.plus(QUOTIENT_STEP).toFixed()}e${exponent}`);
827
+ if (lowNumber === highNumber || low.times(denominator.digits).eq(scaled)) return sign * lowNumber;
828
+ }
207
829
  }
208
- function assertNever(value) {
209
- throw new Error(`Unhandled union member: ${JSON.stringify(value)}`);
830
+ function coefficientOf(decimal) {
831
+ const [digits = "", exponent = "0"] = decimal.abs().toExponential().split("e");
832
+ return { digits, exponent: Number(exponent) };
210
833
  }
211
834
 
212
835
  // ../shared/src/schemas/read_row.ts
@@ -1242,9 +1865,18 @@ export {
1242
1865
  tiersAscend,
1243
1866
  bandKey,
1244
1867
  bandOf,
1868
+ addDecimal,
1869
+ subtractDecimal,
1870
+ multiplyDecimal,
1871
+ multiplyExactly,
1872
+ divideDecimal,
1873
+ moduloDecimal,
1874
+ compareDecimal,
1245
1875
  sumDecimal,
1246
- sample,
1247
- assertNever,
1876
+ roundDecimal,
1877
+ percentOf,
1878
+ fixedDecimal,
1879
+ powerDecimal,
1248
1880
  AGGREGATE_COUNT_COLUMN,
1249
1881
  AGGREGATE_SUM_COLUMN,
1250
1882
  aggregateRows,
package/dist/index.js CHANGED
@@ -3,35 +3,44 @@ import {
3
3
  AGGREGATE_SUM_COLUMN,
4
4
  DEFAULT_IMAGE_FIDELITY,
5
5
  __export,
6
+ addDecimal,
6
7
  aggregateRows,
7
8
  anyRecordingLive,
8
9
  applyPatch,
9
- assertNever,
10
10
  bandKey,
11
11
  bandOf,
12
+ compareDecimal,
12
13
  decodeAll,
14
+ divideDecimal,
13
15
  encodePatch,
16
+ fixedDecimal,
14
17
  getUrlParams,
15
18
  isEmbedded,
19
+ moduloDecimal,
20
+ multiplyDecimal,
21
+ multiplyExactly,
16
22
  paramsEqual,
17
23
  peekUrlParams,
24
+ percentOf,
18
25
  postHostNotification,
26
+ powerDecimal,
19
27
  readRecordingSnapshot,
20
28
  recordingStateOf,
21
29
  recordingsVersion,
22
30
  replaceRecordings,
31
+ roundDecimal,
23
32
  rpc,
24
33
  rpcAgentRun,
25
34
  rpcAgentRunContinue,
26
- sample,
27
35
  setUrlParams,
28
36
  subscribeQueriesChanged,
29
37
  subscribeRecordings,
30
38
  subscribeUrlParams,
39
+ subtractDecimal,
31
40
  sumDecimal,
32
41
  tiersAscend,
33
42
  urlParam
34
- } from "./chunk-NZXJENJ2.js";
43
+ } from "./chunk-ABDSJ25E.js";
35
44
 
36
45
  // src/mount.tsx
37
46
  import { createRoot } from "react-dom/client";
@@ -1729,6 +1738,15 @@ var customRandom = (alphabet, defaultSize, getRandom) => {
1729
1738
  };
1730
1739
  var customAlphabet = (alphabet, size2 = 21) => customRandom(alphabet, size2 | 0, random);
1731
1740
 
1741
+ // ../shared/src/utils.ts
1742
+ function sample(arr) {
1743
+ if (arr.length === 0) return void 0;
1744
+ return arr[Math.floor(Math.random() * arr.length)];
1745
+ }
1746
+ function assertNever(value) {
1747
+ throw new Error(`Unhandled union member: ${JSON.stringify(value)}`);
1748
+ }
1749
+
1732
1750
  // ../shared/src/expression_array.ts
1733
1751
  var expression_array_exports = {};
1734
1752
  __export(expression_array_exports, {
@@ -2782,7 +2800,7 @@ function formatNumber(value, decimals) {
2782
2800
  throw new Error("formatNumber: expected number, got " + typeof value);
2783
2801
  }
2784
2802
  assertDecimals(decimals, "formatNumber");
2785
- return value.toFixed(decimals);
2803
+ return fixedDecimal(value, decimals);
2786
2804
  }
2787
2805
  function formatDecimal(value, decimals, locale) {
2788
2806
  if (value == null) return "";
@@ -2902,9 +2920,7 @@ function round(value, precision) {
2902
2920
  if (precision != null && typeof precision !== "number") {
2903
2921
  throw new Error("round: precision must be a number");
2904
2922
  }
2905
- const prec = precision != null ? precision : 0;
2906
- const multiplier = Math.pow(10, prec);
2907
- return Math.round(value * multiplier) / multiplier;
2923
+ return roundDecimal(value, precision ?? 0);
2908
2924
  }
2909
2925
  function sum(arr) {
2910
2926
  if (arr == null) return 0;
@@ -2970,12 +2986,8 @@ function percentage(part, total, decimals) {
2970
2986
  if (decimals != null && typeof decimals !== "number") {
2971
2987
  throw new Error("percentage: decimals must be a number");
2972
2988
  }
2973
- const percent = part / total * 100;
2974
- if (decimals != null) {
2975
- const multiplier = Math.pow(10, decimals);
2976
- return Math.round(percent * multiplier) / multiplier;
2977
- }
2978
- return percent;
2989
+ const percent = divideDecimal(multiplyDecimal(part, 100), total);
2990
+ return decimals != null ? roundDecimal(percent, decimals) : percent;
2979
2991
  }
2980
2992
  function pow(base, exponent) {
2981
2993
  if (base == null || exponent == null) return null;
@@ -2985,7 +2997,7 @@ function pow(base, exponent) {
2985
2997
  if (typeof exponent !== "number") {
2986
2998
  throw new Error("pow: exponent must be a number");
2987
2999
  }
2988
- return Math.pow(base, exponent);
3000
+ return powerDecimal(base, exponent);
2989
3001
  }
2990
3002
  function sqrt(n) {
2991
3003
  if (n == null) return null;
@@ -3008,7 +3020,7 @@ function mod(n, divisor) {
3008
3020
  if (divisor === 0) {
3009
3021
  throw new Error("mod: divisor cannot be zero");
3010
3022
  }
3011
- return n % divisor;
3023
+ return moduloDecimal(n, divisor);
3012
3024
  }
3013
3025
 
3014
3026
  // ../shared/src/expression_object.ts
@@ -5815,9 +5827,21 @@ function isNothing(value) {
5815
5827
  return value === null || value === void 0;
5816
5828
  }
5817
5829
  var MULTIPLICATIVE_OPERATORS = /* @__PURE__ */ new Map([
5818
- ["*", (left, right) => left * right],
5819
- ["/", (left, right) => left / right],
5820
- ["%", (left, right) => left % right]
5830
+ ["*", multiplyDecimal],
5831
+ ["/", divideDecimal],
5832
+ ["%", moduloDecimal]
5833
+ ]);
5834
+ var COMPARISONS = /* @__PURE__ */ new Map([
5835
+ // eslint-disable-next-line eqeqeq
5836
+ ["==", { ofNumbers: (order) => order === 0, ofOthers: (left, right) => left == right }],
5837
+ // eslint-disable-next-line eqeqeq
5838
+ ["!=", { ofNumbers: (order) => order !== 0, ofOthers: (left, right) => left != right }],
5839
+ ["===", { ofNumbers: (order) => order === 0, ofOthers: (left, right) => left === right }],
5840
+ ["!==", { ofNumbers: (order) => order !== 0, ofOthers: (left, right) => left !== right }],
5841
+ ["<", { ofNumbers: (order) => order < 0, ofOthers: (left, right) => left < right }],
5842
+ ["<=", { ofNumbers: (order) => order <= 0, ofOthers: (left, right) => left <= right }],
5843
+ [">", { ofNumbers: (order) => order > 0, ofOthers: (left, right) => left > right }],
5844
+ [">=", { ofNumbers: (order) => order >= 0, ofOthers: (left, right) => left >= right }]
5821
5845
  ]);
5822
5846
  var SafeEvalAstFactory = class extends EvalAstFactory {
5823
5847
  id(name) {
@@ -5856,6 +5880,26 @@ var SafeEvalAstFactory = class extends EvalAstFactory {
5856
5880
  }
5857
5881
  };
5858
5882
  }
5883
+ const comparison = COMPARISONS.get(op);
5884
+ if (comparison) {
5885
+ return {
5886
+ type: "Binary",
5887
+ operator: op,
5888
+ left,
5889
+ right,
5890
+ evaluate(scope) {
5891
+ const leftValue = this.left.evaluate(scope);
5892
+ const rightValue = this.right.evaluate(scope);
5893
+ if (typeof leftValue === "number" && typeof rightValue === "number") return comparison.ofNumbers(compareDecimal(leftValue, rightValue));
5894
+ return comparison.ofOthers(leftValue, rightValue);
5895
+ },
5896
+ getIds(idents) {
5897
+ this.left.getIds(idents);
5898
+ this.right.getIds(idents);
5899
+ return idents;
5900
+ }
5901
+ };
5902
+ }
5859
5903
  if (op !== "+" && op !== "-") {
5860
5904
  return super.binary(left, op, right);
5861
5905
  }
@@ -5871,7 +5915,8 @@ var SafeEvalAstFactory = class extends EvalAstFactory {
5871
5915
  if (isNothing(leftValue) && isNothing(rightValue)) return null;
5872
5916
  const leftOperand = leftValue ?? 0;
5873
5917
  const rightOperand = rightValue ?? 0;
5874
- return op === "+" ? leftOperand + rightOperand : Number(leftOperand) - Number(rightOperand);
5918
+ if (op === "-") return subtractDecimal(Number(leftOperand), Number(rightOperand));
5919
+ return typeof leftOperand === "number" && typeof rightOperand === "number" ? addDecimal(leftOperand, rightOperand) : leftOperand + rightOperand;
5875
5920
  };
5876
5921
  return op === "+" ? addOrConcat(leftValue, rightValue, combine) : combine();
5877
5922
  },
@@ -21164,7 +21209,7 @@ function aggregateTextField(values2, operation) {
21164
21209
  const emptyCount = values2.filter(
21165
21210
  (value) => value === null || value === void 0 || value === ""
21166
21211
  ).length;
21167
- const percentage2 = Math.round(emptyCount / totalCount * 100);
21212
+ const percentage2 = percentOf(emptyCount, totalCount);
21168
21213
  return { result: percentage2 };
21169
21214
  }
21170
21215
  case "percent_filled": {
@@ -21172,7 +21217,7 @@ function aggregateTextField(values2, operation) {
21172
21217
  const filledCount = values2.filter(
21173
21218
  (value) => value !== null && value !== void 0 && value !== ""
21174
21219
  ).length;
21175
- const percentage2 = Math.round(filledCount / totalCount * 100);
21220
+ const percentage2 = percentOf(filledCount, totalCount);
21176
21221
  return { result: percentage2 };
21177
21222
  }
21178
21223
  case "unique": {
@@ -21188,7 +21233,7 @@ function aggregateTextField(values2, operation) {
21188
21233
  );
21189
21234
  if (filledValues.length === 0) return { result: 0 };
21190
21235
  const uniqueValues = new Set(filledValues);
21191
- const percentage2 = Math.round(uniqueValues.size / filledValues.length * 100);
21236
+ const percentage2 = percentOf(uniqueValues.size, filledValues.length);
21192
21237
  return { result: percentage2 };
21193
21238
  }
21194
21239
  default:
@@ -21212,13 +21257,13 @@ function aggregateNumberField(values2, operation) {
21212
21257
  case "percent_empty": {
21213
21258
  if (totalCount === 0) return { result: 0 };
21214
21259
  const emptyCount = values2.filter((value) => !hasNumberValue(value)).length;
21215
- const percentage2 = Math.round(emptyCount / totalCount * 100);
21260
+ const percentage2 = percentOf(emptyCount, totalCount);
21216
21261
  return { result: percentage2 };
21217
21262
  }
21218
21263
  case "percent_filled": {
21219
21264
  if (totalCount === 0) return { result: 0 };
21220
21265
  const filledCount = values2.filter(hasNumberValue).length;
21221
- const percentage2 = Math.round(filledCount / totalCount * 100);
21266
+ const percentage2 = percentOf(filledCount, totalCount);
21222
21267
  return { result: percentage2 };
21223
21268
  }
21224
21269
  case "unique": {
@@ -21230,7 +21275,7 @@ function aggregateNumberField(values2, operation) {
21230
21275
  const filledValues = values2.filter(hasNumberValue);
21231
21276
  if (filledValues.length === 0) return { result: 0 };
21232
21277
  const uniqueValues = new Set(filledValues);
21233
- const percentage2 = Math.round(uniqueValues.size / filledValues.length * 100);
21278
+ const percentage2 = percentOf(uniqueValues.size, filledValues.length);
21234
21279
  return { result: percentage2 };
21235
21280
  }
21236
21281
  }
@@ -21288,13 +21333,13 @@ function aggregateBooleanField(values2, operation) {
21288
21333
  case "percent_checked": {
21289
21334
  if (totalCount === 0) return { result: 0 };
21290
21335
  const checkedCount = values2.filter((value) => value === true).length;
21291
- const percentage2 = Math.round(checkedCount / totalCount * 100);
21336
+ const percentage2 = percentOf(checkedCount, totalCount);
21292
21337
  return { result: percentage2 };
21293
21338
  }
21294
21339
  case "percent_unchecked": {
21295
21340
  if (totalCount === 0) return { result: 0 };
21296
21341
  const uncheckedCount = values2.filter((value) => !value).length;
21297
- const percentage2 = Math.round(uncheckedCount / totalCount * 100);
21342
+ const percentage2 = percentOf(uncheckedCount, totalCount);
21298
21343
  return { result: percentage2 };
21299
21344
  }
21300
21345
  default:
@@ -21321,7 +21366,7 @@ function aggregateDateField(values2, operation) {
21321
21366
  const emptyCount = values2.filter(
21322
21367
  (value) => value === null || value === void 0 || value === ""
21323
21368
  ).length;
21324
- const percentage2 = Math.round(emptyCount / totalCount * 100);
21369
+ const percentage2 = percentOf(emptyCount, totalCount);
21325
21370
  return { result: percentage2 };
21326
21371
  }
21327
21372
  case "percent_filled": {
@@ -21329,7 +21374,7 @@ function aggregateDateField(values2, operation) {
21329
21374
  const filledCount = values2.filter(
21330
21375
  (value) => value !== null && value !== void 0 && value !== ""
21331
21376
  ).length;
21332
- const percentage2 = Math.round(filledCount / totalCount * 100);
21377
+ const percentage2 = percentOf(filledCount, totalCount);
21333
21378
  return { result: percentage2 };
21334
21379
  }
21335
21380
  case "unique": {
@@ -21345,7 +21390,7 @@ function aggregateDateField(values2, operation) {
21345
21390
  );
21346
21391
  if (filledValues.length === 0) return { result: 0 };
21347
21392
  const uniqueValues = new Set(filledValues);
21348
- const percentage2 = Math.round(uniqueValues.size / filledValues.length * 100);
21393
+ const percentage2 = percentOf(uniqueValues.size, filledValues.length);
21349
21394
  return { result: percentage2 };
21350
21395
  }
21351
21396
  }
@@ -21451,13 +21496,13 @@ function aggregateGenericField(values2, operation) {
21451
21496
  case "percent_empty": {
21452
21497
  if (totalCount === 0) return { result: 0 };
21453
21498
  const emptyCount = values2.filter(isEmpty2).length;
21454
- const percentage2 = Math.round(emptyCount / totalCount * 100);
21499
+ const percentage2 = percentOf(emptyCount, totalCount);
21455
21500
  return { result: percentage2 };
21456
21501
  }
21457
21502
  case "percent_filled": {
21458
21503
  if (totalCount === 0) return { result: 0 };
21459
21504
  const filledCount = values2.filter((value) => !isEmpty2(value)).length;
21460
- const percentage2 = Math.round(filledCount / totalCount * 100);
21505
+ const percentage2 = percentOf(filledCount, totalCount);
21461
21506
  return { result: percentage2 };
21462
21507
  }
21463
21508
  case "unique": {
@@ -21484,7 +21529,7 @@ function aggregateGenericField(values2, operation) {
21484
21529
  uniqueValues.add(value);
21485
21530
  }
21486
21531
  }
21487
- const percentage2 = Math.round(uniqueValues.size / filledValues.length * 100);
21532
+ const percentage2 = percentOf(uniqueValues.size, filledValues.length);
21488
21533
  return { result: percentage2 };
21489
21534
  }
21490
21535
  case "selected":
@@ -21513,13 +21558,13 @@ function aggregateSelectRecordLinkField(values2, operation) {
21513
21558
  case "percent_empty": {
21514
21559
  if (totalCount === 0) return { result: 0 };
21515
21560
  const emptyCount = values2.filter(isEmpty2).length;
21516
- const percentage2 = Math.round(emptyCount / totalCount * 100);
21561
+ const percentage2 = percentOf(emptyCount, totalCount);
21517
21562
  return { result: percentage2 };
21518
21563
  }
21519
21564
  case "percent_filled": {
21520
21565
  if (totalCount === 0) return { result: 0 };
21521
21566
  const filledCount = values2.filter((value) => !isEmpty2(value)).length;
21522
- const percentage2 = Math.round(filledCount / totalCount * 100);
21567
+ const percentage2 = percentOf(filledCount, totalCount);
21523
21568
  return { result: percentage2 };
21524
21569
  }
21525
21570
  case "selected":
@@ -21564,13 +21609,13 @@ function aggregateRollupField(values2, operation) {
21564
21609
  case "percent_empty": {
21565
21610
  if (totalCount === 0) return { result: 0 };
21566
21611
  const emptyCount = values2.filter(isEmpty2).length;
21567
- const percentage2 = Math.round(emptyCount / totalCount * 100);
21612
+ const percentage2 = percentOf(emptyCount, totalCount);
21568
21613
  return { result: percentage2 };
21569
21614
  }
21570
21615
  case "percent_filled": {
21571
21616
  if (totalCount === 0) return { result: 0 };
21572
21617
  const filledCount = values2.filter((value) => !isEmpty2(value)).length;
21573
- const percentage2 = Math.round(filledCount / totalCount * 100);
21618
+ const percentage2 = percentOf(filledCount, totalCount);
21574
21619
  return { result: percentage2 };
21575
21620
  }
21576
21621
  case "unique": {
@@ -21583,7 +21628,7 @@ function aggregateRollupField(values2, operation) {
21583
21628
  const filledValues = values2.filter((value) => !isEmpty2(value));
21584
21629
  if (filledValues.length === 0) return { result: 0 };
21585
21630
  const uniqueValues = new Set(filledValues);
21586
- const percentage2 = Math.round(uniqueValues.size / filledValues.length * 100);
21631
+ const percentage2 = percentOf(uniqueValues.size, filledValues.length);
21587
21632
  return { result: percentage2 };
21588
21633
  }
21589
21634
  }
@@ -21904,9 +21949,8 @@ function currencyCodeOf(written) {
21904
21949
  if (Intl.supportedValuesOf("currency").includes(upper2)) return upper2;
21905
21950
  return DONG_SPELLINGS.includes(unitKey(written)) ? "VND" : void 0;
21906
21951
  }
21907
- var EXACT_DIGITS = 15;
21908
21952
  function convert(value, from, to) {
21909
- return from.code === to.code ? value : Number((value * from.factor / to.factor).toPrecision(EXACT_DIGITS));
21953
+ return from.code === to.code ? value : divideDecimal(multiplyDecimal(value, from.factor), to.factor);
21910
21954
  }
21911
21955
  function scaleIn(own, pack) {
21912
21956
  const kin = MEASURED_UNITS.filter((one) => one.dimension === own.dimension);
@@ -28163,33 +28207,34 @@ async function evaluateBinary(op, leftExpr, rightExpr, ctx) {
28163
28207
  assertCheap(ctx.evaluation_budget, left, right);
28164
28208
  assertTextWithin("+", typeof left === "string" ? null : left, typeof right === "string" ? null : right);
28165
28209
  }
28166
- const sum2 = addOrConcat(left, right, () => assertNumber(left, "add", "left") + assertNumber(right, "add", "right"));
28210
+ const sum2 = addOrConcat(left, right, () => addDecimal(assertNumber(left, "add", "left"), assertNumber(right, "add", "right")));
28167
28211
  charge(ctx, builtSize(sum2));
28168
28212
  return sum2;
28169
28213
  }
28170
28214
  case "sub":
28171
- return assertNumber(left, "sub", "left") - assertNumber(right, "sub", "right");
28215
+ return subtractDecimal(assertNumber(left, "sub", "left"), assertNumber(right, "sub", "right"));
28172
28216
  case "mul":
28173
- return assertNumber(left, "mul", "left") * assertNumber(right, "mul", "right");
28217
+ return multiplyDecimal(assertNumber(left, "mul", "left"), assertNumber(right, "mul", "right"));
28174
28218
  case "div": {
28175
28219
  const r = assertNumber(right, "div", "right");
28176
28220
  if (r === 0) {
28177
28221
  throw new WorkflowEvalError("Division by zero", { kind: "binary", at: "div" });
28178
28222
  }
28179
- return assertNumber(left, "div", "left") / r;
28223
+ return divideDecimal(assertNumber(left, "div", "left"), r);
28180
28224
  }
28181
28225
  case "mod": {
28182
28226
  const r = assertNumber(right, "mod", "right");
28183
28227
  if (r === 0) {
28184
28228
  throw new WorkflowEvalError("Modulo by zero", { kind: "binary", at: "mod" });
28185
28229
  }
28186
- return assertNumber(left, "mod", "left") % r;
28230
+ return moduloDecimal(assertNumber(left, "mod", "left"), r);
28187
28231
  }
28188
28232
  }
28189
28233
  }
28190
28234
  function looseEq(a, b) {
28191
28235
  if (isComposite(a) && b !== null && b !== void 0 && !isComposite(b)) return looseEq(textOf(a), b);
28192
28236
  if (isComposite(b) && a !== null && a !== void 0 && !isComposite(a)) return looseEq(a, textOf(b));
28237
+ if (typeof a === "number" && typeof b === "number") return compareDecimal(a, b) === 0;
28193
28238
  return a == b;
28194
28239
  }
28195
28240
  function isComposite(value) {
@@ -28204,6 +28249,7 @@ function isScalar(value) {
28204
28249
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint";
28205
28250
  }
28206
28251
  function strictEq(a, b) {
28252
+ if (typeof a === "number" && typeof b === "number") return compareDecimal(a, b) === 0;
28207
28253
  return a === b;
28208
28254
  }
28209
28255
  function compareOrdered(a, b) {
@@ -28211,7 +28257,7 @@ function compareOrdered(a, b) {
28211
28257
  return NaN;
28212
28258
  }
28213
28259
  if (typeof a === "number" && typeof b === "number") {
28214
- return a - b;
28260
+ return compareDecimal(a, b);
28215
28261
  }
28216
28262
  if (typeof a === "string" && typeof b === "string") {
28217
28263
  return a < b ? -1 : a > b ? 1 : 0;
@@ -30510,7 +30556,7 @@ function evaluateCondition(record2, fieldByKey, looseCondition, memberContext, f
30510
30556
  if (reading.unit !== void 0 && filterCondition.value !== null && filterCondition.value !== void 0) {
30511
30557
  const factor = rowUnitFactor(reading.unit, data);
30512
30558
  if (factor === void 0) return false;
30513
- const inBase = { ...filterCondition, value: filterCondition.value * reading.unit.factor };
30559
+ const inBase = { ...filterCondition, value: multiplyExactly(filterCondition.value, reading.unit.factor) };
30514
30560
  return matchCell(columnValue, field, inBase, looseCondition, memberContext, fileFacts, factor);
30515
30561
  }
30516
30562
  }
@@ -30619,7 +30665,7 @@ function matchCell(cell, field, filterCondition, looseCondition, memberContext,
30619
30665
  matches = foldedValue !== void 0 && needles.some((needle) => foldedValue.includes(needle));
30620
30666
  }
30621
30667
  } else if (filterCondition.type === "number") {
30622
- const numberValue = typeof columnValue === "number" ? columnValue * figureFactor : columnValue;
30668
+ const numberValue = typeof columnValue === "number" ? multiplyExactly(columnValue, figureFactor) : columnValue;
30623
30669
  if (filterCondition.operator === "is_empty") {
30624
30670
  matches = !numberValue && numberValue !== 0;
30625
30671
  } else if (filterCondition.operator === "is_not_empty") {
package/dist/router.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  isEmbedded,
3
3
  postHostNotification,
4
4
  setUrlParams
5
- } from "./chunk-NZXJENJ2.js";
5
+ } from "./chunk-ABDSJ25E.js";
6
6
 
7
7
  // src/router.tsx
8
8
  import { useEffect } from "react";
package/docs/workflows.md CHANGED
@@ -384,8 +384,8 @@ body does not look like what you typed.
384
384
  | `x.length` (dot only) | `length(x)` — strings and arrays. `x["length"]` still reads a field |
385
385
  | `String(x)`, `Number(x)`, `parseFloat(x)`, `+x` | `toString(x)` / `toNumber(x)` |
386
386
  | `x.toUpperCase()`, `x.toLowerCase()` | `upper(x)`, `lower(x)` |
387
- | `x.toFixed(2)` | `formatNumber(x, 2)` |
388
- | `Math.round/min/max/abs/floor/ceil/pow/sqrt(…)` | the like-named helper |
387
+ | `x.toFixed(2)` | `formatNumber(x, 2)` — rounds the decimal, a half away from zero: `1.005` is `"1.01"` |
388
+ | `Math.round/min/max/abs/floor/ceil/pow/sqrt(…)` | the like-named helper. `round` rounds the decimal, a half away from zero: `round(-2.5)` is `-3` |
389
389
  | `Math.max(...arr)` / `Math.min(...arr)` | `max(arr)` / `min(arr)` |
390
390
  | `JSON.parse`, `JSON.stringify` | `parseJson`, `toJson` |
391
391
  | `Array.isArray`, `Object.keys/values/entries` | `isArray`, `keys`/`values`/`entries` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/app-sdk",
3
- "version": "0.120.2",
3
+ "version": "0.120.3",
4
4
  "description": "The SDK a Lotics custom-code app reads and writes through — typed hooks over the host bridge, cell readers, mount() and AppRouter",
5
5
  "type": "module",
6
6
  "exports": {