@@ -7,18 +7,103 @@ import { getUserEntityPermissions } from '@/lib/permissions/utils'
77import { saveWorkflowToNormalizedTables } from '@/lib/workflows/db-helpers'
88import { db } from '@/db'
99import { workflow } from '@/db/schema'
10+ import type { WorkflowState } from '@/stores/workflows/workflow/types'
1011
1112const logger = createLogger ( 'WorkflowStateAPI' )
1213
14+ // Zod schemas for workflow state validation
15+ const PositionSchema = z . object ( {
16+ x : z . number ( ) ,
17+ y : z . number ( ) ,
18+ } )
19+
20+ const BlockDataSchema = z . object ( {
21+ parentId : z . string ( ) . optional ( ) ,
22+ extent : z . literal ( 'parent' ) . optional ( ) ,
23+ width : z . number ( ) . optional ( ) ,
24+ height : z . number ( ) . optional ( ) ,
25+ collection : z . unknown ( ) . optional ( ) ,
26+ count : z . number ( ) . optional ( ) ,
27+ loopType : z . enum ( [ 'for' , 'forEach' ] ) . optional ( ) ,
28+ parallelType : z . enum ( [ 'collection' , 'count' ] ) . optional ( ) ,
29+ type : z . string ( ) . optional ( ) ,
30+ } )
31+
32+ const SubBlockStateSchema = z . object ( {
33+ id : z . string ( ) ,
34+ type : z . string ( ) ,
35+ value : z . union ( [ z . string ( ) , z . number ( ) , z . array ( z . array ( z . string ( ) ) ) , z . null ( ) ] ) ,
36+ } )
37+
38+ const BlockOutputSchema = z . any ( )
39+
40+ const BlockStateSchema = z . object ( {
41+ id : z . string ( ) ,
42+ type : z . string ( ) ,
43+ name : z . string ( ) ,
44+ position : PositionSchema ,
45+ subBlocks : z . record ( SubBlockStateSchema ) ,
46+ outputs : z . record ( BlockOutputSchema ) ,
47+ enabled : z . boolean ( ) ,
48+ horizontalHandles : z . boolean ( ) . optional ( ) ,
49+ isWide : z . boolean ( ) . optional ( ) ,
50+ height : z . number ( ) . optional ( ) ,
51+ advancedMode : z . boolean ( ) . optional ( ) ,
52+ data : BlockDataSchema . optional ( ) ,
53+ } )
54+
55+ const EdgeSchema = z . object ( {
56+ id : z . string ( ) ,
57+ source : z . string ( ) ,
58+ target : z . string ( ) ,
59+ sourceHandle : z . string ( ) . optional ( ) ,
60+ targetHandle : z . string ( ) . optional ( ) ,
61+ type : z . string ( ) . optional ( ) ,
62+ animated : z . boolean ( ) . optional ( ) ,
63+ style : z . record ( z . any ( ) ) . optional ( ) ,
64+ data : z . record ( z . any ( ) ) . optional ( ) ,
65+ label : z . string ( ) . optional ( ) ,
66+ labelStyle : z . record ( z . any ( ) ) . optional ( ) ,
67+ labelShowBg : z . boolean ( ) . optional ( ) ,
68+ labelBgStyle : z . record ( z . any ( ) ) . optional ( ) ,
69+ labelBgPadding : z . array ( z . number ( ) ) . optional ( ) ,
70+ labelBgBorderRadius : z . number ( ) . optional ( ) ,
71+ markerStart : z . string ( ) . optional ( ) ,
72+ markerEnd : z . string ( ) . optional ( ) ,
73+ } )
74+
75+ const LoopSchema = z . object ( {
76+ id : z . string ( ) ,
77+ nodes : z . array ( z . string ( ) ) ,
78+ iterations : z . number ( ) ,
79+ loopType : z . enum ( [ 'for' , 'forEach' ] ) ,
80+ forEachItems : z . union ( [ z . array ( z . any ( ) ) , z . record ( z . any ( ) ) , z . string ( ) ] ) . optional ( ) ,
81+ } )
82+
83+ const ParallelSchema = z . object ( {
84+ id : z . string ( ) ,
85+ nodes : z . array ( z . string ( ) ) ,
86+ distribution : z . union ( [ z . array ( z . any ( ) ) , z . record ( z . any ( ) ) , z . string ( ) ] ) . optional ( ) ,
87+ count : z . number ( ) . optional ( ) ,
88+ parallelType : z . enum ( [ 'count' , 'collection' ] ) . optional ( ) ,
89+ } )
90+
91+ const DeploymentStatusSchema = z . object ( {
92+ id : z . string ( ) ,
93+ status : z . enum ( [ 'deploying' , 'deployed' , 'failed' , 'stopping' , 'stopped' ] ) ,
94+ deployedAt : z . date ( ) . optional ( ) ,
95+ error : z . string ( ) . optional ( ) ,
96+ } )
97+
1398const WorkflowStateSchema = z . object ( {
14- blocks : z . record ( z . any ( ) ) ,
15- edges : z . array ( z . any ( ) ) ,
16- loops : z . record ( z . any ( ) ) . optional ( ) ,
17- parallels : z . record ( z . any ( ) ) . optional ( ) ,
99+ blocks : z . record ( BlockStateSchema ) ,
100+ edges : z . array ( EdgeSchema ) ,
101+ loops : z . record ( LoopSchema ) . optional ( ) ,
102+ parallels : z . record ( ParallelSchema ) . optional ( ) ,
18103 lastSaved : z . number ( ) . optional ( ) ,
19104 isDeployed : z . boolean ( ) . optional ( ) ,
20105 deployedAt : z . date ( ) . optional ( ) ,
21- deploymentStatuses : z . record ( z . any ( ) ) . optional ( ) ,
106+ deploymentStatuses : z . record ( DeploymentStatusSchema ) . optional ( ) ,
22107 hasActiveSchedule : z . boolean ( ) . optional ( ) ,
23108 hasActiveWebhook : z . boolean ( ) . optional ( ) ,
24109} )
@@ -100,7 +185,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
100185 hasActiveWebhook : state . hasActiveWebhook || false ,
101186 }
102187
103- const saveResult = await saveWorkflowToNormalizedTables ( workflowId , workflowState )
188+ const saveResult = await saveWorkflowToNormalizedTables ( workflowId , workflowState as any )
104189
105190 if ( ! saveResult . success ) {
106191 logger . error ( `[${ requestId } ] Failed to save workflow ${ workflowId } state:` , saveResult . error )
@@ -131,7 +216,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
131216 } ,
132217 { status : 200 }
133218 )
134- } catch ( error : any ) {
219+ } catch ( error : unknown ) {
135220 const elapsed = Date . now ( ) - startTime
136221 if ( error instanceof z . ZodError ) {
137222 logger . warn ( `[${ requestId } ] Invalid workflow state data for ${ workflowId } ` , {
0 commit comments