@@ -433,7 +433,22 @@ class JobsPlugin extends Plugin {
433433 const { jobKey } = this . _resolveJob ( req , res ) ;
434434 if ( ! jobKey ) return ;
435435
436- const params = req . body ?. params as Record < string , unknown > | undefined ;
436+ const rawParams = req . body ?. params ;
437+ if (
438+ rawParams !== undefined &&
439+ ( typeof rawParams !== "object" ||
440+ rawParams === null ||
441+ Array . isArray ( rawParams ) )
442+ ) {
443+ res
444+ . status ( 400 )
445+ . json ( {
446+ error : "params must be a plain object" ,
447+ plugin : this . name ,
448+ } ) ;
449+ return ;
450+ }
451+ const params = rawParams as Record < string , unknown > | undefined ;
437452 const stream = req . query . stream === "true" ;
438453
439454 try {
@@ -554,6 +569,40 @@ class JobsPlugin extends Plugin {
554569 }
555570 } ,
556571 } ) ;
572+
573+ // DELETE /:jobKey/runs/:runId
574+ this . route ( router , {
575+ name : "cancel-run" ,
576+ method : "delete" ,
577+ path : "/:jobKey/runs/:runId" ,
578+ handler : async ( req : express . Request , res : express . Response ) => {
579+ const { jobKey } = this . _resolveJob ( req , res ) ;
580+ if ( ! jobKey ) return ;
581+
582+ const runId = Number . parseInt ( req . params . runId , 10 ) ;
583+ if ( Number . isNaN ( runId ) ) {
584+ res . status ( 400 ) . json ( { error : "Invalid runId" , plugin : this . name } ) ;
585+ return ;
586+ }
587+
588+ try {
589+ const userPlugin = this . asUser ( req ) as JobsPlugin ;
590+ const api = userPlugin . createJobAPI ( jobKey ) ;
591+ await api . cancelRun ( runId ) ;
592+ res . status ( 204 ) . end ( ) ;
593+ } catch ( error ) {
594+ logger . error (
595+ "Cancel run failed for job %s run %d: %O" ,
596+ jobKey ,
597+ runId ,
598+ error ,
599+ ) ;
600+ res
601+ . status ( 500 )
602+ . json ( { error : "Cancel run failed" , plugin : this . name } ) ;
603+ }
604+ } ,
605+ } ) ;
557606 }
558607
559608 exports ( ) : JobsExport {
0 commit comments