@@ -1255,13 +1255,14 @@ type ChangeWorkflowMailingListRequest struct {
12551255
12561256// ChangeWorkflowMailingListResponse is returned by
12571257// [Client.ChangeWorkflowMailingList]. Status is one of the
1258- // WorkflowMutationStatus* values. WorkflowRevisionID is set only when Status
1259- // is "updated".
1258+ // WorkflowMutationStatus* values. WorkflowRevisionID and Workflow are set only
1259+ // when Status is "updated".
12601260type ChangeWorkflowMailingListResponse struct {
1261- Status string `json:"status"`
1262- MailingListID * string `json:"mailingListId"`
1263- WorkflowRevisionID * string `json:"workflowRevisionId,omitempty"`
1264- QueuedContactCount float64 `json:"queuedContactCount"`
1261+ Status string `json:"status"`
1262+ MailingListID * string `json:"mailingListId"`
1263+ WorkflowRevisionID * string `json:"workflowRevisionId,omitempty"`
1264+ QueuedContactCount float64 `json:"queuedContactCount"`
1265+ Workflow * SimplifiedWorkflow `json:"workflow,omitempty"`
12651266}
12661267
12671268// ChangeWorkflowMailingList changes the mailing list of the workflow
@@ -1312,6 +1313,7 @@ func (c *Client) ChangeWorkflowMailingList(id string, req ChangeWorkflowMailingL
13121313const (
13131314 WorkflowInsertModeBetween = "between"
13141315 WorkflowInsertModeBefore = "before"
1316+ WorkflowInsertModeAfter = "after"
13151317)
13161318
13171319// Node types that can be created via [Client.CreateWorkflowNode]. Trigger and
@@ -1329,8 +1331,11 @@ const (
13291331// InsertMode selects the placement:
13301332// - "between" inserts between FromNodeID and ToNodeID (FromNodeID must
13311333// currently point to ToNodeID); both are required.
1332- // - "before" inserts before BeforeNodeID, which must have an incoming parent
1333- // and cannot be a trigger node.
1334+ // - "before" inserts before ToNodeID, which must have an incoming parent and
1335+ // cannot be a trigger node.
1336+ // - "after" inserts after FromNodeID, valid only when FromNodeID has exactly
1337+ // one outgoing node (not zero, not multiple, and not an exit node). Use
1338+ // "between" with an explicit ToNodeID when the source has multiple outputs.
13341339//
13351340// ExpectedRevisionID is required and always sent (as JSON null when nil).
13361341// NodeTypeName is one of the CreateWorkflowNodeType* constants.
@@ -1340,7 +1345,10 @@ type CreateWorkflowNodeRequest struct {
13401345 NodeTypeName string
13411346 FromNodeID string
13421347 ToNodeID string
1343- BeforeNodeID string
1348+
1349+ // Deprecated: the API now expects ToNodeID for "before" mode. Set ToNodeID
1350+ // instead; BeforeNodeID is only sent when ToNodeID is empty.
1351+ BeforeNodeID string
13441352}
13451353
13461354// CreateWorkflowNodeResponse is returned by [Client.CreateWorkflowNode].
@@ -1363,7 +1371,13 @@ func (c *Client) CreateWorkflowNode(id string, req CreateWorkflowNodeRequest) (*
13631371 body ["fromNodeId" ] = req .FromNodeID
13641372 body ["toNodeId" ] = req .ToNodeID
13651373 case WorkflowInsertModeBefore :
1366- body ["beforeNodeId" ] = req .BeforeNodeID
1374+ if req .ToNodeID != "" {
1375+ body ["toNodeId" ] = req .ToNodeID
1376+ } else {
1377+ body ["beforeNodeId" ] = req .BeforeNodeID
1378+ }
1379+ case WorkflowInsertModeAfter :
1380+ body ["fromNodeId" ] = req .FromNodeID
13671381 }
13681382
13691383 b , err := json .Marshal (body )
@@ -1508,8 +1522,33 @@ type UpdateWorkflowNodeRequest struct {
15081522}
15091523
15101524// UpdateWorkflowNodeResponse is the updated node returned by
1511- // [Client.UpdateWorkflowNode], with the latest workflow revision token.
1512- type UpdateWorkflowNodeResponse = WorkflowMutationNodeWithRevision
1525+ // [Client.UpdateWorkflowNode] (its fields stay flat via the embedded type)
1526+ // plus the latest simplified workflow.
1527+ type UpdateWorkflowNodeResponse struct {
1528+ WorkflowMutationNodeWithRevision
1529+ Workflow SimplifiedWorkflow `json:"workflow"`
1530+ }
1531+
1532+ // UnmarshalJSON decodes the node and revision via the embedded type and then
1533+ // the latest workflow.
1534+ func (n * UpdateWorkflowNodeResponse ) UnmarshalJSON (data []byte ) error {
1535+ if err := n .WorkflowMutationNodeWithRevision .UnmarshalJSON (data ); err != nil {
1536+ return err
1537+ }
1538+ var extra struct {
1539+ Workflow SimplifiedWorkflow `json:"workflow"`
1540+ }
1541+ if err := json .Unmarshal (data , & extra ); err != nil {
1542+ return err
1543+ }
1544+ n .Workflow = extra .Workflow
1545+ return nil
1546+ }
1547+
1548+ // MarshalJSON encodes the embedded node and revision and adds the workflow.
1549+ func (n UpdateWorkflowNodeResponse ) MarshalJSON () ([]byte , error ) {
1550+ return mergeMarshal (n .WorkflowMutationNodeWithRevision , map [string ]any {"workflow" : n .Workflow })
1551+ }
15131552
15141553// UpdateWorkflowNode applies req.Payload to the node identified by
15151554// workflowID/nodeID and returns the updated node.
@@ -1606,13 +1645,14 @@ type DeleteWorkflowNodeRequest struct {
16061645
16071646// DeleteWorkflowNodeResponse is returned by [Client.DeleteWorkflowNode] and
16081647// [Client.DeleteWorkflowNodeRecursive]. Status is one of the
1609- // WorkflowMutationStatus* values. WorkflowRevisionID is set only when Status
1610- // is "deleted".
1648+ // WorkflowMutationStatus* values. WorkflowRevisionID and Workflow are set only
1649+ // when Status is "deleted".
16111650type DeleteWorkflowNodeResponse struct {
1612- Status string `json:"status"`
1613- NodeIDs []string `json:"nodeIds"`
1614- WorkflowRevisionID * string `json:"workflowRevisionId,omitempty"`
1615- QueuedContactCount float64 `json:"queuedContactCount"`
1651+ Status string `json:"status"`
1652+ NodeIDs []string `json:"nodeIds"`
1653+ WorkflowRevisionID * string `json:"workflowRevisionId,omitempty"`
1654+ QueuedContactCount float64 `json:"queuedContactCount"`
1655+ Workflow * SimplifiedWorkflow `json:"workflow,omitempty"`
16161656}
16171657
16181658func (c * Client ) deleteWorkflowNode (path string , req DeleteWorkflowNodeRequest ) (* DeleteWorkflowNodeResponse , error ) {
@@ -1667,3 +1707,79 @@ func (c *Client) DeleteWorkflowNode(workflowID, nodeID string, req DeleteWorkflo
16671707func (c * Client ) DeleteWorkflowNodeRecursive (workflowID , nodeID string , req DeleteWorkflowNodeRequest ) (* DeleteWorkflowNodeResponse , error ) {
16681708 return c .deleteWorkflowNode ("/workflows/" + workflowID + "/nodes/" + nodeID + "/recursive" , req )
16691709}
1710+
1711+ // RerouteNodeConnectionRequest is the request body for
1712+ // [Client.RerouteNodeConnection]. ExpectedRevisionID is required and always
1713+ // sent (as JSON null when nil). NewTargetNodeID is the valid node that should
1714+ // receive the source node's outgoing connection.
1715+ type RerouteNodeConnectionRequest struct {
1716+ ExpectedRevisionID * string
1717+ NewTargetNodeID string
1718+ }
1719+
1720+ // RerouteNodeConnectionResponse is the updated source node returned by
1721+ // [Client.RerouteNodeConnection] (its fields stay flat via the embedded type)
1722+ // plus the latest simplified workflow.
1723+ type RerouteNodeConnectionResponse struct {
1724+ WorkflowMutationNodeWithRevision
1725+ Workflow SimplifiedWorkflow `json:"workflow"`
1726+ }
1727+
1728+ // UnmarshalJSON decodes the node and revision via the embedded type and then
1729+ // the latest workflow.
1730+ func (n * RerouteNodeConnectionResponse ) UnmarshalJSON (data []byte ) error {
1731+ if err := n .WorkflowMutationNodeWithRevision .UnmarshalJSON (data ); err != nil {
1732+ return err
1733+ }
1734+ var extra struct {
1735+ Workflow SimplifiedWorkflow `json:"workflow"`
1736+ }
1737+ if err := json .Unmarshal (data , & extra ); err != nil {
1738+ return err
1739+ }
1740+ n .Workflow = extra .Workflow
1741+ return nil
1742+ }
1743+
1744+ // MarshalJSON encodes the embedded node and revision and adds the workflow.
1745+ func (n RerouteNodeConnectionResponse ) MarshalJSON () ([]byte , error ) {
1746+ return mergeMarshal (n .WorkflowMutationNodeWithRevision , map [string ]any {"workflow" : n .Workflow })
1747+ }
1748+
1749+ // RerouteNodeConnection moves the single outgoing connection of the source node
1750+ // identified by workflowID/nodeID to req.NewTargetNodeID, returning the updated
1751+ // source node and the latest workflow. The source node must have exactly one
1752+ // outgoing connection; branch and experiment branch nodes cannot be rerouted.
1753+ func (c * Client ) RerouteNodeConnection (workflowID , nodeID string , req RerouteNodeConnectionRequest ) (* RerouteNodeConnectionResponse , error ) {
1754+ body := map [string ]any {
1755+ "expectedRevisionId" : req .ExpectedRevisionID ,
1756+ "newTargetNodeId" : req .NewTargetNodeID ,
1757+ }
1758+
1759+ b , err := json .Marshal (body )
1760+ if err != nil {
1761+ return nil , fmt .Errorf ("failed to encode request: %w" , err )
1762+ }
1763+
1764+ httpReq , err := c .newRequest (http .MethodPost , "/workflows/" + workflowID + "/nodes/" + nodeID + "/reroute" , bytes .NewReader (b ))
1765+ if err != nil {
1766+ return nil , err
1767+ }
1768+
1769+ resp , err := c .do (httpReq )
1770+ if err != nil {
1771+ return nil , err
1772+ }
1773+ defer resp .Body .Close ()
1774+
1775+ if resp .StatusCode != http .StatusOK {
1776+ return nil , errorFromResponse (resp )
1777+ }
1778+
1779+ var result RerouteNodeConnectionResponse
1780+ if err := json .NewDecoder (resp .Body ).Decode (& result ); err != nil {
1781+ return nil , fmt .Errorf ("failed to decode response: %w" , err )
1782+ }
1783+
1784+ return & result , nil
1785+ }
0 commit comments