@bian-womp/spark-graph 0.2.30 → 0.2.32
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 +83 -54
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/examples/async.d.ts +1 -1
- package/lib/cjs/src/examples/async.d.ts.map +1 -1
- package/lib/cjs/src/plugins/composite.d.ts +1 -1
- package/lib/cjs/src/plugins/composite.d.ts.map +1 -1
- package/lib/cjs/src/runtime/AbstractEngine.d.ts +1 -1
- package/lib/cjs/src/runtime/AbstractEngine.d.ts.map +1 -1
- package/lib/cjs/src/runtime/Engine.d.ts +1 -1
- package/lib/cjs/src/runtime/Engine.d.ts.map +1 -1
- package/lib/cjs/src/runtime/GraphRuntime.d.ts +1 -1
- package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/cjs/src/runtime/LocalRunner.d.ts +1 -1
- package/lib/cjs/src/runtime/LocalRunner.d.ts.map +1 -1
- package/lib/cjs/src/runtime/RunnerControl.d.ts +1 -1
- package/lib/cjs/src/runtime/RunnerControl.d.ts.map +1 -1
- package/lib/esm/index.js +83 -54
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/examples/async.d.ts +1 -1
- package/lib/esm/src/examples/async.d.ts.map +1 -1
- package/lib/esm/src/plugins/composite.d.ts +1 -1
- package/lib/esm/src/plugins/composite.d.ts.map +1 -1
- package/lib/esm/src/runtime/AbstractEngine.d.ts +1 -1
- package/lib/esm/src/runtime/AbstractEngine.d.ts.map +1 -1
- package/lib/esm/src/runtime/Engine.d.ts +1 -1
- package/lib/esm/src/runtime/Engine.d.ts.map +1 -1
- package/lib/esm/src/runtime/GraphRuntime.d.ts +1 -1
- package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/esm/src/runtime/LocalRunner.d.ts +1 -1
- package/lib/esm/src/runtime/LocalRunner.d.ts.map +1 -1
- package/lib/esm/src/runtime/RunnerControl.d.ts +1 -1
- package/lib/esm/src/runtime/RunnerControl.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -573,57 +573,67 @@ class GraphRuntime {
|
|
|
573
573
|
return node?.outputs[output];
|
|
574
574
|
}
|
|
575
575
|
static buildEdgeConverters(srcDeclared, dstDeclared, registry) {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
return payload;
|
|
596
|
-
if (res.kind === "async")
|
|
597
|
-
return await res.convertAsync(payload, signal);
|
|
598
|
-
return res.convert(payload);
|
|
599
|
-
};
|
|
576
|
+
if (!dstDeclared || !srcDeclared) {
|
|
577
|
+
return {};
|
|
578
|
+
}
|
|
579
|
+
const isUnion = Array.isArray(srcDeclared);
|
|
580
|
+
const srcTypes = isUnion ? srcDeclared : [srcDeclared];
|
|
581
|
+
// Helper to get the coercion for a specific type
|
|
582
|
+
const getCoercion = (typeId) => {
|
|
583
|
+
return registry.resolveCoercion(typeId, dstDeclared);
|
|
584
|
+
};
|
|
585
|
+
// Resolve coercions for all source types
|
|
586
|
+
const coercions = srcTypes.map(getCoercion);
|
|
587
|
+
const hasAsync = coercions.some((r) => r?.kind === "async");
|
|
588
|
+
// Helper to extract and validate typed output for unions
|
|
589
|
+
const extractPayload = (v) => {
|
|
590
|
+
const typeId = getTypedOutputTypeId(v);
|
|
591
|
+
const payload = getTypedOutputValue(v);
|
|
592
|
+
if (isUnion) {
|
|
593
|
+
if (!typeId) {
|
|
594
|
+
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
600
595
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const typeId = getTypedOutputTypeId(v);
|
|
604
|
-
if (!typeId)
|
|
605
|
-
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
606
|
-
if (!srcTypes.includes(typeId))
|
|
607
|
-
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
608
|
-
const payload = getTypedOutputValue(v);
|
|
609
|
-
const res = registry.resolveCoercion(typeId, dstDeclared);
|
|
610
|
-
if (!res)
|
|
611
|
-
return payload;
|
|
612
|
-
if (res.kind === "async")
|
|
613
|
-
throw new Error("Async coercion required but convert used");
|
|
614
|
-
return res.convert(payload);
|
|
615
|
-
};
|
|
596
|
+
if (!srcTypes.includes(typeId)) {
|
|
597
|
+
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
616
598
|
}
|
|
617
599
|
}
|
|
618
|
-
else {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
convertAsync = res.convertAsync;
|
|
622
|
-
else if (res?.kind === "sync")
|
|
623
|
-
convert = res.convert;
|
|
600
|
+
else if (typeId) {
|
|
601
|
+
// Warn if typed output is used for non-union source
|
|
602
|
+
console.warn(`Typed output ${typeId} is fed even though source is not union: ${srcDeclared} -> ${dstDeclared}`);
|
|
624
603
|
}
|
|
604
|
+
return { typeId: typeId || srcTypes[0], payload };
|
|
605
|
+
};
|
|
606
|
+
if (hasAsync) {
|
|
607
|
+
return {
|
|
608
|
+
convertAsync: async (v, signal) => {
|
|
609
|
+
const { typeId, payload } = extractPayload(v);
|
|
610
|
+
const res = getCoercion(typeId);
|
|
611
|
+
if (!res)
|
|
612
|
+
return payload;
|
|
613
|
+
if (res.kind === "async") {
|
|
614
|
+
return await res.convertAsync(payload, signal);
|
|
615
|
+
}
|
|
616
|
+
return res.convert(payload);
|
|
617
|
+
},
|
|
618
|
+
};
|
|
625
619
|
}
|
|
626
|
-
|
|
620
|
+
// Sync path
|
|
621
|
+
const firstCoercion = coercions.find((r) => r?.kind === "sync");
|
|
622
|
+
if (!firstCoercion) {
|
|
623
|
+
return {};
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
convert: (v) => {
|
|
627
|
+
const { typeId, payload } = extractPayload(v);
|
|
628
|
+
const res = getCoercion(typeId);
|
|
629
|
+
if (!res)
|
|
630
|
+
return payload;
|
|
631
|
+
if (res.kind === "async") {
|
|
632
|
+
throw new Error("Async coercion required but convert used");
|
|
633
|
+
}
|
|
634
|
+
return res.convert(payload);
|
|
635
|
+
},
|
|
636
|
+
};
|
|
627
637
|
}
|
|
628
638
|
scheduleInputsChanged(nodeId) {
|
|
629
639
|
const node = this.nodes.get(nodeId);
|
|
@@ -827,6 +837,9 @@ class GraphRuntime {
|
|
|
827
837
|
const dstNode = this.nodes.get(e.target.nodeId);
|
|
828
838
|
if (!dstNode)
|
|
829
839
|
return;
|
|
840
|
+
// Skip writing to unresolved handles - wait for handle resolution
|
|
841
|
+
if (e.dstDeclared === undefined)
|
|
842
|
+
return;
|
|
830
843
|
const dstIsArray = typeof e.dstDeclared === "string" && e.dstDeclared.endsWith("[]");
|
|
831
844
|
let next = v;
|
|
832
845
|
// If target input is an array type, merge per-edge contributions deterministically
|
|
@@ -1035,6 +1048,7 @@ class GraphRuntime {
|
|
|
1035
1048
|
for (const e of this.edges) {
|
|
1036
1049
|
let srcDeclared = e.effectiveTypeId; // Use effectiveTypeId as fallback
|
|
1037
1050
|
let dstDeclared = e.dstDeclared;
|
|
1051
|
+
const oldDstDeclared = dstDeclared; // Track old value to detect resolution
|
|
1038
1052
|
if (e.source.nodeId === nodeId) {
|
|
1039
1053
|
const resolved = this.resolvedByNode.get(nodeId);
|
|
1040
1054
|
srcDeclared = resolved
|
|
@@ -1057,11 +1071,24 @@ class GraphRuntime {
|
|
|
1057
1071
|
const conv = GraphRuntime.buildEdgeConverters(srcDeclared, dstDeclared, registry);
|
|
1058
1072
|
e.convert = conv.convert;
|
|
1059
1073
|
e.convertAsync = conv.convertAsync;
|
|
1074
|
+
// If target handle was just resolved (was undefined, now has a type), re-propagate values
|
|
1075
|
+
if (e.target.nodeId === nodeId &&
|
|
1076
|
+
oldDstDeclared === undefined &&
|
|
1077
|
+
dstDeclared !== undefined) {
|
|
1078
|
+
const srcNode = this.nodes.get(e.source.nodeId);
|
|
1079
|
+
if (srcNode) {
|
|
1080
|
+
const srcValue = srcNode.outputs[e.source.handle];
|
|
1081
|
+
if (srcValue !== undefined) {
|
|
1082
|
+
// Re-propagate through the now-resolved edge converter
|
|
1083
|
+
this.propagate(e.source.nodeId, e.source.handle, srcValue);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1060
1087
|
}
|
|
1061
1088
|
// Invalidate downstream for this node so UI refreshes
|
|
1062
1089
|
this.invalidateDownstream(nodeId);
|
|
1063
1090
|
}
|
|
1064
|
-
launch() {
|
|
1091
|
+
launch(invalidate = false) {
|
|
1065
1092
|
// call onActivated for nodes that implement it
|
|
1066
1093
|
for (const node of this.nodes.values()) {
|
|
1067
1094
|
const ctrl = new AbortController();
|
|
@@ -1085,10 +1112,12 @@ class GraphRuntime {
|
|
|
1085
1112
|
});
|
|
1086
1113
|
node.runtime.onActivated?.(ctx);
|
|
1087
1114
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
this.
|
|
1115
|
+
if (invalidate) {
|
|
1116
|
+
// After activation, schedule nodes that have all inbound inputs present
|
|
1117
|
+
for (const nodeId of this.nodes.keys()) {
|
|
1118
|
+
if (this.allInboundHaveValue(nodeId))
|
|
1119
|
+
this.scheduleInputsChanged(nodeId);
|
|
1120
|
+
}
|
|
1092
1121
|
}
|
|
1093
1122
|
}
|
|
1094
1123
|
triggerExternal(nodeId, event) {
|
|
@@ -1874,11 +1903,11 @@ class AbstractEngine {
|
|
|
1874
1903
|
constructor(graphRuntime) {
|
|
1875
1904
|
this.graphRuntime = graphRuntime;
|
|
1876
1905
|
}
|
|
1877
|
-
launch() {
|
|
1878
|
-
this.graphRuntime.launch();
|
|
1906
|
+
launch(invalidate = false) {
|
|
1907
|
+
this.graphRuntime.launch(invalidate);
|
|
1879
1908
|
}
|
|
1880
1909
|
setInput(nodeId, handle, value) {
|
|
1881
|
-
this.setInputs(nodeId, { [handle]: value });
|
|
1910
|
+
this.graphRuntime.setInputs(nodeId, { [handle]: value });
|
|
1882
1911
|
}
|
|
1883
1912
|
setInputs(nodeId, inputs) {
|
|
1884
1913
|
this.graphRuntime.setInputs(nodeId, inputs);
|