@rkmodules/rules 0.0.169 → 0.0.171

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.
@@ -544,31 +544,6 @@ function toArray(a) {
544
544
  return Object.values(a).flat();
545
545
  }
546
546
 
547
- var getType = {
548
- name: "getType",
549
- label: "Get Type",
550
- description: "Gets the type of a value as a string",
551
- inputs: {
552
- input: { type: "any" },
553
- },
554
- outputs: {
555
- type: "string",
556
- },
557
- impl: function (inputs, params) { return __awaiter(void 0, void 0, void 0, function () {
558
- return __generator(this, function (_a) {
559
- return [2 /*return*/, {
560
- type: mapTree(inputs.input, function (x) {
561
- if (x === undefined)
562
- return "empty";
563
- if (x === null)
564
- return "empty";
565
- return typeof x;
566
- }),
567
- }];
568
- });
569
- }); },
570
- };
571
-
572
547
  // utilities
573
548
  /**
574
549
  * merges two trees by concatenating the branches with the same path
@@ -640,6 +615,27 @@ function hasReference(value) {
640
615
  function parseReference(ref) {
641
616
  return ref.slice(1, -1);
642
617
  }
618
+ /** Reference paths using the same literal-array and token rules as interpolation. */
619
+ function getReferencePaths(value) {
620
+ var paths = new Set();
621
+ var visit = function (value) {
622
+ if (Array.isArray(value)) {
623
+ if (!value.every(Array.isArray))
624
+ value.forEach(visit);
625
+ }
626
+ else if (value && typeof value === "object") {
627
+ Object.values(value).forEach(visit);
628
+ }
629
+ else if (typeof value === "string") {
630
+ (value.match(/<.*?>/g) || []).forEach(function (token) {
631
+ if (isReference(token))
632
+ paths.add(parseReference(token));
633
+ });
634
+ }
635
+ };
636
+ visit(value);
637
+ return __spreadArray([], __read(paths), false);
638
+ }
643
639
  function uid$1() {
644
640
  return Math.random().toString(36).substring(2, 15);
645
641
  }
@@ -746,7 +742,200 @@ function interpolate(inputs, scope) {
746
742
  }));
747
743
  }
748
744
 
745
+ // Bounds count entries, not bytes. Each location keeps only its last successful result.
746
+ var MAX_SCOPES = 32;
747
+ var MAX_ENTRIES = 1024;
748
+ var cachePath = function (path) { return JSON.stringify(path); };
749
+ function sameRecord(a, b) {
750
+ var keys = Object.keys(a);
751
+ var otherKeys = Object.keys(b);
752
+ return keys.length === otherKeys.length && keys.every(function (key, i) { return key === otherKeys[i] && Object.is(a[key], b[key]); });
753
+ }
754
+ function put(map, key, value) {
755
+ map.delete(key);
756
+ map.set(key, value);
757
+ if (map.size > MAX_ENTRIES)
758
+ map.delete(map.keys().next().value);
759
+ }
760
+ /** Engine-owned caches; execution state is carried explicitly across async boundaries. */
761
+ var ExecutionCache = /** @class */ (function () {
762
+ function ExecutionCache() {
763
+ this.scopes = new Map();
764
+ }
765
+ ExecutionCache.prototype.begin = function (graph, options) {
766
+ var _a;
767
+ var cacheKey = (_a = options.cacheKey) !== null && _a !== void 0 ? _a : "";
768
+ var key = cachePath([graph, cacheKey]);
769
+ var scope = this.scopes.get(key);
770
+ if (!scope) {
771
+ scope = { graph: graph, cacheKey: cacheKey, generation: 0, run: 0,
772
+ interpolation: new Map(), pure: new Map(), preview: new Map() };
773
+ }
774
+ this.scopes.delete(key);
775
+ this.scopes.set(key, scope);
776
+ if (this.scopes.size > MAX_SCOPES) {
777
+ var oldest = this.scopes.keys().next().value;
778
+ this.scopes.get(oldest).generation++;
779
+ this.scopes.delete(oldest);
780
+ }
781
+ return { scope: scope, generation: scope.generation, run: ++scope.run,
782
+ options: __assign({}, options), visited: new Set() };
783
+ };
784
+ ExecutionCache.prototype.current = function (run) {
785
+ return run.generation === run.scope.generation && run.run === run.scope.run;
786
+ };
787
+ ExecutionCache.prototype.clear = function (options) {
788
+ var e_1, _a;
789
+ if (options === void 0) { options = {}; }
790
+ try {
791
+ for (var _b = __values(this.scopes.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
792
+ var scope = _c.value;
793
+ if (options.graph !== undefined && scope.graph !== options.graph)
794
+ continue;
795
+ if (options.cacheKey !== undefined && scope.cacheKey !== options.cacheKey)
796
+ continue;
797
+ // Pending runs may finish for their callers, but cannot refill cleared caches.
798
+ scope.generation++;
799
+ if (!options.kind || options.kind === "all") {
800
+ scope.interpolation.clear();
801
+ scope.pure.clear();
802
+ scope.preview.clear();
803
+ }
804
+ else {
805
+ scope[options.kind].clear();
806
+ }
807
+ }
808
+ }
809
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
810
+ finally {
811
+ try {
812
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
813
+ }
814
+ finally { if (e_1) throw e_1.error; }
815
+ }
816
+ };
817
+ ExecutionCache.prototype.visit = function (run, path) {
818
+ run.visited.add(cachePath(path));
819
+ };
820
+ ExecutionCache.prototype.finish = function (run) {
821
+ var e_2, _a, e_3, _b;
822
+ if (!this.current(run))
823
+ return;
824
+ try {
825
+ for (var _c = __values([run.scope.interpolation, run.scope.pure, run.scope.preview]), _d = _c.next(); !_d.done; _d = _c.next()) {
826
+ var map = _d.value;
827
+ try {
828
+ for (var _e = (e_3 = void 0, __values(map.keys())), _f = _e.next(); !_f.done; _f = _e.next()) {
829
+ var key = _f.value;
830
+ if (!run.visited.has(key))
831
+ map.delete(key);
832
+ }
833
+ }
834
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
835
+ finally {
836
+ try {
837
+ if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
838
+ }
839
+ finally { if (e_3) throw e_3.error; }
840
+ }
841
+ }
842
+ }
843
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
844
+ finally {
845
+ try {
846
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
847
+ }
848
+ finally { if (e_2) throw e_2.error; }
849
+ }
850
+ };
851
+ ExecutionCache.prototype.interpolate = function (run, path, raw, scope) {
852
+ var key = cachePath(path);
853
+ run.visited.add(key);
854
+ if (!this.current(run))
855
+ return interpolate(raw, scope);
856
+ var previous = run.scope.interpolation.get(key);
857
+ var ports = new Map();
858
+ var entries = Object.entries(raw).map(function (_a) {
859
+ var _b = __read(_a, 2), name = _b[0], value = _b[1];
860
+ // Deep references depend on the base tree's identity. Unrelated scope
861
+ // entries never invalidate this port; a fresh execution context is fine.
862
+ var old = previous === null || previous === void 0 ? void 0 : previous.ports.get(name);
863
+ var paths = old && Object.is(old.raw, value) ? old.paths :
864
+ getReferencePaths(value).map(function (path) { return path.split(".").slice(0, 2).join("."); });
865
+ var dependencies = paths.map(function (path) { return getValue$1(scope, path); });
866
+ var same = old && Object.is(old.raw, value) &&
867
+ old.dependencies.length === dependencies.length &&
868
+ dependencies.every(function (value, i) { return Object.is(value, old.dependencies[i]); });
869
+ var port = same ? old : {
870
+ raw: value,
871
+ paths: paths,
872
+ dependencies: dependencies,
873
+ tree: interpolate({ value: value }, scope).value,
874
+ };
875
+ ports.set(name, port);
876
+ return [name, port.tree];
877
+ });
878
+ var next = Object.fromEntries(entries);
879
+ var result = previous && sameRecord(previous.result, next) ? previous.result : next;
880
+ put(run.scope.interpolation, key, { ports: ports, result: result });
881
+ return result;
882
+ };
883
+ ExecutionCache.prototype.key = function (call) {
884
+ call.inputs; call.params; var metadata = __rest(call, ["inputs", "params"]);
885
+ return metadata;
886
+ };
887
+ ExecutionCache.prototype.get = function (run, path, kind, fn, call, inputs, params) {
888
+ var key = cachePath(path);
889
+ run.visited.add(key);
890
+ if (!this.current(run))
891
+ return;
892
+ var entry = run.scope[kind].get(key);
893
+ if (entry && entry.definition === fn && entry.impl === fn.impl &&
894
+ sameRecord(entry.metadata, this.key(call)) && sameRecord(entry.inputs, inputs) &&
895
+ sameRecord(entry.params, params)) {
896
+ put(run.scope[kind], key, entry);
897
+ return entry;
898
+ }
899
+ };
900
+ ExecutionCache.prototype.set = function (run, path, kind, fn, call, inputs, params, result, impl, createdAt) {
901
+ if (!this.current(run))
902
+ return;
903
+ var key = cachePath(path);
904
+ run.visited.add(key);
905
+ put(run.scope[kind], key, { definition: fn, impl: impl, metadata: this.key(call),
906
+ inputs: __assign({}, inputs), params: __assign({}, params), result: result, info: { kind: kind, createdAt: createdAt } });
907
+ };
908
+ return ExecutionCache;
909
+ }());
910
+
911
+ var getType = {
912
+ pure: true,
913
+ name: "getType",
914
+ label: "Get Type",
915
+ description: "Gets the type of a value as a string",
916
+ inputs: {
917
+ input: { type: "any" },
918
+ },
919
+ outputs: {
920
+ type: "string",
921
+ },
922
+ impl: function (inputs, params) { return __awaiter(void 0, void 0, void 0, function () {
923
+ return __generator(this, function (_a) {
924
+ return [2 /*return*/, {
925
+ type: mapTree(inputs.input, function (x) {
926
+ if (x === undefined)
927
+ return "empty";
928
+ if (x === null)
929
+ return "empty";
930
+ return typeof x;
931
+ }),
932
+ }];
933
+ });
934
+ }); },
935
+ };
936
+
749
937
  var getValue = {
938
+ pure: true,
750
939
  name: "getValue",
751
940
  label: "Get Value",
752
941
  description: "Get a value from an object at a specified path.",
@@ -777,6 +966,8 @@ var getValue = {
777
966
  };
778
967
 
779
968
  var log = {
969
+ // Logging is a required side effect, even when the data is unchanged.
970
+ pure: false,
780
971
  name: "log",
781
972
  label: "Log",
782
973
  description: "Logs the input data to the console",
@@ -801,6 +992,7 @@ var log = {
801
992
  * value primitive function
802
993
  */
803
994
  var value = {
995
+ pure: true,
804
996
  name: "value",
805
997
  label: "Value",
806
998
  description: "Outputs a constant value of a specified type",
@@ -852,6 +1044,7 @@ function isNumber() {
852
1044
  }
853
1045
 
854
1046
  var add$1 = {
1047
+ pure: true,
855
1048
  name: "add",
856
1049
  label: "Add",
857
1050
  description: "Add two numbers or strings",
@@ -897,6 +1090,8 @@ function evaluate(expression, scope) {
897
1090
  * TODO: need rank polymorhism on the tree item sizes
898
1091
  */
899
1092
  var calc = {
1093
+ // Expressions can use randomness; failed evaluations also log diagnostics.
1094
+ pure: false,
900
1095
  name: "calc",
901
1096
  label: "Calc",
902
1097
  nodeType: "Calc",
@@ -1035,6 +1230,7 @@ function getUnboundSymbols(expr, scope, extraBound) {
1035
1230
  }
1036
1231
 
1037
1232
  var cosDeg = {
1233
+ pure: true,
1038
1234
  name: "cosDeg",
1039
1235
  label: "Cosine",
1040
1236
  description: "Cosine of angle in degrees",
@@ -1058,6 +1254,7 @@ var cosDeg = {
1058
1254
  };
1059
1255
 
1060
1256
  var divide = {
1257
+ pure: true,
1061
1258
  name: "divide",
1062
1259
  label: "Divide",
1063
1260
  description: "Divide two numbers",
@@ -1084,6 +1281,7 @@ var divide = {
1084
1281
  };
1085
1282
 
1086
1283
  var equalTo = {
1284
+ pure: true,
1087
1285
  name: "equalTo",
1088
1286
  label: "Equal to",
1089
1287
  description: "Compare equal and not equal",
@@ -1114,6 +1312,7 @@ var equalTo = {
1114
1312
  };
1115
1313
 
1116
1314
  var greaterThan = {
1315
+ pure: true,
1117
1316
  name: "greaterThan",
1118
1317
  label: "Greater Than",
1119
1318
  description: "Compare on greater than or greater than or equal to",
@@ -1144,6 +1343,7 @@ var greaterThan = {
1144
1343
  };
1145
1344
 
1146
1345
  var lessThan = {
1346
+ pure: true,
1147
1347
  name: "lessThan",
1148
1348
  label: "Less Than",
1149
1349
  description: "Compare on less than or less than or equal to",
@@ -1174,6 +1374,7 @@ var lessThan = {
1174
1374
  };
1175
1375
 
1176
1376
  var modulo = {
1377
+ pure: true,
1177
1378
  name: "modulo",
1178
1379
  label: "Modulo",
1179
1380
  description: "Division remainder of two numbers",
@@ -1198,6 +1399,7 @@ var modulo = {
1198
1399
  };
1199
1400
 
1200
1401
  var multiply = {
1402
+ pure: true,
1201
1403
  name: "multiply",
1202
1404
  label: "Multiply",
1203
1405
  description: "Multiply two numbers",
@@ -1222,6 +1424,7 @@ var multiply = {
1222
1424
  };
1223
1425
 
1224
1426
  var pow = {
1427
+ pure: true,
1225
1428
  name: "pow",
1226
1429
  label: "Power",
1227
1430
  description: "Power a number",
@@ -1246,6 +1449,7 @@ var pow = {
1246
1449
  };
1247
1450
 
1248
1451
  var sinDeg = {
1452
+ pure: true,
1249
1453
  name: "sinDeg",
1250
1454
  label: "Sine",
1251
1455
  description: "Sine of angle in degrees",
@@ -1269,6 +1473,7 @@ var sinDeg = {
1269
1473
  };
1270
1474
 
1271
1475
  var sqrt = {
1476
+ pure: true,
1272
1477
  name: "sqrt",
1273
1478
  label: "Square root",
1274
1479
  description: "Square root of a number",
@@ -1294,6 +1499,7 @@ var sqrt = {
1294
1499
  };
1295
1500
 
1296
1501
  var subtract$1 = {
1502
+ pure: true,
1297
1503
  name: "subtract",
1298
1504
  label: "Subtract",
1299
1505
  description: "Subtract two numbers",
@@ -1318,6 +1524,7 @@ var subtract$1 = {
1318
1524
  };
1319
1525
 
1320
1526
  var tanDeg = {
1527
+ pure: true,
1321
1528
  name: "tanDeg",
1322
1529
  label: "Tangent",
1323
1530
  description: "Tangent of angle in degrees",
@@ -1341,6 +1548,7 @@ var tanDeg = {
1341
1548
  };
1342
1549
 
1343
1550
  var ceil = {
1551
+ pure: true,
1344
1552
  name: "ceil",
1345
1553
  label: "Round up",
1346
1554
  description: "Round a number up to the nearest integer",
@@ -1369,6 +1577,7 @@ var ceil = {
1369
1577
  };
1370
1578
 
1371
1579
  var floor = {
1580
+ pure: true,
1372
1581
  name: "floor",
1373
1582
  label: "Round down",
1374
1583
  description: "Round a number down to the nearest integer",
@@ -1397,6 +1606,7 @@ var floor = {
1397
1606
  };
1398
1607
 
1399
1608
  var round = {
1609
+ pure: true,
1400
1610
  name: "round",
1401
1611
  label: "Round",
1402
1612
  description: "Round a number to the nearest integer",
@@ -1425,6 +1635,7 @@ var round = {
1425
1635
  };
1426
1636
 
1427
1637
  var sum = {
1638
+ pure: true,
1428
1639
  name: "sum",
1429
1640
  label: "Sum",
1430
1641
  description: "Sum of all items in a group",
@@ -1475,6 +1686,7 @@ var primitives$8 = (_a$8 = {},
1475
1686
  _a$8);
1476
1687
 
1477
1688
  var joinStrings = {
1689
+ pure: true,
1478
1690
  name: "joinStrings",
1479
1691
  label: "Join Strings",
1480
1692
  description: "Join all strings in a group",
@@ -1503,6 +1715,7 @@ var joinStrings = {
1503
1715
  };
1504
1716
 
1505
1717
  var stringEqualTo = {
1718
+ pure: true,
1506
1719
  name: "stringEqualTo",
1507
1720
  label: "String Equal to",
1508
1721
  description: "Compare string equal and not equal",
@@ -1529,6 +1742,7 @@ var stringEqualTo = {
1529
1742
  };
1530
1743
 
1531
1744
  var stringTemplate = {
1745
+ pure: true,
1532
1746
  name: "stringTemplate",
1533
1747
  label: "String Template",
1534
1748
  description: "Assembles a string from inputs, use ${...} to interpolate inputs",
@@ -1568,6 +1782,7 @@ var stringTemplate = {
1568
1782
  };
1569
1783
 
1570
1784
  var toString = {
1785
+ pure: true,
1571
1786
  name: "toString",
1572
1787
  label: "To String",
1573
1788
  description: "convert to string",
@@ -1599,6 +1814,7 @@ var primitives$7 = (_a$7 = {},
1599
1814
  _a$7);
1600
1815
 
1601
1816
  var filterList = {
1817
+ pure: true,
1602
1818
  name: "filterList",
1603
1819
  label: "Filter List",
1604
1820
  description: "Filters the list by a boolean value",
@@ -1642,6 +1858,7 @@ var filterList = {
1642
1858
  };
1643
1859
 
1644
1860
  var listItem = {
1861
+ pure: true,
1645
1862
  name: "listItem",
1646
1863
  label: "List Item",
1647
1864
  description: "Retrieve the items from the list at the specified indices",
@@ -1690,6 +1907,7 @@ var listItem = {
1690
1907
  };
1691
1908
 
1692
1909
  var listLength = {
1910
+ pure: true,
1693
1911
  name: "listLength",
1694
1912
  label: "List Length",
1695
1913
  description: "Get the length of a list",
@@ -1711,6 +1929,7 @@ var listLength = {
1711
1929
  };
1712
1930
 
1713
1931
  var concat = {
1932
+ pure: true,
1714
1933
  name: "concat",
1715
1934
  label: "Concat Lists",
1716
1935
  description: "Concatenates two lists back to back",
@@ -1737,6 +1956,7 @@ var concat = {
1737
1956
  };
1738
1957
 
1739
1958
  var relativeItem = {
1959
+ pure: true,
1740
1960
  name: "relativeItem",
1741
1961
  label: "Relative Item",
1742
1962
  description: "Pairs each item in the tree with its next item",
@@ -1775,6 +1995,7 @@ var relativeItem = {
1775
1995
  };
1776
1996
 
1777
1997
  var relativeItems = {
1998
+ pure: true,
1778
1999
  name: "relativeItems",
1779
2000
  label: "Relative Items",
1780
2001
  description: "Pairs each item in the tree with an item in another tree at a specified offset",
@@ -1820,6 +2041,7 @@ function isNumStr(str) {
1820
2041
  return !isNaN(Number(str));
1821
2042
  }
1822
2043
  var listInput = {
2044
+ pure: true,
1823
2045
  name: "listInput",
1824
2046
  label: "List Input",
1825
2047
  description: "Input a list",
@@ -1860,6 +2082,7 @@ var listInput = {
1860
2082
  };
1861
2083
 
1862
2084
  var uniqueItems = {
2085
+ pure: true,
1863
2086
  name: "uniqueItems",
1864
2087
  label: "Unique Items",
1865
2088
  description: "Removes duplicate items from a list",
@@ -1896,6 +2119,7 @@ var uniqueItems = {
1896
2119
  };
1897
2120
 
1898
2121
  var coalesce = {
2122
+ pure: true,
1899
2123
  name: "coalesce",
1900
2124
  label: "Coalesce Items",
1901
2125
  description: "Outputs the first item if it's not empty, otherwise the second item",
@@ -1920,6 +2144,7 @@ var coalesce = {
1920
2144
  };
1921
2145
 
1922
2146
  var destructureList = {
2147
+ pure: true,
1923
2148
  name: "destructureList",
1924
2149
  label: "Destructure List",
1925
2150
  description: "Separates an list into a part with the specified values and the rest",
@@ -1944,7 +2169,7 @@ var destructureList = {
1944
2169
  var included = [];
1945
2170
  var excluded = [];
1946
2171
  var matches = [];
1947
- console.log("Destructuring list", list, items);
2172
+ // console.log("Destructuring list", list, items);
1948
2173
  list.forEach(function (value) {
1949
2174
  var m = items.includes(value);
1950
2175
  matches.push(m);
@@ -1990,6 +2215,7 @@ var primitives$6 = (_a$6 = {},
1990
2215
  _a$6);
1991
2216
 
1992
2217
  var splitGroup = {
2218
+ pure: true,
1993
2219
  name: "splitGroup",
1994
2220
  label: "Split Group",
1995
2221
  description: "Splits every item of a group into its own group",
@@ -2009,6 +2235,7 @@ var splitGroup = {
2009
2235
  };
2010
2236
 
2011
2237
  var mergeGroup = {
2238
+ pure: true,
2012
2239
  name: "mergeGroup",
2013
2240
  label: "Merge Group",
2014
2241
  description: "Merge the deepest groups into their parent.",
@@ -2034,6 +2261,7 @@ var mergeGroup = {
2034
2261
  };
2035
2262
 
2036
2263
  var cartesianGroups = {
2264
+ pure: true,
2037
2265
  name: "cartesianGroups",
2038
2266
  label: "Cartesian Groups",
2039
2267
  description: "Duplicate groups such that all pairings are created.",
@@ -2073,6 +2301,7 @@ var cartesianGroups = {
2073
2301
  };
2074
2302
 
2075
2303
  var mergeTree = {
2304
+ pure: true,
2076
2305
  name: "mergeTree",
2077
2306
  label: "Merge Tree",
2078
2307
  description: "Merge groups with the same index into a single tree.",
@@ -2101,6 +2330,7 @@ var mergeTree = {
2101
2330
  };
2102
2331
 
2103
2332
  var simplifyTree = {
2333
+ pure: true,
2104
2334
  name: "simplifyTree",
2105
2335
  label: "Simplify Groups",
2106
2336
  description: "Simplify a tree by removing redundant groups.",
@@ -2123,6 +2353,7 @@ var simplifyTree = {
2123
2353
  };
2124
2354
 
2125
2355
  var groupAll = {
2356
+ pure: true,
2126
2357
  name: "groupAll",
2127
2358
  label: "Group All",
2128
2359
  description: "Adds a group around all groups in the input tree",
@@ -2147,6 +2378,7 @@ var groupAll = {
2147
2378
  };
2148
2379
 
2149
2380
  var normalizeTree = {
2381
+ pure: true,
2150
2382
  name: "normalizeTree",
2151
2383
  label: "Normalize Groups",
2152
2384
  description: "Normalize a tree to consequtive groups and removed empty groups.",
@@ -2176,6 +2408,7 @@ var normalizeTree = {
2176
2408
  };
2177
2409
 
2178
2410
  var filterTree = {
2411
+ pure: true,
2179
2412
  name: "filterTree",
2180
2413
  label: "Filter Tree",
2181
2414
  description: "Filter groups by path matchers",
@@ -2221,6 +2454,7 @@ var filterTree = {
2221
2454
  };
2222
2455
 
2223
2456
  var treeItem = {
2457
+ pure: true,
2224
2458
  name: "treeItem",
2225
2459
  label: "Tree Item",
2226
2460
  description: "Retrieve the groups from a tree at specified indexes",
@@ -2263,6 +2497,7 @@ var primitives$5 = (_a$5 = {},
2263
2497
  _a$5);
2264
2498
 
2265
2499
  var series = {
2500
+ pure: true,
2266
2501
  name: "series",
2267
2502
  label: "Series",
2268
2503
  description: "Create a series of numbers.",
@@ -2303,6 +2538,7 @@ var primitives$4 = (_a$4 = {},
2303
2538
  _a$4);
2304
2539
 
2305
2540
  var booleanAnd = {
2541
+ pure: true,
2306
2542
  name: "booleanAnd",
2307
2543
  label: "And",
2308
2544
  description: "Returns true if both of the items are true",
@@ -2326,6 +2562,7 @@ var booleanAnd = {
2326
2562
  };
2327
2563
 
2328
2564
  var booleanNot = {
2565
+ pure: true,
2329
2566
  name: "booleanNot",
2330
2567
  label: "Not",
2331
2568
  description: "Inverts the input boolean value",
@@ -2348,6 +2585,7 @@ var booleanNot = {
2348
2585
  };
2349
2586
 
2350
2587
  var booleanOr = {
2588
+ pure: true,
2351
2589
  name: "booleanOr",
2352
2590
  label: "Or",
2353
2591
  description: "Returns true if one of the items is true",
@@ -2371,6 +2609,7 @@ var booleanOr = {
2371
2609
  };
2372
2610
 
2373
2611
  var groupAnd = {
2612
+ pure: true,
2374
2613
  name: "groupAnd",
2375
2614
  label: "Group and",
2376
2615
  description: "Returns true if all of the items in a group are true",
@@ -2400,6 +2639,7 @@ var groupAnd = {
2400
2639
  };
2401
2640
 
2402
2641
  var groupOr = {
2642
+ pure: true,
2403
2643
  name: "groupOr",
2404
2644
  label: "Group or",
2405
2645
  description: "Returns true if any of the items in a group are true",
@@ -2429,6 +2669,7 @@ var groupOr = {
2429
2669
  };
2430
2670
 
2431
2671
  var groupStats = {
2672
+ pure: true,
2432
2673
  name: "groupStats",
2433
2674
  label: "Group stats",
2434
2675
  description: "Returns statistics about a group of numbers",
@@ -2493,6 +2734,7 @@ var primitives$3 = (_a$3 = {},
2493
2734
  _a$3);
2494
2735
 
2495
2736
  var inputs = {
2737
+ pure: true,
2496
2738
  name: "inputs",
2497
2739
  label: "Input",
2498
2740
  description: "Data input.",
@@ -2509,6 +2751,7 @@ var inputs = {
2509
2751
  };
2510
2752
 
2511
2753
  var output = {
2754
+ pure: true,
2512
2755
  name: "output",
2513
2756
  label: "Output",
2514
2757
  description: "Data output.",
@@ -2529,6 +2772,7 @@ var primitives$2 = (_a$2 = {},
2529
2772
  _a$2);
2530
2773
 
2531
2774
  var mergeObject = {
2775
+ pure: true,
2532
2776
  name: "mergeObject",
2533
2777
  label: "Merge Object",
2534
2778
  description: "Merges objects in groups",
@@ -2557,6 +2801,7 @@ var mergeObject = {
2557
2801
  };
2558
2802
 
2559
2803
  var object = {
2804
+ pure: true,
2560
2805
  name: "object",
2561
2806
  label: "Object",
2562
2807
  description: "Creates an object",
@@ -2584,6 +2829,7 @@ var object = {
2584
2829
  };
2585
2830
 
2586
2831
  var listToArray = {
2832
+ pure: true,
2587
2833
  name: "listToArray",
2588
2834
  label: "To Array",
2589
2835
  description: "Converts each branch to an array",
@@ -2606,6 +2852,7 @@ var listToArray = {
2606
2852
  };
2607
2853
 
2608
2854
  var objectEntries = {
2855
+ pure: true,
2609
2856
  name: "objectEntries",
2610
2857
  label: "Entries",
2611
2858
  description: "Gets keys and pairs of an object",
@@ -2639,6 +2886,7 @@ var objectEntries = {
2639
2886
  };
2640
2887
 
2641
2888
  var arrayToList = {
2889
+ pure: true,
2642
2890
  name: "arrayToList",
2643
2891
  label: "Array to List",
2644
2892
  description: "Separates array",
@@ -2667,6 +2915,7 @@ var arrayToList = {
2667
2915
  };
2668
2916
 
2669
2917
  var explodeObject = {
2918
+ pure: true,
2670
2919
  name: "explodeObject",
2671
2920
  label: "Explode Object",
2672
2921
  description: "Separates all fields of an object",
@@ -2726,6 +2975,7 @@ var explodeObject = {
2726
2975
  };
2727
2976
 
2728
2977
  var setField = {
2978
+ pure: true,
2729
2979
  name: "setField",
2730
2980
  label: "Set Field",
2731
2981
  description: "Sets a field in an object to a specified value.",
@@ -2765,6 +3015,7 @@ var setField = {
2765
3015
  };
2766
3016
 
2767
3017
  var destructureObject = {
3018
+ pure: true,
2768
3019
  name: "destructureObject",
2769
3020
  label: "Destructure Object",
2770
3021
  description: "Separates an object into a part with the specified fields and the rest",
@@ -2834,6 +3085,8 @@ var primitives$1 = (_a$1 = {},
2834
3085
  var INFERRED = "inferred";
2835
3086
  var ary$1 = __spreadArray([INFERRED], __read(Intl.supportedValuesOf("timeZone")), false);
2836
3087
  var parseDate = {
3088
+ // Empty values fall back to the clock; parsing also logs to the console.
3089
+ pure: false,
2837
3090
  name: "parseDate",
2838
3091
  label: "Parse",
2839
3092
  description: "Parses a date string",
@@ -2871,6 +3124,8 @@ var parseDate = {
2871
3124
 
2872
3125
  var ary = Intl.supportedValuesOf("timeZone");
2873
3126
  var formatDate = {
3127
+ // Empty values fall back to the clock; omitted options use host locale/timezone.
3128
+ pure: false,
2874
3129
  name: "formatDate",
2875
3130
  label: "Format",
2876
3131
  description: "Formats a date",
@@ -2990,6 +3245,7 @@ var formatDate = {
2990
3245
  };
2991
3246
 
2992
3247
  var duration = {
3248
+ pure: true,
2993
3249
  name: "duration",
2994
3250
  label: "Duration",
2995
3251
  description: "Creates a duration",
@@ -3030,6 +3286,8 @@ var duration = {
3030
3286
  };
3031
3287
 
3032
3288
  var isoDate = {
3289
+ // Empty values fall back to the current clock.
3290
+ pure: false,
3033
3291
  name: "isoDate",
3034
3292
  label: "To ISO",
3035
3293
  description: "ISO 8601 format of a date",
@@ -3055,6 +3313,8 @@ var isoDate = {
3055
3313
  };
3056
3314
 
3057
3315
  var today = {
3316
+ // Reads the current clock on every evaluation.
3317
+ pure: false,
3058
3318
  name: "today",
3059
3319
  label: "Today",
3060
3320
  description: "The date of today",
@@ -3121,31 +3381,49 @@ function normalizeVarDef(varDef) {
3121
3381
  return varDef;
3122
3382
  }
3123
3383
  function getReferences(inputs) {
3124
- var references = [];
3125
- Object.entries(inputs).forEach(function (_a) {
3384
+ return Object.entries(inputs).flatMap(function (_a) {
3126
3385
  var _b = __read(_a, 2), name = _b[0], value = _b[1];
3127
- var values = Array.isArray(value) ? value : [value];
3128
- values.forEach(function (value) {
3129
- if (!isReference(value)) {
3130
- return;
3131
- }
3132
- var path = parseReference(value);
3386
+ return getReferencePaths(value).map(function (path) {
3133
3387
  var parts = path.split(".");
3134
- references.push({
3388
+ return {
3135
3389
  name: name,
3136
3390
  path: path,
3137
3391
  parts: parts,
3138
3392
  refNode: parts[0],
3139
3393
  refField: parts.slice(1).join("."),
3140
- });
3394
+ };
3141
3395
  });
3142
3396
  });
3143
- return references;
3144
3397
  }
3145
- function topSort(fn) {
3398
+ function getExecutionOrder(fn) {
3146
3399
  var ordered = [];
3147
3400
  var visiting = new Set();
3148
3401
  var done = new Set();
3402
+ var body = fn.body || {};
3403
+ var nodeIds = new Map();
3404
+ Object.keys(body).forEach(function (id) {
3405
+ var referenceId = safeName(id);
3406
+ if (referenceId === "inputs") {
3407
+ throw new Error("Node ID \"".concat(id, "\" is reserved for graph inputs"));
3408
+ }
3409
+ if (nodeIds.has(referenceId)) {
3410
+ throw new Error("Ambiguous node reference \"".concat(referenceId, "\": \"").concat(nodeIds.get(referenceId), "\" and \"").concat(id, "\""));
3411
+ }
3412
+ nodeIds.set(referenceId, id);
3413
+ });
3414
+ var resolve = function (ref, location) {
3415
+ if (ref.parts.length < 2 || ref.parts.some(function (part) { return !part; })) {
3416
+ throw new Error("Invalid reference <".concat(ref.path, "> in ").concat(location, ".").concat(ref.name));
3417
+ }
3418
+ // Public inputs can be supplied at runtime without static definitions.
3419
+ if (ref.refNode === "inputs")
3420
+ return;
3421
+ var id = nodeIds.get(ref.refNode);
3422
+ if (id === undefined) {
3423
+ throw new Error("Reference <".concat(ref.path, "> in ").concat(location, ".").concat(ref.name, " points to missing node \"").concat(ref.refNode, "\""));
3424
+ }
3425
+ return id;
3426
+ };
3149
3427
  var visit = function (id) {
3150
3428
  // if already done, return
3151
3429
  if (done.has(id))
@@ -3156,19 +3434,11 @@ function topSort(fn) {
3156
3434
  }
3157
3435
  // mark as visiting
3158
3436
  visiting.add(id);
3159
- var fnCall = fn.body[id];
3160
- if (!fnCall) {
3161
- console.warn("Function ".concat(id, " not found in body"), fn);
3162
- }
3163
- // check the inputs and visit them
3164
- Object.values(fnCall.inputs || {}).forEach(function (input) {
3165
- if (isReference(input)) {
3166
- var _a = __read(parseReference(input).split("."), 1), id_1 = _a[0];
3167
- // visit inputs
3168
- if (id_1 !== "inputs") {
3169
- visit(id_1);
3170
- }
3171
- }
3437
+ var fnCall = body[id];
3438
+ getReferences(fnCall.inputs || {}).forEach(function (ref) {
3439
+ var dependency = resolve(ref, "node \"".concat(id, "\" input"));
3440
+ if (dependency !== undefined)
3441
+ visit(dependency);
3172
3442
  });
3173
3443
  // push to end of the list
3174
3444
  ordered.push(id);
@@ -3177,7 +3447,12 @@ function topSort(fn) {
3177
3447
  // mark as done
3178
3448
  done.add(id);
3179
3449
  };
3180
- Object.keys(fn.body).forEach(visit);
3450
+ Object.keys(body).forEach(visit);
3451
+ getReferences(fn.outputs || {}).forEach(function (ref) { return resolve(ref, "output"); });
3452
+ return ordered;
3453
+ }
3454
+ function topSort(fn) {
3455
+ var ordered = getExecutionOrder(fn);
3181
3456
  var orderedBody = Object.fromEntries(ordered.map(function (id) { return [id, fn.body[id]]; }));
3182
3457
  return __assign(__assign({}, fn), { body: orderedBody });
3183
3458
  }
@@ -3189,41 +3464,161 @@ function getDefault(varDef, inputs) {
3189
3464
  }
3190
3465
  return normDef.default;
3191
3466
  }
3467
+ var removedReference = Symbol("removedReference");
3468
+ // Copy only containers that change, retaining unrelated values and references.
3469
+ // A removed standalone reference is omitted; in a template it becomes empty text.
3470
+ function removeReferences(value, matches) {
3471
+ if (isReference(value)) {
3472
+ return matches(value) ? removedReference : value;
3473
+ }
3474
+ if (typeof value === "string") {
3475
+ return value.replace(/<.*?>/g, function (ref) {
3476
+ return isReference(ref) && matches(ref) ? "" : ref;
3477
+ });
3478
+ }
3479
+ if (Array.isArray(value)) {
3480
+ var changed_1 = false;
3481
+ var items_1 = [];
3482
+ value.forEach(function (item) {
3483
+ var next = removeReferences(item, matches);
3484
+ if (next !== item)
3485
+ changed_1 = true;
3486
+ if (next !== removedReference)
3487
+ items_1.push(next);
3488
+ });
3489
+ return changed_1 ? items_1 : value;
3490
+ }
3491
+ if (value && typeof value === "object") {
3492
+ var prototype = Object.getPrototypeOf(value);
3493
+ if (prototype !== Object.prototype && prototype !== null)
3494
+ return value;
3495
+ var changed_2 = false;
3496
+ var entries_1 = [];
3497
+ Object.entries(value).forEach(function (_a) {
3498
+ var _b = __read(_a, 2), key = _b[0], item = _b[1];
3499
+ var next = removeReferences(item, matches);
3500
+ if (next !== item)
3501
+ changed_2 = true;
3502
+ if (next !== removedReference)
3503
+ entries_1.push([key, next]);
3504
+ });
3505
+ return changed_2 ? Object.fromEntries(entries_1) : value;
3506
+ }
3507
+ return value;
3508
+ }
3192
3509
  var Engine = /** @class */ (function () {
3193
3510
  function Engine(morePrimitives, env) {
3194
3511
  if (morePrimitives === void 0) { morePrimitives = {}; }
3195
3512
  if (env === void 0) { env = {}; }
3513
+ this.graphDefinitions = new WeakMap();
3514
+ this.automaticMounts = new Map();
3196
3515
  this.listeners = {};
3197
- this.cache = {};
3198
- this.cacheMiss = Symbol("cacheMiss");
3516
+ this.cache = new ExecutionCache();
3517
+ this.graphRunners = new WeakMap();
3518
+ this.executions = new WeakMap();
3519
+ this.latestRuns = new WeakMap();
3199
3520
  this.context = null;
3200
3521
  this.fnIndex = __assign(__assign({}, primitives), morePrimitives);
3201
3522
  this.env = env;
3202
3523
  }
3203
- Engine.prototype.checkCache = function (fnName, inputs) {
3204
- if (!this.cache[fnName]) {
3205
- return this.cacheMiss;
3206
- }
3207
- // TODO: need to check the interpolated inputs, as the references can be the same
3208
- // however, the interpolation does create new objects
3209
- return {};
3524
+ /** Clear successful results; running calls finish but cannot refill invalidated entries. */
3525
+ Engine.prototype.clearCache = function (options) {
3526
+ if (options === void 0) { options = {}; }
3527
+ this.cache.clear(options);
3210
3528
  };
3211
- Engine.prototype.runGraph = function (node, inputs, params) {
3529
+ Engine.prototype.executeCall = function (fn_1, call_1, inputs_1, params_1, context_1, name_1, executionId_1, run_1, path_1) {
3530
+ return __awaiter(this, arguments, void 0, function (fn, call, inputs, params, context, name, executionId, run, path, root) {
3531
+ var graphRunner, kind, hit, startTime, start, result, createdAt, impl, _a, endTime, event;
3532
+ if (root === void 0) { root = false; }
3533
+ return __generator(this, function (_b) {
3534
+ switch (_b.label) {
3535
+ case 0:
3536
+ this.cache.visit(run, path);
3537
+ graphRunner = this.graphRunners.get(fn);
3538
+ kind = graphRunner
3539
+ ? undefined
3540
+ : fn.pure
3541
+ ? "pure"
3542
+ : run.options.mode === "preview" && fn.previewCache
3543
+ ? "preview"
3544
+ : undefined;
3545
+ hit = kind
3546
+ ? this.cache.get(run, path, kind, fn, call, inputs, params)
3547
+ : undefined;
3548
+ startTime = performance.now();
3549
+ start = {
3550
+ name: name,
3551
+ fn: call.name,
3552
+ inputs: inputs,
3553
+ params: params,
3554
+ executionId: executionId,
3555
+ context: context,
3556
+ startTime: startTime,
3557
+ };
3558
+ if (!hit) return [3 /*break*/, 1];
3559
+ result = hit.result;
3560
+ createdAt = hit.info.createdAt;
3561
+ return [3 /*break*/, 8];
3562
+ case 1:
3563
+ context.activations[name] = true;
3564
+ impl = fn.impl;
3565
+ console.log("Executing function call: ".concat(name));
3566
+ _b.label = 2;
3567
+ case 2:
3568
+ _b.trys.push([2, , 7, 8]);
3569
+ this.fireEvent("functionCall", start);
3570
+ if (!graphRunner) return [3 /*break*/, 4];
3571
+ return [4 /*yield*/, graphRunner(inputs, params, run, path)];
3572
+ case 3:
3573
+ _a = (_b.sent()).result;
3574
+ return [3 /*break*/, 6];
3575
+ case 4: return [4 /*yield*/, impl.call(fn, inputs, params, this, root ? null : context, name)];
3576
+ case 5:
3577
+ _a = _b.sent();
3578
+ _b.label = 6;
3579
+ case 6:
3580
+ result = _a;
3581
+ createdAt = Date.now();
3582
+ if (kind)
3583
+ this.cache.set(run, path, kind, fn, call, inputs, params, result, impl, createdAt);
3584
+ return [3 /*break*/, 8];
3585
+ case 7:
3586
+ context.activations[name] = false;
3587
+ context.timings[name] = performance.now() - startTime;
3588
+ return [7 /*endfinally*/];
3589
+ case 8:
3590
+ endTime = performance.now();
3591
+ context.activations[name] = false;
3592
+ context.timings[name] = endTime - startTime;
3593
+ context.scope[name] = result;
3594
+ event = __assign(__assign({}, start), { result: result, endTime: endTime, duration: endTime - startTime, cached: !!hit, cache: kind ? { kind: kind, createdAt: createdAt } : undefined });
3595
+ // Hits still notify subscribers and populate a fresh context for the editor.
3596
+ this.fireEvent("functionResult", event);
3597
+ return [2 /*return*/, event];
3598
+ }
3599
+ });
3600
+ });
3601
+ };
3602
+ Engine.prototype.runGraph = function (node, suppliedInputs, params, executionOrder, run, path) {
3212
3603
  return __awaiter(this, void 0, void 0, function () {
3213
- var _a, body, executionId, context, startTime, _b, _c, _d, _i, name_1, fnCall, fn, inputs_1, params_1, result_1, cacheResult, startTime_1, endTime_1, result, endTime, response;
3214
- return __generator(this, function (_e) {
3215
- switch (_e.label) {
3604
+ var _a, body, executionId, defaults, mappedDefaults, inputs, context, startTime, executionOrder_1, executionOrder_1_1, name_1, fnCall, fn, callPath, inputs_1, params_1, e_1_1, result, endTime, response;
3605
+ var e_1, _b;
3606
+ return __generator(this, function (_c) {
3607
+ switch (_c.label) {
3216
3608
  case 0:
3217
3609
  _a = node.body, body = _a === void 0 ? {} : _a;
3218
3610
  executionId = uid$1();
3219
- // add input defaults
3611
+ defaults = {};
3220
3612
  Object.entries(node.inputs || {}).forEach(function (_a) {
3221
3613
  var _b = __read(_a, 2), name = _b[0], def = _b[1];
3222
3614
  var normDef = normalizeVarDef(def);
3223
- if (inputs[name] === undefined && normDef.default !== undefined) {
3224
- inputs[name] = getDefault(normDef, inputs);
3615
+ if (suppliedInputs[name] === undefined &&
3616
+ normDef.default !== undefined) {
3617
+ defaults[name] = getDefault(normDef, suppliedInputs);
3225
3618
  }
3226
3619
  });
3620
+ mappedDefaults = this.cache.interpolate(run, __spreadArray(__spreadArray([], __read(path), false), ["$defaults"], false), defaults, {});
3621
+ inputs = __assign(__assign({}, suppliedInputs), mappedDefaults);
3227
3622
  context = {
3228
3623
  scope: { inputs: inputs },
3229
3624
  calls: {},
@@ -3232,76 +3627,46 @@ var Engine = /** @class */ (function () {
3232
3627
  timings: {},
3233
3628
  activations: {},
3234
3629
  };
3630
+ this.executions.set(context, { run: run, path: path });
3235
3631
  startTime = performance.now();
3236
- _b = body;
3237
- _c = [];
3238
- for (_d in _b)
3239
- _c.push(_d);
3240
- _i = 0;
3241
- _e.label = 1;
3632
+ _c.label = 1;
3242
3633
  case 1:
3243
- if (!(_i < _c.length)) return [3 /*break*/, 5];
3244
- _d = _c[_i];
3245
- if (!(_d in _b)) return [3 /*break*/, 4];
3246
- name_1 = _d;
3634
+ _c.trys.push([1, 6, 7, 8]);
3635
+ executionOrder_1 = __values(executionOrder), executionOrder_1_1 = executionOrder_1.next();
3636
+ _c.label = 2;
3637
+ case 2:
3638
+ if (!!executionOrder_1_1.done) return [3 /*break*/, 5];
3639
+ name_1 = executionOrder_1_1.value;
3247
3640
  fnCall = body[name_1];
3248
3641
  fn = this.fnIndex[fnCall.name];
3249
- if (!fn) {
3642
+ if (!fn)
3250
3643
  throw new Error("function ".concat(fnCall.name, " not found in index"));
3251
- }
3252
- inputs_1 = interpolate(fnCall.inputs || {}, context.scope);
3644
+ callPath = __spreadArray(__spreadArray([], __read(path), false), [name_1], false);
3645
+ inputs_1 = this.cache.interpolate(run, __spreadArray(__spreadArray([], __read(callPath), false), ["$inputs"], false), fnCall.inputs || {}, context.scope);
3253
3646
  params_1 = fnCall.params || {};
3254
- result_1 = {};
3255
3647
  context.calls[name_1] = fnCall;
3256
3648
  context.inputs[name_1] = inputs_1;
3257
3649
  context.params[name_1] = params_1;
3258
- cacheResult = this.checkCache(name_1, inputs_1);
3259
- if (!(cacheResult !== this.cacheMiss)) return [3 /*break*/, 2];
3260
- // use as result
3261
- result_1 = cacheResult;
3262
- // store the result in the scope
3263
- context.scope[name_1] = result_1;
3264
- return [3 /*break*/, 4];
3265
- case 2:
3266
- // cache miss, call the function implementation
3267
- context.activations[name_1] = true;
3268
- startTime_1 = performance.now();
3269
- this.fireEvent("functionCall", {
3270
- name: name_1,
3271
- fn: fnCall.name,
3272
- inputs: inputs_1,
3273
- params: params_1,
3274
- executionId: executionId,
3275
- context: context,
3276
- startTime: startTime_1,
3277
- });
3278
- return [4 /*yield*/, fn.impl(inputs_1, params_1, this, context, name_1)];
3650
+ return [4 /*yield*/, this.executeCall(fn, fnCall, inputs_1, params_1, context, name_1, executionId, run, callPath)];
3279
3651
  case 3:
3280
- // call the implentation of sub functions
3281
- result_1 = _e.sent();
3282
- endTime_1 = performance.now();
3283
- context.activations[name_1] = false;
3284
- context.timings[name_1] = endTime_1 - startTime_1;
3285
- // store the result in the scope
3286
- context.scope[name_1] = result_1;
3287
- this.fireEvent("functionResult", {
3288
- name: name_1,
3289
- fn: fnCall.name,
3290
- inputs: inputs_1,
3291
- params: params_1,
3292
- executionId: executionId,
3293
- context: context,
3294
- result: result_1,
3295
- startTime: startTime_1,
3296
- endTime: endTime_1,
3297
- duration: endTime_1 - startTime_1,
3298
- });
3299
- _e.label = 4;
3652
+ _c.sent();
3653
+ _c.label = 4;
3300
3654
  case 4:
3301
- _i++;
3302
- return [3 /*break*/, 1];
3303
- case 5:
3304
- result = interpolate(node.outputs || {}, context.scope);
3655
+ executionOrder_1_1 = executionOrder_1.next();
3656
+ return [3 /*break*/, 2];
3657
+ case 5: return [3 /*break*/, 8];
3658
+ case 6:
3659
+ e_1_1 = _c.sent();
3660
+ e_1 = { error: e_1_1 };
3661
+ return [3 /*break*/, 8];
3662
+ case 7:
3663
+ try {
3664
+ if (executionOrder_1_1 && !executionOrder_1_1.done && (_b = executionOrder_1.return)) _b.call(executionOrder_1);
3665
+ }
3666
+ finally { if (e_1) throw e_1.error; }
3667
+ return [7 /*endfinally*/];
3668
+ case 8:
3669
+ result = this.cache.interpolate(run, __spreadArray(__spreadArray([], __read(path), false), ["$outputs"], false), node.outputs || {}, context.scope);
3305
3670
  endTime = performance.now();
3306
3671
  response = {
3307
3672
  name: node.name,
@@ -3337,6 +3702,16 @@ var Engine = /** @class */ (function () {
3337
3702
  return node;
3338
3703
  }
3339
3704
  var _a = node.body, body = _a === void 0 ? {} : _a, props = __rest(node, ["body"]);
3705
+ // Validate before registering or mounting, preserving the last working
3706
+ // definition if an edit introduces a broken reference or cycle.
3707
+ var executionOrder = getExecutionOrder(node);
3708
+ executionOrder.forEach(function (id) {
3709
+ var call = body[id];
3710
+ if (!Object.prototype.hasOwnProperty.call(_this.fnIndex, call.name) ||
3711
+ !_this.fnIndex[call.name]) {
3712
+ throw new Error("function ".concat(call.name, " not found in index (node \"").concat(id, "\")"));
3713
+ }
3714
+ });
3340
3715
  // create a primitive function, one that has an implementation and optional mounting function
3341
3716
  var primitive = __assign(__assign({}, props), { outputs: Object.fromEntries(Object.entries(node.outputs || {}).map(function (_a) {
3342
3717
  var _b = __read(_a, 2), key = _b[0]; _b[1];
@@ -3344,8 +3719,9 @@ var Engine = /** @class */ (function () {
3344
3719
  })), mount: function (trigger) {
3345
3720
  // mount all the nodes
3346
3721
  var unsubs = [];
3347
- Object.values(body).forEach(function (n) {
3722
+ executionOrder.forEach(function (id) {
3348
3723
  var _a;
3724
+ var n = body[id];
3349
3725
  var fn = _this.fnIndex[n.name];
3350
3726
  if (!fn) {
3351
3727
  console.warn("function ".concat(n.name, " not found in index"));
@@ -3357,7 +3733,7 @@ var Engine = /** @class */ (function () {
3357
3733
  }
3358
3734
  });
3359
3735
  return function () {
3360
- var e_1, _a;
3736
+ var e_2, _a;
3361
3737
  try {
3362
3738
  // console.log(`Unmounting function: ${node.name}`);
3363
3739
  // unmount all the nodes
@@ -3366,35 +3742,48 @@ var Engine = /** @class */ (function () {
3366
3742
  unsub();
3367
3743
  }
3368
3744
  }
3369
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
3745
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
3370
3746
  finally {
3371
3747
  try {
3372
3748
  if (unsubs_1_1 && !unsubs_1_1.done && (_a = unsubs_1.return)) _a.call(unsubs_1);
3373
3749
  }
3374
- finally { if (e_1) throw e_1.error; }
3750
+ finally { if (e_2) throw e_2.error; }
3375
3751
  }
3376
3752
  };
3377
- }, impl: function (inputs, params, engine) { return __awaiter(_this, void 0, void 0, function () {
3378
- var response;
3753
+ }, impl: function (inputs, params, engine, context, name) { return __awaiter(_this, void 0, void 0, function () {
3754
+ var parent, run, path, response;
3379
3755
  return __generator(this, function (_a) {
3380
3756
  switch (_a.label) {
3381
- case 0: return [4 /*yield*/, engine.runGraph(node, inputs, params)];
3757
+ case 0:
3758
+ parent = context && engine.executions.get(context);
3759
+ run = (parent === null || parent === void 0 ? void 0 : parent.run) || engine.cache.begin(node.name, {});
3760
+ path = parent ? __spreadArray(__spreadArray([], __read(parent.path), false), [name], false) : ["_root"];
3761
+ return [4 /*yield*/, engine.runGraph(node, inputs, params, executionOrder, run, path)];
3382
3762
  case 1:
3383
3763
  response = _a.sent();
3764
+ if (!parent)
3765
+ engine.cache.finish(run);
3384
3766
  return [2 /*return*/, response.result];
3385
3767
  }
3386
3768
  });
3387
3769
  }); } });
3770
+ this.graphRunners.set(primitive, function (inputs, params, run, path) {
3771
+ return _this.runGraph(node, inputs, params, executionOrder, run, path);
3772
+ });
3388
3773
  // register the primitive
3389
3774
  this.fnIndex[primitive.name] = primitive;
3775
+ this.graphDefinitions.set(primitive, node);
3390
3776
  return primitive;
3391
3777
  };
3392
- Engine.prototype.mount = function (node) {
3778
+ Engine.prototype.mount = function (node, inputs, options) {
3393
3779
  var _this = this;
3394
3780
  var _a;
3781
+ if (inputs === void 0) { inputs = {}; }
3782
+ if (options === void 0) { options = {}; }
3395
3783
  return (_a = node.mount) === null || _a === void 0 ? void 0 : _a.call(node, function () {
3396
- // console.log(`Triggering node: ${node.name}`);
3397
- _this.run(node);
3784
+ var _a, _b;
3785
+ var latest = _this.latestRuns.get(node);
3786
+ void _this.run(node, (_a = latest === null || latest === void 0 ? void 0 : latest.inputs) !== null && _a !== void 0 ? _a : inputs, (_b = latest === null || latest === void 0 ? void 0 : latest.options) !== null && _b !== void 0 ? _b : options);
3398
3787
  });
3399
3788
  };
3400
3789
  Engine.prototype.getContext = function () {
@@ -3413,138 +3802,188 @@ var Engine = /** @class */ (function () {
3413
3802
  };
3414
3803
  };
3415
3804
  Engine.prototype.fireEvent = function (eventName, event) {
3416
- var e_2, _a;
3805
+ var e_3, _a;
3417
3806
  try {
3418
3807
  for (var _b = __values(this.listeners[eventName] || []), _c = _b.next(); !_c.done; _c = _b.next()) {
3419
3808
  var listener = _c.value;
3420
3809
  listener(event);
3421
3810
  }
3422
3811
  }
3423
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
3812
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
3424
3813
  finally {
3425
3814
  try {
3426
3815
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3427
3816
  }
3428
- finally { if (e_2) throw e_2.error; }
3817
+ finally { if (e_3) throw e_3.error; }
3429
3818
  }
3430
3819
  };
3431
3820
  Engine.prototype.run = function (node_1) {
3432
- return __awaiter(this, arguments, void 0, function (node, inputs) {
3433
- var builtFn, mappedInputs, result;
3821
+ return __awaiter(this, arguments, void 0, function (node, inputs, options) {
3822
+ if (inputs === void 0) { inputs = {}; }
3823
+ if (options === void 0) { options = {}; }
3824
+ return __generator(this, function (_a) {
3825
+ switch (_a.label) {
3826
+ case 0: return [4 /*yield*/, this.runDetailed(node, inputs, options)];
3827
+ case 1: return [2 /*return*/, (_a.sent()).result];
3828
+ }
3829
+ });
3830
+ });
3831
+ };
3832
+ Engine.prototype.runDetailed = function (node_1) {
3833
+ return __awaiter(this, arguments, void 0, function (node, inputs, options) {
3834
+ var builtFn, rebuilt, mounted, unmount, run, mappedInputs, runner, response, context;
3434
3835
  var _a;
3435
3836
  if (inputs === void 0) { inputs = {}; }
3837
+ if (options === void 0) { options = {}; }
3436
3838
  return __generator(this, function (_b) {
3437
3839
  switch (_b.label) {
3438
3840
  case 0:
3439
3841
  if (!isPrimitive(node)) {
3440
3842
  builtFn = this.getFunction(node.name);
3441
- if (!builtFn) {
3442
- // not yet build
3843
+ rebuilt = false;
3844
+ // Graphs are edited immutably: the name identifies a registry slot,
3845
+ // while object identity tells us whether its definition is current.
3846
+ if (!builtFn || this.graphDefinitions.get(builtFn) !== node) {
3443
3847
  builtFn = this.build(node);
3444
- // mount if needed
3445
- this.mount(builtFn);
3848
+ rebuilt = true;
3849
+ }
3850
+ mounted = this.automaticMounts.get(node.name);
3851
+ if (rebuilt || (mounted && mounted.fn !== builtFn)) {
3852
+ // Only replace subscriptions owned by run(); explicit mount()
3853
+ // callers retain ownership of their cleanup callbacks.
3854
+ (_a = mounted === null || mounted === void 0 ? void 0 : mounted.unmount) === null || _a === void 0 ? void 0 : _a.call(mounted);
3855
+ this.automaticMounts.delete(node.name);
3856
+ unmount = this.mount(builtFn);
3857
+ this.automaticMounts.set(node.name, {
3858
+ fn: builtFn,
3859
+ unmount: unmount || undefined,
3860
+ });
3446
3861
  }
3447
- return [2 /*return*/, this.run(builtFn, inputs)];
3862
+ node = builtFn;
3448
3863
  }
3449
- mappedInputs = interpolate(inputs, {});
3450
- return [4 /*yield*/, ((_a = node.impl) === null || _a === void 0 ? void 0 : _a.call(node, mappedInputs, {}, this, null, "_root"))];
3864
+ this.latestRuns.set(node, { inputs: inputs, options: __assign({}, options) });
3865
+ run = this.cache.begin(node.name, options);
3866
+ mappedInputs = this.cache.interpolate(run, ["$inputs"], inputs, {});
3867
+ runner = this.graphRunners.get(node);
3868
+ if (!runner) return [3 /*break*/, 2];
3869
+ return [4 /*yield*/, runner(mappedInputs, {}, run, ["_root"])];
3451
3870
  case 1:
3452
- result = _b.sent();
3453
- // console.log("Engine run complete", result);
3454
- return [2 /*return*/, result];
3871
+ response = _b.sent();
3872
+ return [3 /*break*/, 4];
3873
+ case 2:
3874
+ context = {
3875
+ scope: { inputs: mappedInputs },
3876
+ calls: { _root: { name: node.name } },
3877
+ inputs: { _root: mappedInputs },
3878
+ params: { _root: {} },
3879
+ timings: {},
3880
+ activations: {},
3881
+ };
3882
+ return [4 /*yield*/, this.executeCall(node, context.calls._root, mappedInputs, {}, context, "_root", uid$1(), run, ["_root"], true)];
3883
+ case 3:
3884
+ response = _b.sent();
3885
+ response = __assign(__assign({}, response), { name: node.name, fn: "root" });
3886
+ this.fireEvent("result", response);
3887
+ this.context = context;
3888
+ _b.label = 4;
3889
+ case 4:
3890
+ this.cache.finish(run);
3891
+ return [2 /*return*/, response];
3455
3892
  }
3456
3893
  });
3457
3894
  });
3458
3895
  };
3459
- Engine.prototype.runDetailed = function (node_1) {
3460
- return __awaiter(this, arguments, void 0, function (node, inputs) {
3461
- var _this = this;
3462
- if (inputs === void 0) { inputs = {}; }
3463
- return __generator(this, function (_a) {
3464
- return [2 /*return*/, new Promise(function (resolve, reject) {
3465
- var unsub = _this.subscribe("result", function (event) {
3466
- if (event.name === node.name) {
3467
- resolve(event);
3468
- unsub();
3469
- }
3470
- });
3471
- _this.run(node, inputs).catch(function (e) {
3472
- unsub();
3473
- reject(e);
3474
- });
3475
- })];
3476
- });
3477
- });
3478
- };
3479
3896
  Engine.prototype.getFunction = function (name) {
3480
3897
  return this.fnIndex[name];
3481
3898
  };
3482
3899
  // node handlers
3483
3900
  Engine.prototype.applyNodeDelete = function (oldFn, nodeIds) {
3484
- var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
3485
- if (nodeIds.every(function (id) { return id === "output"; })) {
3486
- // cannot delete output node
3901
+ var deletedIds = new Set(nodeIds.filter(function (id) { return id !== "output"; }));
3902
+ if (!deletedIds.size) {
3903
+ // The generated output node is protected, including in bulk deletes.
3487
3904
  return oldFn;
3488
3905
  }
3489
- if (nodeIds.includes("inputs")) {
3906
+ var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
3907
+ if (deletedIds.has("inputs")) {
3490
3908
  delete newFn.inputs;
3491
3909
  }
3492
- nodeIds.forEach(function (id) {
3910
+ deletedIds.forEach(function (id) {
3493
3911
  delete newFn.body[id];
3494
3912
  });
3495
- // remove any references to the deleted nodes
3913
+ var matches = function (ref) {
3914
+ return deletedIds.has(parseReference(ref).split(".")[0]);
3915
+ };
3916
+ // Clone affected nodes as well as their inputs so shallow comparisons work.
3496
3917
  Object.entries(newFn.body).forEach(function (_a) {
3497
3918
  var _b = __read(_a, 2), id = _b[0], node = _b[1];
3498
- Object.entries(node.inputs || {}).forEach(function (_a) {
3499
- var _b;
3500
- var _c = __read(_a, 2), name = _c[0], value = _c[1];
3501
- if (isReference(value)) {
3502
- var path = parseReference(value);
3503
- var parts = path.split(".");
3504
- if (nodeIds.includes(parts[0])) {
3505
- (_b = newFn.body[id].inputs) === null || _b === void 0 ? true : delete _b[name];
3506
- }
3919
+ if (!node.inputs)
3920
+ return;
3921
+ var inputs = removeReferences(node.inputs, matches);
3922
+ if (inputs !== node.inputs) {
3923
+ newFn.body[id] = __assign(__assign({}, node), { inputs: inputs });
3924
+ }
3925
+ });
3926
+ Object.entries(oldFn.outputs || {}).forEach(function (_a) {
3927
+ var _b = __read(_a, 2), name = _b[0], value = _b[1];
3928
+ var next = removeReferences(value, matches);
3929
+ if (next !== value) {
3930
+ if (newFn.outputs === oldFn.outputs) {
3931
+ newFn.outputs = __assign({}, oldFn.outputs);
3507
3932
  }
3508
- });
3933
+ // Keep the public port, matching explicit output-edge deletion.
3934
+ newFn.outputs[name] = next === removedReference ? "" : next;
3935
+ }
3509
3936
  });
3510
3937
  return newFn;
3511
3938
  };
3512
3939
  Engine.prototype.applyEdgeDelete = function (oldFn, fromNode, toNode, fromField, toField) {
3513
3940
  var _a, _b;
3514
- var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body), outputs: __assign({}, oldFn.outputs) });
3941
+ var _c, _d, _e;
3942
+ var matches = function (ref) { return ref === "<".concat(fromNode, ".").concat(fromField, ">"); };
3515
3943
  if (toNode === "output") {
3516
- // deleting of output edges
3517
- if ((_a = newFn.outputs) === null || _a === void 0 ? void 0 : _a[toField]) {
3518
- // set to empty to prevent port from being removed, as that would cause the output node to be deleted
3519
- newFn.outputs[toField] = "";
3520
- }
3521
- return newFn;
3522
- }
3523
- var to = newFn.body[toNode];
3944
+ var value_1 = (_c = oldFn.outputs) === null || _c === void 0 ? void 0 : _c[toField];
3945
+ if (value_1 === undefined)
3946
+ return oldFn;
3947
+ var next_1 = removeReferences(value_1, matches);
3948
+ if (next_1 === value_1)
3949
+ return oldFn;
3950
+ return __assign(__assign({}, oldFn), { outputs: __assign(__assign({}, oldFn.outputs), (_a = {}, _a[toField] = next_1 === removedReference ? "" : next_1, _a)) });
3951
+ }
3952
+ var to = oldFn.body[toNode];
3524
3953
  var fn = this.fnIndex[to === null || to === void 0 ? void 0 : to.name];
3525
3954
  if (!to) {
3526
3955
  console.warn("Invalid nodes for edge deletion");
3527
- return newFn;
3956
+ return oldFn;
3528
3957
  }
3529
3958
  if (!fn) {
3530
3959
  console.warn("Function ".concat(to === null || to === void 0 ? void 0 : to.name, " not found in index, which is unexpected as you are deleting an edge to it."));
3531
- return newFn;
3960
+ return oldFn;
3961
+ }
3962
+ var value = (_d = to.inputs) === null || _d === void 0 ? void 0 : _d[toField];
3963
+ if (value === undefined) {
3964
+ console.warn("No matching edge found to delete");
3965
+ return oldFn;
3532
3966
  }
3533
- if (to.inputs && to.inputs[toField] === "<".concat(fromNode, ".").concat(fromField, ">")) {
3534
- // delete the incoming edge
3535
- delete to.inputs[toField];
3967
+ var next = removeReferences(value, matches);
3968
+ if (next === value) {
3969
+ console.warn("No matching edge found to delete");
3970
+ return oldFn;
3971
+ }
3972
+ var inputs = __assign({}, to.inputs);
3973
+ if (next === removedReference) {
3974
+ delete inputs[toField];
3536
3975
  // revert to default value if exists
3537
- if ((_b = fn.inputs) === null || _b === void 0 ? void 0 : _b[toField]) {
3976
+ if ((_e = fn.inputs) === null || _e === void 0 ? void 0 : _e[toField]) {
3538
3977
  var normDef = normalizeVarDef(fn.inputs[toField]);
3539
3978
  if (normDef.default !== undefined) {
3540
- to.inputs[toField] = getDefault(normDef, to.inputs);
3979
+ inputs[toField] = getDefault(normDef, inputs);
3541
3980
  }
3542
3981
  }
3543
3982
  }
3544
3983
  else {
3545
- console.warn("No matching edge found to delete");
3984
+ inputs[toField] = next;
3546
3985
  }
3547
- return newFn;
3986
+ return __assign(__assign({}, oldFn), { body: __assign(__assign({}, oldFn.body), (_b = {}, _b[toNode] = __assign(__assign({}, to), { inputs: inputs }), _b)) });
3548
3987
  };
3549
3988
  Engine.prototype.applyNodeAdd = function (oldFn, nodeName, callback) {
3550
3989
  var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
@@ -3591,25 +4030,20 @@ var Engine = /** @class */ (function () {
3591
4030
  return topSort(newFn);
3592
4031
  };
3593
4032
  Engine.prototype.applyNodeConnect = function (oldFn, fromNode, toNode, fromField, toField) {
3594
- var _a;
4033
+ var _a, _b;
3595
4034
  var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
3596
4035
  if (toNode === "output") {
3597
4036
  newFn.outputs = __assign(__assign({}, oldFn.outputs), (_a = {}, _a[toField] = "<".concat(fromNode, ".").concat(fromField, ">"), _a));
3598
4037
  // no need to sort, as only output has changed
3599
4038
  return newFn;
3600
4039
  }
3601
- // const from = newFn.body[fromNode];
3602
- var to = __assign({}, newFn.body[toNode]);
4040
+ var to = oldFn.body[toNode];
3603
4041
  if (!to) {
3604
4042
  console.warn("Invalid nodes for connection");
3605
- return newFn;
3606
- }
3607
- if (!to.inputs) {
3608
- to.inputs = {};
4043
+ return oldFn;
3609
4044
  }
3610
- // add the reference
3611
- to.inputs[toField] = "<".concat(fromNode, ".").concat(fromField, ">");
3612
- newFn.body[toNode] = to;
4045
+ // Copy the inputs before assigning: copying only the node still aliases them.
4046
+ newFn.body[toNode] = __assign(__assign({}, to), { inputs: __assign(__assign({}, to.inputs), (_b = {}, _b[toField] = "<".concat(fromNode, ".").concat(fromField, ">"), _b)) });
3613
4047
  return topSort(newFn);
3614
4048
  };
3615
4049
  return Engine;
@@ -6736,16 +7170,17 @@ Log.displayName = "LogNode";
6736
7170
 
6737
7171
  function GenericNode(_a) {
6738
7172
  var _b;
6739
- var _c;
7173
+ var _c, _d;
6740
7174
  var id = _a.id, data = _a.data, selected = _a.selected, inputs = _a.inputs, outputs = _a.outputs, params = _a.params, children = _a.children;
6741
7175
  var inputEntries = Object.entries(inputs || data.inputDefs || {});
6742
7176
  var outputEntries = Object.entries(outputs || data.outputDefs || {});
6743
7177
  var paramEntries = Object.entries(params || data.paramDefs || {});
6744
7178
  var engine = useEngine();
6745
- var _d = __read(React.useState({}), 2), result = _d[0], setResult = _d[1];
6746
- var _e = __read(React.useState(null), 2), duration = _e[0], setDuration = _e[1];
6747
- var _f = __read(useInner(((_c = outputEntries[0]) === null || _c === void 0 ? void 0 : _c[0]) || null, [outputs, data.outputDefs]), 2), focus = _f[0], setFocus = _f[1];
6748
- var _g = __read(React.useState(false), 2), showPreview = _g[0], setShowPreview = _g[1];
7179
+ var _e = __read(React.useState({}), 2), result = _e[0], setResult = _e[1];
7180
+ var _f = __read(React.useState(), 2), cache = _f[0], setCache = _f[1];
7181
+ var _g = __read(React.useState(null), 2), duration = _g[0], setDuration = _g[1];
7182
+ var _h = __read(useInner(((_c = outputEntries[0]) === null || _c === void 0 ? void 0 : _c[0]) || null, [outputs, data.outputDefs]), 2), focus = _h[0], setFocus = _h[1];
7183
+ var _j = __read(React.useState(false), 2), showPreview = _j[0], setShowPreview = _j[1];
6749
7184
  var previewValue = focus ? result[focus] : Object.values(result)[0];
6750
7185
  React.useEffect(function () {
6751
7186
  return engine.subscribe("functionResult", function (event) {
@@ -6753,10 +7188,11 @@ function GenericNode(_a) {
6753
7188
  if (event.name === id) {
6754
7189
  setResult(event.result || {});
6755
7190
  setDuration((_a = event.duration) !== null && _a !== void 0 ? _a : null);
7191
+ setCache(event.cached ? event.cache : undefined);
6756
7192
  }
6757
7193
  });
6758
- }, []);
6759
- return (React.createElement(NodeContainer, { label: data.label, selected: selected, id: id },
7194
+ }, [engine, id]);
7195
+ return (React.createElement(NodeContainer, { label: data.label, selected: selected, id: id, className: (_d = data.nodeProps) === null || _d === void 0 ? void 0 : _d.className },
6760
7196
  React.createElement("div", { className: styles$1.Description }, data.description),
6761
7197
  children,
6762
7198
  React.createElement("div", { className: styles$1.Ports },
@@ -6777,9 +7213,10 @@ function GenericNode(_a) {
6777
7213
  _b)), onClick: function () { return setShowPreview(!showPreview); } }, "Preview")),
6778
7214
  showPreview && (React.createElement("div", { className: styles$1.Preview },
6779
7215
  React.createElement(TreeView, { value: previewValue }),
6780
- duration !== null && (React.createElement("div", { className: styles$1.Duration },
6781
- duration.toFixed(2),
6782
- " ms"))))));
7216
+ duration !== null && (React.createElement("div", { className: styles$1.Duration }, cache ? (React.createElement("span", { title: "Result computed ".concat(new Date(cache.createdAt).toLocaleString()) },
7217
+ cache.kind === "preview" ? "Cached preview" : "Cached",
7218
+ " · ",
7219
+ new Date(cache.createdAt).toLocaleTimeString())) : "".concat(duration.toFixed(2), " ms")))))));
6783
7220
  }
6784
7221
 
6785
7222
  var math = create(all, {});
@@ -7845,44 +8282,58 @@ function useDraggableNode(name, itemProps) {
7845
8282
  return function (ref) { return drag(ref); };
7846
8283
  }
7847
8284
 
7848
- /**
7849
- * using functions
7850
- *
7851
- * in React context
7852
- * - use useFunction. This will build the function, mount it if needed and provides a run function.
7853
- *
7854
- *
7855
- * in Vanilla context
7856
- * - use engine.build(fn) to build the function
7857
- * - use engine.mount(fn) to mount the function (if it has a mount function)
7858
- * - use await engine.run(fn, inputs) to run the function and get the result
8285
+ /** Build a graph, optionally subscribe to triggers, and retain the latest run inputs.
8286
+ * Preview caching requires { mode: "preview" }; refresh clears external preview
8287
+ * results for this graph/session and reruns with the latest inputs.
7859
8288
  */
7860
- function useFunction(engine, fn, mount) {
8289
+ function useFunction(engine, fn, mount, options) {
7861
8290
  var _this = this;
7862
- var _a = __read(React.useState(null), 2), result = _a[0], setResult = _a[1];
7863
- var builtFn = React.useMemo(function () { return engine.build(fn); }, [fn]);
8291
+ if (options === void 0) { options = {}; }
8292
+ var _a = options.mode, mode = _a === void 0 ? "normal" : _a, _b = options.cacheKey, cacheKey = _b === void 0 ? "" : _b;
8293
+ var _c = __read(React.useState(null), 2), result = _c[0], setResult = _c[1];
8294
+ var builtFn = React.useMemo(function () { return engine.build(fn); }, [engine, fn]);
8295
+ var latestInputs = React.useRef({});
8296
+ var sequence = React.useRef(0);
8297
+ var currentDefinition = React.useRef(builtFn);
8298
+ currentDefinition.current = builtFn;
8299
+ var run = React.useCallback(function () {
8300
+ var args_1 = [];
8301
+ for (var _i = 0; _i < arguments.length; _i++) {
8302
+ args_1[_i] = arguments[_i];
8303
+ }
8304
+ return __awaiter(_this, __spreadArray([], __read(args_1), false), void 0, function (inputs) {
8305
+ var request, result;
8306
+ if (inputs === void 0) { inputs = latestInputs.current; }
8307
+ return __generator(this, function (_a) {
8308
+ switch (_a.label) {
8309
+ case 0:
8310
+ latestInputs.current = inputs;
8311
+ request = ++sequence.current;
8312
+ return [4 /*yield*/, engine.run(builtFn, inputs, { mode: mode, cacheKey: cacheKey })];
8313
+ case 1:
8314
+ result = _a.sent();
8315
+ if (request === sequence.current && currentDefinition.current === builtFn) {
8316
+ setResult(result);
8317
+ }
8318
+ return [2 /*return*/, result];
8319
+ }
8320
+ });
8321
+ });
8322
+ }, [engine, builtFn, mode, cacheKey]);
8323
+ var latestRun = React.useRef(run);
8324
+ latestRun.current = run;
7864
8325
  React.useEffect(function () {
8326
+ var _a;
7865
8327
  if (mount) {
7866
- return engine.mount(builtFn);
8328
+ // Keep this hook's inputs/options even when another editor shares the engine.
8329
+ return (_a = builtFn.mount) === null || _a === void 0 ? void 0 : _a.call(builtFn, function () { void latestRun.current(); });
7867
8330
  }
7868
8331
  }, [builtFn, mount]);
7869
- var run = React.useCallback(function (inputs) { return __awaiter(_this, void 0, void 0, function () {
7870
- var result;
7871
- return __generator(this, function (_a) {
7872
- switch (_a.label) {
7873
- case 0: return [4 /*yield*/, engine.run(builtFn, inputs)];
7874
- case 1:
7875
- result = _a.sent();
7876
- setResult(result);
7877
- return [2 /*return*/, result];
7878
- }
7879
- });
7880
- }); }, [builtFn]);
7881
- return React.useMemo(function () { return ({
7882
- fn: builtFn,
7883
- run: run,
7884
- result: result,
7885
- }); }, [builtFn, run, result]);
8332
+ var refresh = React.useCallback(function () {
8333
+ engine.clearCache({ kind: "preview", graph: fn.name, cacheKey: cacheKey });
8334
+ return run();
8335
+ }, [engine, fn.name, cacheKey, run]);
8336
+ return React.useMemo(function () { return ({ fn: builtFn, run: run, refresh: refresh, result: result }); }, [builtFn, run, refresh, result]);
7886
8337
  }
7887
8338
 
7888
8339
  // cheap lodash replacements
@@ -8868,5 +9319,5 @@ function DDContext(_a) {
8868
9319
  return React.createElement(DndProvider, { backend: HTML5Backend }, children);
8869
9320
  }
8870
9321
 
8871
- export { DDContext, DISCARD, Engine, Flow, FlowContext, GenericNode, Input, InputBoolean, InputNumber, InputSelect, InputString, InputText, Lib, Output, Param, binaryOnTree, binaryOnTreeBranch, broadCast, deRefEdgeHandle, ensureBranch, expandTree, forEachBranch, forEachItem, getBranch, getBranches, getItem, getPaths, getPositions, getReferences, getValue$1 as getValue, getVariable, graftTree, hasReference, interpolate, isEmpty, isEmptyTree, isList, isMultiBranch, isReference, isSingleTon, isTree, mapTree, mapTreeBranch, mergeWithOrder, nAryOnTree, nAryOnTreeBranch, normalizePaths, normalizeVarDef, parseReference, primitives, pushItem, safeName, sameShape, simplifyTree$1 as simplifyTree, toArray, topSort, treeSize, treeStats, trimTree, uid$1 as uid, useControls, useDraggableNode, useEngine, useFlow, useFunction, useGraphedFunction, usePositions, usePrompts, useUpdatePositions, useVariable, variableStore };
9322
+ export { DDContext, DISCARD, Engine, Flow, FlowContext, GenericNode, Input, InputBoolean, InputNumber, InputSelect, InputString, InputText, Lib, Output, Param, binaryOnTree, binaryOnTreeBranch, broadCast, deRefEdgeHandle, ensureBranch, expandTree, forEachBranch, forEachItem, getBranch, getBranches, getItem, getPaths, getPositions, getReferencePaths, getReferences, getValue$1 as getValue, getVariable, graftTree, hasReference, interpolate, isEmpty, isEmptyTree, isList, isMultiBranch, isReference, isSingleTon, isTree, mapTree, mapTreeBranch, mergeWithOrder, nAryOnTree, nAryOnTreeBranch, normalizePaths, normalizeVarDef, parseReference, primitives, pushItem, safeName, sameShape, simplifyTree$1 as simplifyTree, toArray, topSort, treeSize, treeStats, trimTree, uid$1 as uid, useControls, useDraggableNode, useEngine, useFlow, useFunction, useGraphedFunction, usePositions, usePrompts, useUpdatePositions, useVariable, variableStore };
8872
9323
  //# sourceMappingURL=index.esm.mjs.map