@bian-womp/spark-graph 0.2.30 → 0.2.31
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
|
@@ -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
|
+
};
|
|
619
|
+
}
|
|
620
|
+
// Sync path
|
|
621
|
+
const firstCoercion = coercions.find((r) => r?.kind === "sync");
|
|
622
|
+
if (!firstCoercion) {
|
|
623
|
+
return {};
|
|
625
624
|
}
|
|
626
|
-
return {
|
|
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,6 +1071,19 @@ 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);
|