@bian-womp/spark-graph 0.3.16 → 0.3.18
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/lib/cjs/index.cjs +306 -119
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/index.d.ts +1 -0
- package/lib/cjs/src/index.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/HandleResolver.d.ts +2 -10
- package/lib/cjs/src/runtime/components/HandleResolver.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/NodeExecutor.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/RunContextManager.d.ts +7 -1
- package/lib/cjs/src/runtime/components/RunContextManager.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/interfaces.d.ts +0 -2
- package/lib/cjs/src/runtime/components/interfaces.d.ts.map +1 -1
- package/lib/cjs/src/runtime/utils.d.ts +51 -0
- package/lib/cjs/src/runtime/utils.d.ts.map +1 -1
- package/lib/esm/index.js +306 -120
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/index.d.ts +1 -0
- package/lib/esm/src/index.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/HandleResolver.d.ts +2 -10
- package/lib/esm/src/runtime/components/HandleResolver.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/NodeExecutor.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/RunContextManager.d.ts +7 -1
- package/lib/esm/src/runtime/components/RunContextManager.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/interfaces.d.ts +0 -2
- package/lib/esm/src/runtime/components/interfaces.d.ts.map +1 -1
- package/lib/esm/src/runtime/utils.d.ts +51 -0
- package/lib/esm/src/runtime/utils.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -932,15 +932,166 @@ class EventEmitter {
|
|
|
932
932
|
}
|
|
933
933
|
}
|
|
934
934
|
|
|
935
|
+
const LOG_LEVEL_VALUES = {
|
|
936
|
+
debug: 0,
|
|
937
|
+
info: 1,
|
|
938
|
+
warn: 2,
|
|
939
|
+
error: 3,
|
|
940
|
+
silent: 4,
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Shared utility functions for runtime components
|
|
945
|
+
*/
|
|
946
|
+
/**
|
|
947
|
+
* Type guard to check if a value is a Promise
|
|
948
|
+
*/
|
|
949
|
+
function isPromise(value) {
|
|
950
|
+
return !!value && typeof value.then === "function";
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Unwrap a value that might be a Promise
|
|
954
|
+
*/
|
|
955
|
+
async function unwrapMaybePromise(value) {
|
|
956
|
+
return isPromise(value) ? await value : value;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Shallow/deep-ish equality check to avoid unnecessary runs on identical values
|
|
960
|
+
*/
|
|
961
|
+
function valuesEqual(a, b) {
|
|
962
|
+
if (a === b)
|
|
963
|
+
return true;
|
|
964
|
+
if (typeof a !== typeof b)
|
|
965
|
+
return false;
|
|
966
|
+
if (a && b && typeof a === "object") {
|
|
967
|
+
try {
|
|
968
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
969
|
+
}
|
|
970
|
+
catch {
|
|
971
|
+
return false;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* A reusable logger class that supports configurable log levels and prefixes.
|
|
978
|
+
* Can be instantiated with a default log level and optionally override per call.
|
|
979
|
+
*/
|
|
980
|
+
class LevelLogger {
|
|
981
|
+
constructor(defaultLevel = "info", prefix = "") {
|
|
982
|
+
this.defaultLevel = defaultLevel;
|
|
983
|
+
this.prefix = prefix;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Sets the prefix for log messages
|
|
987
|
+
*/
|
|
988
|
+
setPrefix(prefix) {
|
|
989
|
+
this.prefix = prefix;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Gets the current prefix
|
|
993
|
+
*/
|
|
994
|
+
getPrefix() {
|
|
995
|
+
return this.prefix;
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Sets the default log level for this logger instance
|
|
999
|
+
*/
|
|
1000
|
+
setLevel(level) {
|
|
1001
|
+
this.defaultLevel = level;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Gets the current default log level
|
|
1005
|
+
*/
|
|
1006
|
+
getLevel() {
|
|
1007
|
+
return this.defaultLevel;
|
|
1008
|
+
}
|
|
1009
|
+
getLevelValue() {
|
|
1010
|
+
return LevelLogger.levelValues[this.defaultLevel];
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Logs a debug message
|
|
1014
|
+
*/
|
|
1015
|
+
debug(message, context, overrideLevel) {
|
|
1016
|
+
this.log("debug", message, context, overrideLevel);
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Logs an info message
|
|
1020
|
+
*/
|
|
1021
|
+
info(message, context, overrideLevel) {
|
|
1022
|
+
this.log("info", message, context, overrideLevel);
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Logs a warning message
|
|
1026
|
+
*/
|
|
1027
|
+
warn(message, context, overrideLevel) {
|
|
1028
|
+
this.log("warn", message, context, overrideLevel);
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Logs an error message
|
|
1032
|
+
*/
|
|
1033
|
+
error(message, context, overrideLevel) {
|
|
1034
|
+
this.log("error", message, context, overrideLevel);
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Core logging method that respects the log level and applies prefix
|
|
1038
|
+
*/
|
|
1039
|
+
log(requestedLevel, message, context, overrideLevel) {
|
|
1040
|
+
const effectiveLevel = overrideLevel ?? this.defaultLevel;
|
|
1041
|
+
// Silent level suppresses all logs
|
|
1042
|
+
if (effectiveLevel === "silent") {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
const requestedValue = LevelLogger.levelValues[requestedLevel] ?? 1;
|
|
1046
|
+
const effectiveValue = LevelLogger.levelValues[effectiveLevel] ?? 1;
|
|
1047
|
+
// Only log if the requested level is >= effective level
|
|
1048
|
+
if (requestedValue >= effectiveValue) {
|
|
1049
|
+
const contextStr = context
|
|
1050
|
+
? ` ${Object.entries(context)
|
|
1051
|
+
.map(([k, v]) => `${k}=${JSON.stringify(v)}`)
|
|
1052
|
+
.join(" ")}`
|
|
1053
|
+
: "";
|
|
1054
|
+
const prefixedMessage = this.prefix
|
|
1055
|
+
? `${this.prefix} ${message}${contextStr}`
|
|
1056
|
+
: `${message}${contextStr}`;
|
|
1057
|
+
switch (requestedLevel) {
|
|
1058
|
+
case "debug":
|
|
1059
|
+
console.info(prefixedMessage);
|
|
1060
|
+
break;
|
|
1061
|
+
case "info":
|
|
1062
|
+
console.info(prefixedMessage);
|
|
1063
|
+
break;
|
|
1064
|
+
case "warn":
|
|
1065
|
+
console.warn(prefixedMessage);
|
|
1066
|
+
break;
|
|
1067
|
+
case "error":
|
|
1068
|
+
console.error(prefixedMessage);
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Maps log levels to numeric values for comparison
|
|
1076
|
+
*/
|
|
1077
|
+
LevelLogger.levelValues = LOG_LEVEL_VALUES;
|
|
1078
|
+
|
|
935
1079
|
/**
|
|
936
1080
|
* RunContextManager component - manages run-context lifecycle
|
|
937
1081
|
*/
|
|
938
1082
|
class RunContextManager {
|
|
939
|
-
constructor(graph) {
|
|
1083
|
+
constructor(graph, logLevel) {
|
|
940
1084
|
this.graph = graph;
|
|
941
1085
|
this.runContexts = new Map();
|
|
942
1086
|
this.runContextCounter = 0;
|
|
943
1087
|
this.graph = graph;
|
|
1088
|
+
this.logger = new LevelLogger(logLevel ?? "info", "[RunContextManager]");
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Set the log level for this manager
|
|
1092
|
+
*/
|
|
1093
|
+
setLogLevel(logLevel) {
|
|
1094
|
+
this.logger.setLevel(logLevel);
|
|
944
1095
|
}
|
|
945
1096
|
/**
|
|
946
1097
|
* Create a new run-context for runFromHere
|
|
@@ -959,6 +1110,12 @@ class RunContextManager {
|
|
|
959
1110
|
resolve,
|
|
960
1111
|
};
|
|
961
1112
|
this.runContexts.set(id, ctx);
|
|
1113
|
+
this.logger.info("create-run-context", {
|
|
1114
|
+
id,
|
|
1115
|
+
startNodeId,
|
|
1116
|
+
skipPropagateValues: ctx.skipPropagateValues,
|
|
1117
|
+
propagate: ctx.propagate,
|
|
1118
|
+
});
|
|
962
1119
|
return id;
|
|
963
1120
|
}
|
|
964
1121
|
/**
|
|
@@ -981,41 +1138,101 @@ class RunContextManager {
|
|
|
981
1138
|
}
|
|
982
1139
|
startNodeRun(id, nodeId) {
|
|
983
1140
|
const ctx = this.runContexts.get(id);
|
|
984
|
-
if (!ctx)
|
|
1141
|
+
if (!ctx) {
|
|
1142
|
+
this.logger.debug("start-node-run-context-not-found", {
|
|
1143
|
+
runContextId: id,
|
|
1144
|
+
nodeId,
|
|
1145
|
+
});
|
|
985
1146
|
return;
|
|
1147
|
+
}
|
|
986
1148
|
ctx.pendingNodes++;
|
|
1149
|
+
this.logger.debug("start-node-run", {
|
|
1150
|
+
runContextId: id,
|
|
1151
|
+
nodeId,
|
|
1152
|
+
pendingNodes: ctx.pendingNodes,
|
|
1153
|
+
});
|
|
987
1154
|
}
|
|
988
1155
|
finishNodeRun(id, nodeId) {
|
|
989
1156
|
const ctx = this.runContexts.get(id);
|
|
990
|
-
if (!ctx)
|
|
1157
|
+
if (!ctx) {
|
|
1158
|
+
this.logger.debug("finish-node-run-context-not-found", {
|
|
1159
|
+
runContextId: id,
|
|
1160
|
+
nodeId,
|
|
1161
|
+
});
|
|
991
1162
|
return;
|
|
1163
|
+
}
|
|
992
1164
|
ctx.pendingNodes--;
|
|
1165
|
+
this.logger.debug("finish-node-run", {
|
|
1166
|
+
runContextId: id,
|
|
1167
|
+
nodeId,
|
|
1168
|
+
pendingNodes: ctx.pendingNodes,
|
|
1169
|
+
});
|
|
993
1170
|
this.finishRunContextIfPossible(id);
|
|
994
1171
|
}
|
|
995
1172
|
startEdgeConversion(id, edgeId) {
|
|
996
1173
|
const ctx = this.runContexts.get(id);
|
|
997
|
-
if (!ctx)
|
|
1174
|
+
if (!ctx) {
|
|
1175
|
+
this.logger.debug("start-edge-conversion-context-not-found", {
|
|
1176
|
+
runContextId: id,
|
|
1177
|
+
edgeId,
|
|
1178
|
+
});
|
|
998
1179
|
return;
|
|
1180
|
+
}
|
|
999
1181
|
ctx.pendingEdges++;
|
|
1182
|
+
this.logger.debug("start-edge-conversion", {
|
|
1183
|
+
runContextId: id,
|
|
1184
|
+
edgeId,
|
|
1185
|
+
pendingEdges: ctx.pendingEdges,
|
|
1186
|
+
});
|
|
1000
1187
|
}
|
|
1001
1188
|
finishEdgeConversion(id, edgeId) {
|
|
1002
1189
|
const ctx = this.runContexts.get(id);
|
|
1003
|
-
if (!ctx)
|
|
1190
|
+
if (!ctx) {
|
|
1191
|
+
this.logger.debug("finish-edge-conversion-context-not-found", {
|
|
1192
|
+
runContextId: id,
|
|
1193
|
+
edgeId,
|
|
1194
|
+
});
|
|
1004
1195
|
return;
|
|
1196
|
+
}
|
|
1005
1197
|
ctx.pendingEdges--;
|
|
1198
|
+
this.logger.debug("finish-edge-conversion", {
|
|
1199
|
+
runContextId: id,
|
|
1200
|
+
edgeId,
|
|
1201
|
+
pendingEdges: ctx.pendingEdges,
|
|
1202
|
+
});
|
|
1006
1203
|
this.finishRunContextIfPossible(id);
|
|
1007
1204
|
}
|
|
1008
1205
|
startHandleResolution(id, nodeId) {
|
|
1009
1206
|
const ctx = this.runContexts.get(id);
|
|
1010
|
-
if (!ctx)
|
|
1207
|
+
if (!ctx) {
|
|
1208
|
+
this.logger.debug("start-handle-resolution-context-not-found", {
|
|
1209
|
+
runContextId: id,
|
|
1210
|
+
nodeId,
|
|
1211
|
+
});
|
|
1011
1212
|
return;
|
|
1213
|
+
}
|
|
1012
1214
|
ctx.pendingResolvers++;
|
|
1215
|
+
this.logger.debug("start-handle-resolution", {
|
|
1216
|
+
runContextId: id,
|
|
1217
|
+
nodeId,
|
|
1218
|
+
pendingResolvers: ctx.pendingResolvers,
|
|
1219
|
+
});
|
|
1013
1220
|
}
|
|
1014
1221
|
finishHandleResolution(id, nodeId) {
|
|
1015
1222
|
const ctx = this.runContexts.get(id);
|
|
1016
|
-
if (!ctx)
|
|
1223
|
+
if (!ctx) {
|
|
1224
|
+
this.logger.debug("finish-handle-resolution-context-not-found", {
|
|
1225
|
+
runContextId: id,
|
|
1226
|
+
nodeId,
|
|
1227
|
+
});
|
|
1017
1228
|
return;
|
|
1229
|
+
}
|
|
1018
1230
|
ctx.pendingResolvers--;
|
|
1231
|
+
this.logger.debug("finish-handle-resolution", {
|
|
1232
|
+
runContextId: id,
|
|
1233
|
+
nodeId,
|
|
1234
|
+
pendingResolvers: ctx.pendingResolvers,
|
|
1235
|
+
});
|
|
1019
1236
|
this.finishRunContextIfPossible(id);
|
|
1020
1237
|
}
|
|
1021
1238
|
/**
|
|
@@ -1023,13 +1240,22 @@ class RunContextManager {
|
|
|
1023
1240
|
*/
|
|
1024
1241
|
finishRunContextIfPossible(id) {
|
|
1025
1242
|
const ctx = this.runContexts.get(id);
|
|
1026
|
-
if (!ctx)
|
|
1243
|
+
if (!ctx) {
|
|
1244
|
+
this.logger.debug("finish-run-context-not-found", {
|
|
1245
|
+
runContextId: id,
|
|
1246
|
+
});
|
|
1027
1247
|
return;
|
|
1248
|
+
}
|
|
1028
1249
|
if (ctx.pendingNodes > 0 ||
|
|
1029
1250
|
ctx.pendingEdges > 0 ||
|
|
1030
1251
|
ctx.pendingResolvers > 0) {
|
|
1031
1252
|
return; // Still has pending work
|
|
1032
1253
|
}
|
|
1254
|
+
this.logger.info("finish-run-context", {
|
|
1255
|
+
runContextId: id,
|
|
1256
|
+
startNodes: Array.from(ctx.startNodes),
|
|
1257
|
+
cancelledNodes: Array.from(ctx.cancelledNodes),
|
|
1258
|
+
});
|
|
1033
1259
|
// Clean up activeRunContexts from all nodes
|
|
1034
1260
|
this.graph.forEachNode((node) => {
|
|
1035
1261
|
this.graph.removeNodeRunContextId(node.nodeId, id);
|
|
@@ -1067,6 +1293,12 @@ class RunContextManager {
|
|
|
1067
1293
|
});
|
|
1068
1294
|
}
|
|
1069
1295
|
}
|
|
1296
|
+
this.logger.debug("cancel-node-in-run-contexts", {
|
|
1297
|
+
nodeId,
|
|
1298
|
+
includeDownstream,
|
|
1299
|
+
cancelledNodes: Array.from(toCancel),
|
|
1300
|
+
affectedRunContexts: Array.from(this.runContexts.keys()),
|
|
1301
|
+
});
|
|
1070
1302
|
// Mark nodes as cancelled in all run-contexts
|
|
1071
1303
|
for (const ctx of this.runContexts.values()) {
|
|
1072
1304
|
for (const id of toCancel) {
|
|
@@ -1082,6 +1314,11 @@ class RunContextManager {
|
|
|
1082
1314
|
* Resolve all pending run-context promises (for cleanup)
|
|
1083
1315
|
*/
|
|
1084
1316
|
resolveAll() {
|
|
1317
|
+
const count = this.runContexts.size;
|
|
1318
|
+
this.logger.info("resolve-all-run-contexts", {
|
|
1319
|
+
count,
|
|
1320
|
+
runContextIds: Array.from(this.runContexts.keys()),
|
|
1321
|
+
});
|
|
1085
1322
|
for (const ctx of this.runContexts.values()) {
|
|
1086
1323
|
if (ctx.resolve)
|
|
1087
1324
|
ctx.resolve();
|
|
@@ -1091,52 +1328,12 @@ class RunContextManager {
|
|
|
1091
1328
|
* Clear all run-contexts
|
|
1092
1329
|
*/
|
|
1093
1330
|
clear() {
|
|
1331
|
+
const count = this.runContexts.size;
|
|
1332
|
+
this.logger.info("clear-all-run-contexts", { count });
|
|
1094
1333
|
this.runContexts.clear();
|
|
1095
1334
|
}
|
|
1096
1335
|
}
|
|
1097
1336
|
|
|
1098
|
-
const LOG_LEVEL_VALUES = {
|
|
1099
|
-
debug: 0,
|
|
1100
|
-
info: 1,
|
|
1101
|
-
warn: 2,
|
|
1102
|
-
error: 3,
|
|
1103
|
-
silent: 4,
|
|
1104
|
-
};
|
|
1105
|
-
|
|
1106
|
-
/**
|
|
1107
|
-
* Shared utility functions for runtime components
|
|
1108
|
-
*/
|
|
1109
|
-
/**
|
|
1110
|
-
* Type guard to check if a value is a Promise
|
|
1111
|
-
*/
|
|
1112
|
-
function isPromise(value) {
|
|
1113
|
-
return !!value && typeof value.then === "function";
|
|
1114
|
-
}
|
|
1115
|
-
/**
|
|
1116
|
-
* Unwrap a value that might be a Promise
|
|
1117
|
-
*/
|
|
1118
|
-
async function unwrapMaybePromise(value) {
|
|
1119
|
-
return isPromise(value) ? await value : value;
|
|
1120
|
-
}
|
|
1121
|
-
/**
|
|
1122
|
-
* Shallow/deep-ish equality check to avoid unnecessary runs on identical values
|
|
1123
|
-
*/
|
|
1124
|
-
function valuesEqual(a, b) {
|
|
1125
|
-
if (a === b)
|
|
1126
|
-
return true;
|
|
1127
|
-
if (typeof a !== typeof b)
|
|
1128
|
-
return false;
|
|
1129
|
-
if (a && b && typeof a === "object") {
|
|
1130
|
-
try {
|
|
1131
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
1132
|
-
}
|
|
1133
|
-
catch {
|
|
1134
|
-
return false;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
return false;
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
1337
|
function tryHandleResolving(def, registry, environment) {
|
|
1141
1338
|
const out = new Map();
|
|
1142
1339
|
const pending = new Set();
|
|
@@ -1335,7 +1532,7 @@ class HandleResolver {
|
|
|
1335
1532
|
this.recomputeTokenByNode = new Map();
|
|
1336
1533
|
this.environment = {};
|
|
1337
1534
|
this.pendingResolutions = new Map();
|
|
1338
|
-
this.
|
|
1535
|
+
this.isRecomputing = new Map();
|
|
1339
1536
|
this.environment = environment ?? {};
|
|
1340
1537
|
}
|
|
1341
1538
|
setRegistry(registry) {
|
|
@@ -1344,33 +1541,12 @@ class HandleResolver {
|
|
|
1344
1541
|
setEnvironment(environment) {
|
|
1345
1542
|
this.environment = environment;
|
|
1346
1543
|
}
|
|
1347
|
-
/**
|
|
1348
|
-
* Check if handle resolution is pending for a node
|
|
1349
|
-
*/
|
|
1350
|
-
isResolvingHandles(nodeId) {
|
|
1351
|
-
return this.pendingResolutions.has(nodeId);
|
|
1352
|
-
}
|
|
1353
1544
|
/**
|
|
1354
1545
|
* Get the promise for pending handle resolution, or null if none
|
|
1355
1546
|
*/
|
|
1356
1547
|
getPendingResolution(nodeId) {
|
|
1357
1548
|
return this.pendingResolutions.get(nodeId) || null;
|
|
1358
1549
|
}
|
|
1359
|
-
/**
|
|
1360
|
-
* Track additional run contexts for a pending resolution
|
|
1361
|
-
*/
|
|
1362
|
-
trackRunContextsForPendingResolution(nodeId, runContextIds) {
|
|
1363
|
-
if (!this.pendingResolutions.has(nodeId))
|
|
1364
|
-
return;
|
|
1365
|
-
const tracked = this.pendingResolutionRunContexts.get(nodeId) ?? new Set();
|
|
1366
|
-
for (const runContextId of runContextIds) {
|
|
1367
|
-
if (!tracked.has(runContextId)) {
|
|
1368
|
-
this.runContextManager.startHandleResolution(runContextId, nodeId);
|
|
1369
|
-
tracked.add(runContextId);
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
this.pendingResolutionRunContexts.set(nodeId, tracked);
|
|
1373
|
-
}
|
|
1374
1550
|
/**
|
|
1375
1551
|
* Schedule async recomputation of handles for a node
|
|
1376
1552
|
*/
|
|
@@ -1381,27 +1557,43 @@ class HandleResolver {
|
|
|
1381
1557
|
const node = this.graph.getNode(nodeId);
|
|
1382
1558
|
if (!node)
|
|
1383
1559
|
return;
|
|
1560
|
+
// If already recomputing, increment token to mark that a new recompute is needed
|
|
1561
|
+
// but don't schedule another concurrent execution
|
|
1562
|
+
if (this.isRecomputing.get(nodeId)) {
|
|
1563
|
+
const currentToken = this.recomputeTokenByNode.get(nodeId) ?? 0;
|
|
1564
|
+
this.recomputeTokenByNode.set(nodeId, currentToken + 1);
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1384
1567
|
// Track resolver start for all active run-contexts
|
|
1385
1568
|
const activeRunContextIds = this.graph.getNodeRunContextIds(nodeId);
|
|
1386
|
-
const trackedRunContextIds = new Set(activeRunContextIds);
|
|
1387
1569
|
if (activeRunContextIds.size > 0) {
|
|
1388
1570
|
for (const runContextId of activeRunContextIds) {
|
|
1389
1571
|
this.runContextManager.startHandleResolution(runContextId, nodeId);
|
|
1390
1572
|
}
|
|
1391
1573
|
}
|
|
1574
|
+
// Mark as recomputing
|
|
1575
|
+
this.isRecomputing.set(nodeId, true);
|
|
1576
|
+
// Capture initial token before starting (will be incremented in recomputeHandlesForNode)
|
|
1577
|
+
const initialToken = this.recomputeTokenByNode.get(nodeId) ?? 0;
|
|
1392
1578
|
// Create and track the resolution promise
|
|
1393
1579
|
const resolutionPromise = new Promise((resolve) => {
|
|
1394
1580
|
setTimeout(async () => {
|
|
1395
|
-
|
|
1396
|
-
const allTracked = this.pendingResolutionRunContexts.get(nodeId) ?? trackedRunContextIds;
|
|
1397
|
-
await this.recomputeHandlesForNode(nodeId, allTracked.size > 0 ? allTracked : undefined);
|
|
1581
|
+
await this.recomputeHandlesForNode(nodeId, activeRunContextIds);
|
|
1398
1582
|
this.pendingResolutions.delete(nodeId);
|
|
1399
|
-
this.
|
|
1583
|
+
this.isRecomputing.delete(nodeId);
|
|
1584
|
+
// Check if a new recompute was requested while we were running
|
|
1585
|
+
// (token was incremented by another scheduleRecomputeHandles call)
|
|
1586
|
+
const finalToken = this.recomputeTokenByNode.get(nodeId) ?? 0;
|
|
1587
|
+
// After recomputeHandlesForNode, token should be initialToken + 1
|
|
1588
|
+
// If finalToken > initialToken + 1, a new recompute was requested
|
|
1589
|
+
if (finalToken > initialToken + 1) {
|
|
1590
|
+
// A new recompute was requested, schedule it now
|
|
1591
|
+
this.scheduleRecomputeHandles(nodeId);
|
|
1592
|
+
}
|
|
1400
1593
|
resolve();
|
|
1401
1594
|
}, 0);
|
|
1402
1595
|
});
|
|
1403
1596
|
this.pendingResolutions.set(nodeId, resolutionPromise);
|
|
1404
|
-
this.pendingResolutionRunContexts.set(nodeId, trackedRunContextIds);
|
|
1405
1597
|
}
|
|
1406
1598
|
// Update resolved handles for a single node and refresh edge converters/types that touch it
|
|
1407
1599
|
updateNodeHandles(nodeId, handles) {
|
|
@@ -2019,33 +2211,23 @@ class NodeExecutor {
|
|
|
2019
2211
|
progress: Math.max(0, Math.min(1, Number(p) || 0)),
|
|
2020
2212
|
});
|
|
2021
2213
|
});
|
|
2022
|
-
// Create log function that respects node's logLevel
|
|
2214
|
+
// Create log function that respects node's logLevel using LevelLogger
|
|
2215
|
+
const nodeLogLevel = node.logLevel ?? "info";
|
|
2216
|
+
const logger = new LevelLogger(nodeLogLevel, `[node:${runId || nodeId}:${node.typeId}]`);
|
|
2023
2217
|
const log = (level, message, context) => {
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
console.info(fullMessage);
|
|
2038
|
-
break;
|
|
2039
|
-
case "info":
|
|
2040
|
-
console.info(fullMessage);
|
|
2041
|
-
break;
|
|
2042
|
-
case "warn":
|
|
2043
|
-
console.warn(fullMessage);
|
|
2044
|
-
break;
|
|
2045
|
-
case "error":
|
|
2046
|
-
console.error(fullMessage);
|
|
2047
|
-
break;
|
|
2048
|
-
}
|
|
2218
|
+
switch (level) {
|
|
2219
|
+
case "debug":
|
|
2220
|
+
logger.debug(message, context);
|
|
2221
|
+
break;
|
|
2222
|
+
case "info":
|
|
2223
|
+
logger.info(message, context);
|
|
2224
|
+
break;
|
|
2225
|
+
case "warn":
|
|
2226
|
+
logger.warn(message, context);
|
|
2227
|
+
break;
|
|
2228
|
+
case "error":
|
|
2229
|
+
logger.error(message, context);
|
|
2230
|
+
break;
|
|
2049
2231
|
}
|
|
2050
2232
|
};
|
|
2051
2233
|
return {
|
|
@@ -2117,23 +2299,27 @@ class NodeExecutor {
|
|
|
2117
2299
|
}
|
|
2118
2300
|
// Check if handles are being resolved - wait for resolution before executing
|
|
2119
2301
|
// Do this AFTER setting up run contexts so handle resolution can track them
|
|
2120
|
-
|
|
2121
|
-
|
|
2302
|
+
const pendingResolution = this.handleResolver.getPendingResolution(nodeId);
|
|
2303
|
+
if (pendingResolution) {
|
|
2122
2304
|
if (runContextIds && runContextIds.size > 0) {
|
|
2123
|
-
|
|
2305
|
+
for (const id of runContextIds) {
|
|
2306
|
+
this.runContextManager.startHandleResolution(id, nodeId);
|
|
2307
|
+
}
|
|
2124
2308
|
}
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
//
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2309
|
+
// Wait for resolution to complete, then re-execute
|
|
2310
|
+
pendingResolution.then(() => {
|
|
2311
|
+
// Re-check node still exists and conditions
|
|
2312
|
+
const nodeAfter = this.graph.getNode(nodeId);
|
|
2313
|
+
if (nodeAfter) {
|
|
2314
|
+
this.execute(nodeId, runContextIds);
|
|
2315
|
+
}
|
|
2316
|
+
if (runContextIds && runContextIds.size > 0) {
|
|
2317
|
+
for (const id of runContextIds) {
|
|
2318
|
+
this.runContextManager.finishHandleResolution(id, nodeId);
|
|
2133
2319
|
}
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
return;
|
|
2137
2323
|
}
|
|
2138
2324
|
// Handle debouncing
|
|
2139
2325
|
const now = Date.now();
|
|
@@ -2574,7 +2760,7 @@ class GraphRuntime {
|
|
|
2574
2760
|
// Initialize components
|
|
2575
2761
|
this.graph = new Graph();
|
|
2576
2762
|
this.eventEmitter = new EventEmitter();
|
|
2577
|
-
this.runContextManager = new RunContextManager(this.graph);
|
|
2763
|
+
this.runContextManager = new RunContextManager(this.graph, "debug");
|
|
2578
2764
|
this.handleResolver = new HandleResolver(this.graph, this.eventEmitter, this.runContextManager, this);
|
|
2579
2765
|
this.edgePropagator = new EdgePropagator(this.graph, this.eventEmitter, this.runContextManager, this.handleResolver, this);
|
|
2580
2766
|
// Create NodeExecutor with EdgePropagator and HandleResolver
|
|
@@ -5709,6 +5895,7 @@ exports.CompositeCategory = CompositeCategory;
|
|
|
5709
5895
|
exports.ComputeCategory = ComputeCategory;
|
|
5710
5896
|
exports.GraphBuilder = GraphBuilder;
|
|
5711
5897
|
exports.GraphRuntime = GraphRuntime;
|
|
5898
|
+
exports.LevelLogger = LevelLogger;
|
|
5712
5899
|
exports.LocalEngine = LocalEngine;
|
|
5713
5900
|
exports.Registry = Registry;
|
|
5714
5901
|
exports.buildValueConverter = buildValueConverter;
|