@bian-womp/spark-graph 0.2.29 → 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 +96 -54
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/runtime/GraphRuntime.d.ts +2 -28
- package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/esm/index.js +96 -54
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/runtime/GraphRuntime.d.ts +2 -28
- package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RuntimeValue, RuntimeInvalidate, RuntimeError, RuntimeStats, ResolvedHandles, GraphDefinition
|
|
1
|
+
import type { RuntimeValue, RuntimeInvalidate, RuntimeError, RuntimeStats, ResolvedHandles, GraphDefinition } from "@bian-womp/spark-protocol";
|
|
2
2
|
import type { RuntimeNodeStats } from "../core/types";
|
|
3
3
|
import { Registry } from "../builder/Registry";
|
|
4
4
|
export type RuntimeEventListener<K extends RuntimeEventName> = (e: RuntimeEventMap[K]) => void;
|
|
@@ -50,33 +50,7 @@ export declare class GraphRuntime {
|
|
|
50
50
|
} | undefined;
|
|
51
51
|
getEnvironment(): Record<string, unknown>;
|
|
52
52
|
setEnvironment(env: Record<string, unknown>): void;
|
|
53
|
-
getGraphDef():
|
|
54
|
-
nodes: {
|
|
55
|
-
nodeId: string;
|
|
56
|
-
typeId: string;
|
|
57
|
-
params: {
|
|
58
|
-
[x: string]: unknown;
|
|
59
|
-
policy?: Partial<ExecutionPolicy>;
|
|
60
|
-
} | undefined;
|
|
61
|
-
resolvedHandles: {
|
|
62
|
-
inputs: Record<string, import("@bian-womp/spark-protocol").InputHandleDescriptor>;
|
|
63
|
-
outputs: Record<string, import("@bian-womp/spark-protocol").DataTypeId | import("@bian-womp/spark-protocol").DataTypeId[]>;
|
|
64
|
-
inputDefaults: Record<string, unknown>;
|
|
65
|
-
} | undefined;
|
|
66
|
-
}[];
|
|
67
|
-
edges: {
|
|
68
|
-
id: string;
|
|
69
|
-
source: {
|
|
70
|
-
nodeId: string;
|
|
71
|
-
handle: string;
|
|
72
|
-
};
|
|
73
|
-
target: {
|
|
74
|
-
nodeId: string;
|
|
75
|
-
handle: string;
|
|
76
|
-
};
|
|
77
|
-
typeId: string | undefined;
|
|
78
|
-
}[];
|
|
79
|
-
};
|
|
53
|
+
getGraphDef(): GraphDefinition;
|
|
80
54
|
whenIdle(): Promise<void>;
|
|
81
55
|
pause(): void;
|
|
82
56
|
resume(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphRuntime.d.ts","sourceRoot":"","sources":["../../../../src/runtime/GraphRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,eAAe,
|
|
1
|
+
{"version":3,"file":"GraphRuntime.d.ts","sourceRoot":"","sources":["../../../../src/runtime/GraphRuntime.ts"],"names":[],"mappings":"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"}
|
package/lib/esm/index.js
CHANGED
|
@@ -571,57 +571,67 @@ class GraphRuntime {
|
|
|
571
571
|
return node?.outputs[output];
|
|
572
572
|
}
|
|
573
573
|
static buildEdgeConverters(srcDeclared, dstDeclared, registry) {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
return payload;
|
|
594
|
-
if (res.kind === "async")
|
|
595
|
-
return await res.convertAsync(payload, signal);
|
|
596
|
-
return res.convert(payload);
|
|
597
|
-
};
|
|
574
|
+
if (!dstDeclared || !srcDeclared) {
|
|
575
|
+
return {};
|
|
576
|
+
}
|
|
577
|
+
const isUnion = Array.isArray(srcDeclared);
|
|
578
|
+
const srcTypes = isUnion ? srcDeclared : [srcDeclared];
|
|
579
|
+
// Helper to get the coercion for a specific type
|
|
580
|
+
const getCoercion = (typeId) => {
|
|
581
|
+
return registry.resolveCoercion(typeId, dstDeclared);
|
|
582
|
+
};
|
|
583
|
+
// Resolve coercions for all source types
|
|
584
|
+
const coercions = srcTypes.map(getCoercion);
|
|
585
|
+
const hasAsync = coercions.some((r) => r?.kind === "async");
|
|
586
|
+
// Helper to extract and validate typed output for unions
|
|
587
|
+
const extractPayload = (v) => {
|
|
588
|
+
const typeId = getTypedOutputTypeId(v);
|
|
589
|
+
const payload = getTypedOutputValue(v);
|
|
590
|
+
if (isUnion) {
|
|
591
|
+
if (!typeId) {
|
|
592
|
+
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
598
593
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const typeId = getTypedOutputTypeId(v);
|
|
602
|
-
if (!typeId)
|
|
603
|
-
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
604
|
-
if (!srcTypes.includes(typeId))
|
|
605
|
-
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
606
|
-
const payload = getTypedOutputValue(v);
|
|
607
|
-
const res = registry.resolveCoercion(typeId, dstDeclared);
|
|
608
|
-
if (!res)
|
|
609
|
-
return payload;
|
|
610
|
-
if (res.kind === "async")
|
|
611
|
-
throw new Error("Async coercion required but convert used");
|
|
612
|
-
return res.convert(payload);
|
|
613
|
-
};
|
|
594
|
+
if (!srcTypes.includes(typeId)) {
|
|
595
|
+
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
614
596
|
}
|
|
615
597
|
}
|
|
616
|
-
else {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
convertAsync = res.convertAsync;
|
|
620
|
-
else if (res?.kind === "sync")
|
|
621
|
-
convert = res.convert;
|
|
598
|
+
else if (typeId) {
|
|
599
|
+
// Warn if typed output is used for non-union source
|
|
600
|
+
console.warn(`Typed output ${typeId} is fed even though source is not union: ${srcDeclared} -> ${dstDeclared}`);
|
|
622
601
|
}
|
|
602
|
+
return { typeId: typeId || srcTypes[0], payload };
|
|
603
|
+
};
|
|
604
|
+
if (hasAsync) {
|
|
605
|
+
return {
|
|
606
|
+
convertAsync: async (v, signal) => {
|
|
607
|
+
const { typeId, payload } = extractPayload(v);
|
|
608
|
+
const res = getCoercion(typeId);
|
|
609
|
+
if (!res)
|
|
610
|
+
return payload;
|
|
611
|
+
if (res.kind === "async") {
|
|
612
|
+
return await res.convertAsync(payload, signal);
|
|
613
|
+
}
|
|
614
|
+
return res.convert(payload);
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
// Sync path
|
|
619
|
+
const firstCoercion = coercions.find((r) => r?.kind === "sync");
|
|
620
|
+
if (!firstCoercion) {
|
|
621
|
+
return {};
|
|
623
622
|
}
|
|
624
|
-
return {
|
|
623
|
+
return {
|
|
624
|
+
convert: (v) => {
|
|
625
|
+
const { typeId, payload } = extractPayload(v);
|
|
626
|
+
const res = getCoercion(typeId);
|
|
627
|
+
if (!res)
|
|
628
|
+
return payload;
|
|
629
|
+
if (res.kind === "async") {
|
|
630
|
+
throw new Error("Async coercion required but convert used");
|
|
631
|
+
}
|
|
632
|
+
return res.convert(payload);
|
|
633
|
+
},
|
|
634
|
+
};
|
|
625
635
|
}
|
|
626
636
|
scheduleInputsChanged(nodeId) {
|
|
627
637
|
const node = this.nodes.get(nodeId);
|
|
@@ -825,6 +835,9 @@ class GraphRuntime {
|
|
|
825
835
|
const dstNode = this.nodes.get(e.target.nodeId);
|
|
826
836
|
if (!dstNode)
|
|
827
837
|
return;
|
|
838
|
+
// Skip writing to unresolved handles - wait for handle resolution
|
|
839
|
+
if (e.dstDeclared === undefined)
|
|
840
|
+
return;
|
|
828
841
|
const dstIsArray = typeof e.dstDeclared === "string" && e.dstDeclared.endsWith("[]");
|
|
829
842
|
let next = v;
|
|
830
843
|
// If target input is an array type, merge per-edge contributions deterministically
|
|
@@ -982,7 +995,7 @@ class GraphRuntime {
|
|
|
982
995
|
return def.edges.map((e) => {
|
|
983
996
|
const srcNode = def.nodes.find((n) => n.nodeId === e.source.nodeId);
|
|
984
997
|
const dstNode = def.nodes.find((n) => n.nodeId === e.target.nodeId);
|
|
985
|
-
let effectiveTypeId = e.typeId;
|
|
998
|
+
let effectiveTypeId = e.typeId; // Start with original
|
|
986
999
|
let srcDeclared;
|
|
987
1000
|
let dstDeclared;
|
|
988
1001
|
if (srcNode) {
|
|
@@ -991,6 +1004,7 @@ class GraphRuntime {
|
|
|
991
1004
|
srcDeclared = resolved.outputs[e.source.handle];
|
|
992
1005
|
}
|
|
993
1006
|
if (!effectiveTypeId) {
|
|
1007
|
+
// Infer if not explicitly set
|
|
994
1008
|
effectiveTypeId = Array.isArray(srcDeclared)
|
|
995
1009
|
? srcDeclared[0]
|
|
996
1010
|
: srcDeclared;
|
|
@@ -1005,7 +1019,8 @@ class GraphRuntime {
|
|
|
1005
1019
|
id: e.id,
|
|
1006
1020
|
source: { ...e.source },
|
|
1007
1021
|
target: { ...e.target },
|
|
1008
|
-
typeId:
|
|
1022
|
+
typeId: e.typeId, // Preserve original (may be undefined)
|
|
1023
|
+
effectiveTypeId: effectiveTypeId ?? "untyped", // Always present
|
|
1009
1024
|
convert,
|
|
1010
1025
|
convertAsync,
|
|
1011
1026
|
srcUnionTypes: Array.isArray(srcDeclared)
|
|
@@ -1029,18 +1044,19 @@ class GraphRuntime {
|
|
|
1029
1044
|
this.resolvedByNode.set(nodeId, handles);
|
|
1030
1045
|
// Recompute edge converter/type for edges where this node is source or target
|
|
1031
1046
|
for (const e of this.edges) {
|
|
1032
|
-
let srcDeclared = e.
|
|
1047
|
+
let srcDeclared = e.effectiveTypeId; // Use effectiveTypeId as fallback
|
|
1033
1048
|
let dstDeclared = e.dstDeclared;
|
|
1049
|
+
const oldDstDeclared = dstDeclared; // Track old value to detect resolution
|
|
1034
1050
|
if (e.source.nodeId === nodeId) {
|
|
1035
1051
|
const resolved = this.resolvedByNode.get(nodeId);
|
|
1036
1052
|
srcDeclared = resolved
|
|
1037
1053
|
? resolved.outputs[e.source.handle]
|
|
1038
1054
|
: srcDeclared;
|
|
1039
|
-
//
|
|
1055
|
+
// Update effectiveTypeId if original wasn't explicit
|
|
1040
1056
|
if (!e.typeId) {
|
|
1041
|
-
e.
|
|
1042
|
-
? srcDeclared?.[0]
|
|
1043
|
-
: srcDeclared;
|
|
1057
|
+
e.effectiveTypeId = Array.isArray(srcDeclared)
|
|
1058
|
+
? srcDeclared?.[0] ?? "untyped"
|
|
1059
|
+
: srcDeclared ?? "untyped";
|
|
1044
1060
|
}
|
|
1045
1061
|
}
|
|
1046
1062
|
if (e.target.nodeId === nodeId) {
|
|
@@ -1053,6 +1069,19 @@ class GraphRuntime {
|
|
|
1053
1069
|
const conv = GraphRuntime.buildEdgeConverters(srcDeclared, dstDeclared, registry);
|
|
1054
1070
|
e.convert = conv.convert;
|
|
1055
1071
|
e.convertAsync = conv.convertAsync;
|
|
1072
|
+
// If target handle was just resolved (was undefined, now has a type), re-propagate values
|
|
1073
|
+
if (e.target.nodeId === nodeId &&
|
|
1074
|
+
oldDstDeclared === undefined &&
|
|
1075
|
+
dstDeclared !== undefined) {
|
|
1076
|
+
const srcNode = this.nodes.get(e.source.nodeId);
|
|
1077
|
+
if (srcNode) {
|
|
1078
|
+
const srcValue = srcNode.outputs[e.source.handle];
|
|
1079
|
+
if (srcValue !== undefined) {
|
|
1080
|
+
// Re-propagate through the now-resolved edge converter
|
|
1081
|
+
this.propagate(e.source.nodeId, e.source.handle, srcValue);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1056
1085
|
}
|
|
1057
1086
|
// Invalidate downstream for this node so UI refreshes
|
|
1058
1087
|
this.invalidateDownstream(nodeId);
|
|
@@ -1163,10 +1192,23 @@ class GraphRuntime {
|
|
|
1163
1192
|
getGraphDef() {
|
|
1164
1193
|
const nodes = Array.from(this.nodes.values()).map((n) => {
|
|
1165
1194
|
const resolved = this.resolvedByNode.get(n.nodeId);
|
|
1195
|
+
// Collect user-provided inputs (inputs without inbound edges)
|
|
1196
|
+
const initialInputs = {};
|
|
1197
|
+
for (const [handle, value] of Object.entries(n.inputs)) {
|
|
1198
|
+
const hasInbound = this.edges.some((e) => e.target.nodeId === n.nodeId && e.target.handle === handle);
|
|
1199
|
+
if (!hasInbound && value !== undefined) {
|
|
1200
|
+
// Clone to avoid shared references
|
|
1201
|
+
initialInputs[handle] =
|
|
1202
|
+
typeof structuredClone === "function"
|
|
1203
|
+
? structuredClone(value)
|
|
1204
|
+
: JSON.parse(JSON.stringify(value));
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1166
1207
|
return {
|
|
1167
1208
|
nodeId: n.nodeId,
|
|
1168
1209
|
typeId: n.typeId,
|
|
1169
1210
|
params: n.params ? { ...n.params } : undefined,
|
|
1211
|
+
initialInputs: Object.keys(initialInputs).length > 0 ? initialInputs : undefined,
|
|
1170
1212
|
resolvedHandles: resolved ? { ...resolved } : undefined,
|
|
1171
1213
|
};
|
|
1172
1214
|
});
|
|
@@ -1174,7 +1216,7 @@ class GraphRuntime {
|
|
|
1174
1216
|
id: e.id,
|
|
1175
1217
|
source: { nodeId: e.source.nodeId, handle: e.source.handle },
|
|
1176
1218
|
target: { nodeId: e.target.nodeId, handle: e.target.handle },
|
|
1177
|
-
typeId: e.typeId
|
|
1219
|
+
typeId: e.typeId, // Only export original typeId (may be undefined)
|
|
1178
1220
|
}));
|
|
1179
1221
|
return { nodes, edges };
|
|
1180
1222
|
}
|