@bian-womp/spark-graph 0.3.17 → 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 CHANGED
@@ -1532,7 +1532,7 @@ class HandleResolver {
1532
1532
  this.recomputeTokenByNode = new Map();
1533
1533
  this.environment = {};
1534
1534
  this.pendingResolutions = new Map();
1535
- this.pendingResolutionRunContexts = new Map();
1535
+ this.isRecomputing = new Map();
1536
1536
  this.environment = environment ?? {};
1537
1537
  }
1538
1538
  setRegistry(registry) {
@@ -1541,33 +1541,12 @@ class HandleResolver {
1541
1541
  setEnvironment(environment) {
1542
1542
  this.environment = environment;
1543
1543
  }
1544
- /**
1545
- * Check if handle resolution is pending for a node
1546
- */
1547
- isResolvingHandles(nodeId) {
1548
- return this.pendingResolutions.has(nodeId);
1549
- }
1550
1544
  /**
1551
1545
  * Get the promise for pending handle resolution, or null if none
1552
1546
  */
1553
1547
  getPendingResolution(nodeId) {
1554
1548
  return this.pendingResolutions.get(nodeId) || null;
1555
1549
  }
1556
- /**
1557
- * Track additional run contexts for a pending resolution
1558
- */
1559
- trackRunContextsForPendingResolution(nodeId, runContextIds) {
1560
- if (!this.pendingResolutions.has(nodeId))
1561
- return;
1562
- const tracked = this.pendingResolutionRunContexts.get(nodeId) ?? new Set();
1563
- for (const runContextId of runContextIds) {
1564
- if (!tracked.has(runContextId)) {
1565
- this.runContextManager.startHandleResolution(runContextId, nodeId);
1566
- tracked.add(runContextId);
1567
- }
1568
- }
1569
- this.pendingResolutionRunContexts.set(nodeId, tracked);
1570
- }
1571
1550
  /**
1572
1551
  * Schedule async recomputation of handles for a node
1573
1552
  */
@@ -1578,27 +1557,43 @@ class HandleResolver {
1578
1557
  const node = this.graph.getNode(nodeId);
1579
1558
  if (!node)
1580
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
+ }
1581
1567
  // Track resolver start for all active run-contexts
1582
1568
  const activeRunContextIds = this.graph.getNodeRunContextIds(nodeId);
1583
- const trackedRunContextIds = new Set(activeRunContextIds);
1584
1569
  if (activeRunContextIds.size > 0) {
1585
1570
  for (const runContextId of activeRunContextIds) {
1586
1571
  this.runContextManager.startHandleResolution(runContextId, nodeId);
1587
1572
  }
1588
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;
1589
1578
  // Create and track the resolution promise
1590
1579
  const resolutionPromise = new Promise((resolve) => {
1591
1580
  setTimeout(async () => {
1592
- // Get all tracked run contexts (including any added during pending state)
1593
- const allTracked = this.pendingResolutionRunContexts.get(nodeId) ?? trackedRunContextIds;
1594
- await this.recomputeHandlesForNode(nodeId, allTracked.size > 0 ? allTracked : undefined);
1581
+ await this.recomputeHandlesForNode(nodeId, activeRunContextIds);
1595
1582
  this.pendingResolutions.delete(nodeId);
1596
- this.pendingResolutionRunContexts.delete(nodeId);
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
+ }
1597
1593
  resolve();
1598
1594
  }, 0);
1599
1595
  });
1600
1596
  this.pendingResolutions.set(nodeId, resolutionPromise);
1601
- this.pendingResolutionRunContexts.set(nodeId, trackedRunContextIds);
1602
1597
  }
1603
1598
  // Update resolved handles for a single node and refresh edge converters/types that touch it
1604
1599
  updateNodeHandles(nodeId, handles) {
@@ -2304,23 +2299,27 @@ class NodeExecutor {
2304
2299
  }
2305
2300
  // Check if handles are being resolved - wait for resolution before executing
2306
2301
  // Do this AFTER setting up run contexts so handle resolution can track them
2307
- if (this.handleResolver && this.handleResolver.isResolvingHandles(nodeId)) {
2308
- // Track run contexts for the pending resolution
2302
+ const pendingResolution = this.handleResolver.getPendingResolution(nodeId);
2303
+ if (pendingResolution) {
2309
2304
  if (runContextIds && runContextIds.size > 0) {
2310
- this.handleResolver.trackRunContextsForPendingResolution(nodeId, runContextIds);
2305
+ for (const id of runContextIds) {
2306
+ this.runContextManager.startHandleResolution(id, nodeId);
2307
+ }
2311
2308
  }
2312
- const pendingResolution = this.handleResolver.getPendingResolution(nodeId);
2313
- if (pendingResolution) {
2314
- // Wait for resolution to complete, then re-execute
2315
- pendingResolution.then(() => {
2316
- // Re-check node still exists and conditions
2317
- const nodeAfter = this.graph.getNode(nodeId);
2318
- if (nodeAfter) {
2319
- this.execute(nodeId, runContextIds);
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);
2320
2319
  }
2321
- });
2322
- return;
2323
- }
2320
+ }
2321
+ });
2322
+ return;
2324
2323
  }
2325
2324
  // Handle debouncing
2326
2325
  const now = Date.now();