Add the connector contract, reusable nodes and per-port intervals
Connectors are the device-facing node class third parties write, so the surface they build against is versioned and documented: ConnectorNode carries a declared contract version, a polling loop that publishes only what changed and reports health around it, and parameters whose credential fields are marked x-secret so the editor offers the secrets store instead of a text box. They are found through the fluksio.node_types entry point group, with the package's own metadata as the manifest. docs/connectors/ has the contract and the authoring guide; connector-skeleton/ is a working one to copy. The controller no longer knows what any node type is: start, stop and report_health are protocol methods on Node, and the built-ins were migrated to them first, so the hooks a connector implements are the ones the engine has been driving all along. Marking a node reusable moves its source to _lib/ and points the node at it by name. Other flows instantiate it with their own ports and settings, one fix reaches all of them, and a shared source still in use cannot be deleted. Ports gained an interval: an output publishes, and an input wakes its node, at most every n seconds. State keeps the latest value, so only the delivery is skipped, and pressing Run is never throttled. Also fixes autosave sending no version on its first save of a session, which made every flow saved more than once conflict with itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7344eac262
commit
3724b68f23
@@ -453,8 +453,8 @@ function FlowEditorInner({
|
||||
})
|
||||
|
||||
const addNode = useCallback(
|
||||
(type: string) => {
|
||||
const id = uniqueNodeId(definitions, type)
|
||||
(type: string, sourceRef?: string) => {
|
||||
const id = uniqueNodeId(definitions, sourceRef ?? type)
|
||||
// Drop it where the user is looking, but never on top of another node.
|
||||
const position = freePosition(
|
||||
definitions,
|
||||
@@ -470,6 +470,9 @@ function FlowEditorInner({
|
||||
params: {},
|
||||
requires: [],
|
||||
provides: [],
|
||||
// A shared node brings the code; the ports and settings are this
|
||||
// flow's own.
|
||||
...(sourceRef ? { source_ref: sourceRef } : {}),
|
||||
}
|
||||
const nextDefinitions = [...definitions, node]
|
||||
const nextCanvas = [
|
||||
@@ -809,6 +812,9 @@ function FlowEditorInner({
|
||||
onSaveSource={(code) => {
|
||||
if (selected) sourceMutation.mutate({ nodeId: selected.id, code })
|
||||
}}
|
||||
// Sharing rewrites the stored document, so the canvas takes the
|
||||
// server's copy rather than keeping its own.
|
||||
onShared={onReload}
|
||||
onClose={() => {
|
||||
flush()
|
||||
setEditorExpanded(false)
|
||||
@@ -830,6 +836,7 @@ function FlowEditorInner({
|
||||
nodeTypes={nodeTypeInfo ?? []}
|
||||
flows={flows.data}
|
||||
onAddNode={addNode}
|
||||
onAddSharedNode={(libName) => addNode("python", libName)}
|
||||
onRun={() => runMutation.mutate()}
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user