@lotics/app-sdk 0.120.1 → 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.
- package/dist/{chunk-NZXJENJ2.js → chunk-ABDSJ25E.js} +652 -20
- package/dist/index.js +95 -49
- package/dist/router.js +1 -1
- package/docs/mutations.md +2 -2
- package/docs/workflows.md +12 -35
- package/package.json +1 -1
|
@@ -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
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
205
|
-
if (
|
|
206
|
-
|
|
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
|
|
209
|
-
|
|
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
|
-
|
|
1247
|
-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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
|
|
2974
|
-
|
|
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
|
|
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
|
|
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
|
-
["*",
|
|
5819
|
-
["/",
|
|
5820
|
-
["%",
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 :
|
|
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);
|
|
@@ -25051,7 +25095,7 @@ var tableDateFieldSchema = tableFieldBaseSchema.extend({
|
|
|
25051
25095
|
format: dateFormatSchema.optional(),
|
|
25052
25096
|
timezone: zod_default.string().optional().describe("IANA timezone"),
|
|
25053
25097
|
derive_from: zod_default.enum(["created_at", "updated_at"]).optional().describe(
|
|
25054
|
-
"Auto-populate from the row's system timestamp. `created_at` stamps once at insert time; `updated_at` re-stamps on every record edit. A derived field is read-only: a write naming it is refused, as for formula/rollup/lookup.
|
|
25098
|
+
"Auto-populate from the row's system timestamp. `created_at` stamps once at insert time; `updated_at` re-stamps on every record edit. A derived field is read-only: a write naming it is refused, as for formula/rollup/lookup."
|
|
25055
25099
|
),
|
|
25056
25100
|
// A derived date is read-only, so derive_from and default_value are mutually
|
|
25057
25101
|
// exclusive — enforced in validateFieldDefaultValue.
|
|
@@ -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")
|
|
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")
|
|
28215
|
+
return subtractDecimal(assertNumber(left, "sub", "left"), assertNumber(right, "sub", "right"));
|
|
28172
28216
|
case "mul":
|
|
28173
|
-
return assertNumber(left, "mul", "left")
|
|
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")
|
|
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")
|
|
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
|
|
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
|
|
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
|
|
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
package/docs/mutations.md
CHANGED
|
@@ -397,8 +397,8 @@ Why a full-form snapshot save is a bug, not a style choice — three independent
|
|
|
397
397
|
moment *any* field is touched — there is no value-equality pass (deep equality over stored
|
|
398
398
|
shapes would be a silent lock bypass). A snapshot touches every field, so it turns every
|
|
399
399
|
save against a locked record into a total rejection even when nothing changed.
|
|
400
|
-
2. **A table's checks
|
|
401
|
-
|
|
400
|
+
2. **A table's checks run on the write.** They run on every write that touches the record —
|
|
401
|
+
a snapshot save runs them for fields the user never edited.
|
|
402
402
|
3. **Snapshots clobber concurrent edits.** An update writes exactly the fields present in the
|
|
403
403
|
payload; unsent fields keep their current value. A diff therefore coexists with a
|
|
404
404
|
colleague's concurrent edit to a *different* field — a snapshot overwrites it with the
|
package/docs/workflows.md
CHANGED
|
@@ -51,9 +51,7 @@ compile-time "cannot find name", not a runtime `undefined`.
|
|
|
51
51
|
|---|---|---|
|
|
52
52
|
| `trigger` | every context | the trigger namespace. For an app workflow: `trigger.app_workflow.inputs.<name>` |
|
|
53
53
|
| `runtime` | every context | execution context — see the key table below |
|
|
54
|
-
| `record` | button
|
|
55
|
-
| `prev_record` | table `*_update` / `*_delete` | the prior record state — same shape as `record` |
|
|
56
|
-
| `changes` | table `*_update` | per-field diff — a *partial* map, so read it `changes["fld_x"]?.next_value` / `?.prev_value` |
|
|
54
|
+
| `record` | button workflows | the record the button was pressed on |
|
|
57
55
|
| `index` | inside a `for-of` body | the current 0-based iteration index — always the **innermost** loop's. To use an outer loop's index in a nested body, bind it in the outer one (`const outerIdx = index;`) and read that |
|
|
58
56
|
| `<bind_name>` | inside a `for-of` body | the current item. Each loop keeps its own, so a nested body reads the outer loop's item by its own bind name |
|
|
59
57
|
| `<name>` | its block, after the declaration | a `const` — a step's output (`rows.records`, `approval.status`, …) or a bound value |
|
|
@@ -61,10 +59,6 @@ compile-time "cannot find name", not a runtime `undefined`.
|
|
|
61
59
|
| `<param>` | inside a helper callback | that lambda's parameter |
|
|
62
60
|
| `(await <tool>({…}))` | anywhere the call runs unconditionally | that call's output, read in place (see *`await` inside a statement*) |
|
|
63
61
|
|
|
64
|
-
`record`, `prev_record` and `changes` are the **canonical** roots. `trigger.data`,
|
|
65
|
-
`trigger.prev_data` and `trigger.changes` are accepted and lower onto them, so a saved body prints
|
|
66
|
-
back in the bare form. Write the bare form.
|
|
67
|
-
|
|
68
62
|
A body bound to an app alias is an app workflow: it sees `trigger` and `runtime` only. There is
|
|
69
63
|
no `record` — an app workflow is not attached to a table. Pass the record id in as a
|
|
70
64
|
`record_link` input and `get_record` it.
|
|
@@ -72,11 +66,9 @@ no `record` — an app workflow is not attached to a table. Pass the record id i
|
|
|
72
66
|
`runtime` keys: `timezone`, `now`, `workflow_id`, `execution_id`, `workspace_id`,
|
|
73
67
|
`organization_id`, `triggered_by_member_id` (`null` for a system trigger or an anonymous
|
|
74
68
|
public-app caller), and `change_origin` — a discriminated union over how the **execution** was
|
|
75
|
-
started: `button` · `automation` · `app_action` · `app_workflow
|
|
69
|
+
started: `button` · `automation` · `app_action` · `app_workflow`. It describes
|
|
76
70
|
the dispatch, never the person, and it is fixed per attachment — an app workflow always reads
|
|
77
|
-
`app_workflow
|
|
78
|
-
read `trigger.change_origin` on a table workflow (that one carries the originating write's
|
|
79
|
-
origin, and spans every write path: `member`, `chat_agent`, `app_workflow`, …). `runtime`
|
|
71
|
+
`app_workflow`. `runtime`
|
|
80
72
|
is never null, so `runtime?.x` is rejected outright. Prefer the helper `now()` over
|
|
81
73
|
`runtime.now`.
|
|
82
74
|
|
|
@@ -118,16 +110,13 @@ is a second call (`linked(linked(order.data["fld_a"])[0]["fld_b"])[0]`). A linke
|
|
|
118
110
|
deleted, or that the run may not read, stays a positional `null`, so `linked(P)[i]` is always the
|
|
119
111
|
row `P[i]` names.
|
|
120
112
|
|
|
121
|
-
The argument is a path ending on a link field, off anything record-shaped: `record` /
|
|
122
|
-
`prev_record`, a `for-of` item, a lambda parameter, a `let` binding, or a `get_record` /
|
|
113
|
+
The argument is a path ending on a link field, off anything record-shaped: `record`, a `for-of` item, a lambda parameter, a `let` binding, or a `get_record` /
|
|
123
114
|
`query_records` output. The server checks the far field at save only where it can name the table
|
|
124
115
|
before the run — a call with a **literal** `table_id` — and the fetch works either way. Guard **inside** the
|
|
125
116
|
argument — `linked(record?.["fld_link"])[0]` — never on the call: `linked(P)?.[i]` is rejected,
|
|
126
117
|
because the call always returns an array and the guard could never fire. Two more rejections:
|
|
127
118
|
`const ids = record["fld_link"]; linked(ids)`, since the field name comes from the argument's last
|
|
128
|
-
member access (`linked(row["fld_link"])` off a bound ROW is fine)
|
|
129
|
-
`linked(changes["fld_link"]?.next_value)`, since a diff is not a record — read
|
|
130
|
-
`linked(record["fld_link"])` or `linked(prev_record["fld_link"])`, which hold the same ids.
|
|
119
|
+
member access (`linked(row["fld_link"])` off a bound ROW is fine).
|
|
131
120
|
`linked` is grammar, not a helper: it cannot be shadowed, bound, called as a method, or awaited.
|
|
132
121
|
|
|
133
122
|
## Step forms
|
|
@@ -257,13 +246,12 @@ only the dialog. What it may name depends on who renders the refusal:
|
|
|
257
246
|
| Workflow | `field_key` may name |
|
|
258
247
|
|---|---|
|
|
259
248
|
| app workflow | a declared INPUT name (`order_code`, a key of the binding's `inputs`), or the `fld_` key of a field on a table the body names as a literal (a `table_id: "tbl_…"`, or a `const` holding one) |
|
|
260
|
-
|
|
|
249
|
+
| button | the `fld_` key of a field on the button's table |
|
|
261
250
|
| recordless automation (schedule, webhook, email) | anything — nothing renders it, so nothing checks it |
|
|
262
251
|
|
|
263
252
|
An app workflow whose alias declares no inputs leaves input-shaped keys unchecked, so a body can
|
|
264
253
|
be written before its declaration. A key outside its row is refused when the body is SAVED — by
|
|
265
|
-
`set_app_workflow`, by an agent binding one
|
|
266
|
-
`verify_only` call before that. `return({ field_errors })` keys are not checked.
|
|
254
|
+
`set_app_workflow`, by an agent binding one — and by a `verify_only` call before that. `return({ field_errors })` keys are not checked.
|
|
267
255
|
|
|
268
256
|
### `wait_for_approval` — the one wait worth binding
|
|
269
257
|
|
|
@@ -396,8 +384,8 @@ body does not look like what you typed.
|
|
|
396
384
|
| `x.length` (dot only) | `length(x)` — strings and arrays. `x["length"]` still reads a field |
|
|
397
385
|
| `String(x)`, `Number(x)`, `parseFloat(x)`, `+x` | `toString(x)` / `toNumber(x)` |
|
|
398
386
|
| `x.toUpperCase()`, `x.toLowerCase()` | `upper(x)`, `lower(x)` |
|
|
399
|
-
| `x.toFixed(2)` | `formatNumber(x, 2)` |
|
|
400
|
-
| `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` |
|
|
401
389
|
| `Math.max(...arr)` / `Math.min(...arr)` | `max(arr)` / `min(arr)` |
|
|
402
390
|
| `JSON.parse`, `JSON.stringify` | `parseJson`, `toJson` |
|
|
403
391
|
| `Array.isArray`, `Object.keys/values/entries` | `isArray`, `keys`/`values`/`entries` |
|
|
@@ -657,9 +645,8 @@ linked record id as `RecordId<"tbl_…">`. They come out branded from a record r
|
|
|
657
645
|
or from a workflow input declared `member` / `file` / `record_link` — a `rec_*` string carried in
|
|
658
646
|
a plain `text` input does *not* type-check into a link field, so declare the input for what it is.
|
|
659
647
|
|
|
660
|
-
A link **read** is an id array, so it feeds straight back: `set: { fld_link: record["fld_link"] }
|
|
661
|
-
|
|
662
|
-
`?.prev_value`. What does not feed back is a ROW: a link field takes ids, so from rows you already
|
|
648
|
+
A link **read** is an id array, so it feeds straight back: `set: { fld_link: record["fld_link"] }`.
|
|
649
|
+
What does not feed back is a ROW: a link field takes ids, so from rows you already
|
|
663
650
|
hold write `pluck(rows.records, (r) => r.id)`, or `[x.id]` for one. Never route a link read through
|
|
664
651
|
`linked(...)` to get its ids back — it holds them already, and the fetch costs one read per row and
|
|
665
652
|
yields `null` where a row is deleted or unreadable, which the write then rejects.
|
|
@@ -796,8 +783,7 @@ The rules that are easy to get wrong because the failing code looks correct.
|
|
|
796
783
|
`` `Status: ${record["fld_status"]}` `` prints "Done" while
|
|
797
784
|
`record["fld_status"] == "opt_done"` compares keys — both correct, and neither substitutes for
|
|
798
785
|
the other. It holds on every route a record arrives by — a `let`, a callback parameter, a row
|
|
799
|
-
from a variable `table_id
|
|
800
|
-
behaves exactly like the same field read off the record.
|
|
786
|
+
from a variable `table_id`.
|
|
801
787
|
- **Multi-select `==` quietly desugars.** On a multi-select field,
|
|
802
788
|
`record["fld_tags"] == "opt_urgent"` rewrites to `includes(…)` at save. Either spelling is
|
|
803
789
|
fine — but a `switch` on a multi-select discriminant is **rejected**, because its value is an
|
|
@@ -810,15 +796,6 @@ The rules that are easy to get wrong because the failing code looks correct.
|
|
|
810
796
|
`xs = concat(xs, someArray)` fails to typecheck; appending a whole *array* has no `push`
|
|
811
797
|
spelling. Start that binding from the first array instead of seeding it `[]`. Appending single
|
|
812
798
|
**items** (`xs.push(item)`) works on a bare `[]` seed.
|
|
813
|
-
- **A mutation on the trigger table of an `after_*` workflow can re-trigger itself** — a lint
|
|
814
|
-
warning, not an error. Gate it on `trigger.change_origin` — the originating write's origin —
|
|
815
|
-
and name every origin you mean to let through, rather than testing for one. `member` is a
|
|
816
|
-
person in the browser and **only** that: the same edit made over MCP, the CLI, or a direct API
|
|
817
|
-
call arrives as `api_client`, and one made by the chat agent as `chat_agent`. A gate meaning
|
|
818
|
-
"someone did this by hand" is
|
|
819
|
-
`includes(["member", "chat_agent", "api_client"], trigger.change_origin.type)`. Not
|
|
820
|
-
`runtime.change_origin`: that is the execution's own origin, always `table_workflow` here, so
|
|
821
|
-
it discriminates nothing.
|
|
822
799
|
- **Expressions are bounded.** A helper that builds an array — `range`, `list`, `flatten`,
|
|
823
800
|
`concat` of arrays, `split`'s parts — makes at most 100,000 elements, and a callback helper
|
|
824
801
|
takes an array of at most 100,000. `join`, `replaceAll`, `padStart`, `padEnd`, `toString`,
|
package/package.json
CHANGED