@@ -11,11 +11,15 @@ import {
1111 type AppSessionActionResult ,
1212 createGeneratedAppHeroSvg ,
1313 hasAppInterface ,
14+ PostCreateAppRequestSchema ,
1415 PostInstallAppRequestSchema ,
1516 PostLaunchAppRequestSchema ,
1617 PostLoadFromDirectoryRequestSchema ,
18+ PostOverlayPresenceRequestSchema ,
1719 PostRelaunchAppRequestSchema ,
1820 PostReplaceFavoritesRequestSchema ,
21+ PostRunControlRequestSchema ,
22+ PostRunMessageRequestSchema ,
1923 PostStopAppRequestSchema ,
2024 PutAppPermissionsRequestSchema ,
2125 PutFavoriteAppRequestSchema ,
@@ -491,27 +495,6 @@ function parseCapturedBody(body: string): Record<string, unknown> | null {
491495 }
492496}
493497
494- function readSteeringContent (
495- body : Record < string , unknown > | null ,
496- ) : string | null {
497- const content =
498- typeof body ?. content === "string"
499- ? body . content
500- : typeof body ?. message === "string"
501- ? body . message
502- : null ;
503- const trimmed = content ?. trim ( ) ?? "" ;
504- return trimmed . length > 0 ? trimmed : null ;
505- }
506-
507- function readSteeringAction (
508- body : Record < string , unknown > | null ,
509- ) : "pause" | "resume" | null {
510- const action = typeof body ?. action === "string" ? body . action . trim ( ) : "" ;
511- if ( action === "pause" || action === "resume" ) return action ;
512- return null ;
513- }
514-
515498function isAppRunSummary ( value : unknown ) : value is AppRunSummary {
516499 return (
517500 typeof value === "object" &&
@@ -816,7 +799,7 @@ export async function handleAppsRoutes(
816799
817800 if ( method === "PUT" ) {
818801 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
819- if ( rawBody === null || rawBody === undefined ) return true ;
802+ if ( rawBody === null ) return true ;
820803 const parsed = PutFavoriteAppRequestSchema . safeParse ( rawBody ) ;
821804 if ( ! parsed . success ) {
822805 const issue = parsed . error . issues [ 0 ] ;
@@ -845,7 +828,7 @@ export async function handleAppsRoutes(
845828 return true ;
846829 }
847830 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
848- if ( rawBody === null || rawBody === undefined ) return true ;
831+ if ( rawBody === null ) return true ;
849832 const parsed = PostReplaceFavoritesRequestSchema . safeParse ( rawBody ) ;
850833 if ( ! parsed . success ) {
851834 const issue = parsed . error . issues [ 0 ] ;
@@ -871,11 +854,20 @@ export async function handleAppsRoutes(
871854
872855 // Dashboard heartbeat for overlay apps (companion, etc.) — no AppManager run.
873856 if ( method === "POST" && pathname === "/api/apps/overlay-presence" ) {
874- const body = await readJsonBody < { appName ?: string | null } > ( req , res ) ;
875- if ( ! body ) return true ;
876- const raw = body . appName ;
877- const appName =
878- typeof raw === "string" && raw . trim ( ) . length > 0 ? raw . trim ( ) : null ;
857+ const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
858+ if ( rawBody === null ) return true ;
859+ const parsed = PostOverlayPresenceRequestSchema . safeParse ( rawBody ) ;
860+ if ( ! parsed . success ) {
861+ const issue = parsed . error . issues [ 0 ] ;
862+ const issuePath = issue ?. path ?. join ( "." ) ?? "<root>" ;
863+ error (
864+ res ,
865+ `Invalid request body at ${ issuePath } : ${ issue ?. message ?? "validation failed" } ` ,
866+ 400 ,
867+ ) ;
868+ return true ;
869+ }
870+ const { appName } = parsed . data ;
879871 setOverlayAppPresence ( appName ) ;
880872 json ( res , { ok : true , appName } ) ;
881873 return true ;
@@ -946,29 +938,18 @@ export async function handleAppsRoutes(
946938 return true ;
947939 }
948940
949- const body =
950- subroute === "message"
951- ? await readJsonBody < { content ?: string } > ( req , res )
952- : await readJsonBody < { action ?: "pause" | "resume" } > ( req , res ) ;
953- if ( ! body ) return true ;
954-
955- const normalizedBody =
941+ const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
942+ if ( rawBody === null ) return true ;
943+ const parsed =
956944 subroute === "message"
957- ? {
958- content : readSteeringContent ( body ) ,
959- }
960- : {
961- action : readSteeringAction ( body ) ,
962- } ;
963- if (
964- ( subroute === "message" && ! normalizedBody . content ) ||
965- ( subroute === "control" && ! normalizedBody . action )
966- ) {
945+ ? PostRunMessageRequestSchema . safeParse ( rawBody )
946+ : PostRunControlRequestSchema . safeParse ( rawBody ) ;
947+ if ( ! parsed . success ) {
948+ const issue = parsed . error . issues [ 0 ] ;
949+ const issuePath = issue ?. path ?. join ( "." ) ?? "<root>" ;
967950 error (
968951 res ,
969- subroute === "message"
970- ? "content is required"
971- : "action must be pause or resume" ,
952+ `Invalid request body at ${ issuePath } : ${ issue ?. message ?? "validation failed" } ` ,
972953 400 ,
973954 ) ;
974955 return true ;
@@ -978,7 +959,7 @@ export async function handleAppsRoutes(
978959 ctx ,
979960 run ,
980961 subroute ,
981- normalizedBody as Record < string , unknown > ,
962+ parsed . data as Record < string , unknown > ,
982963 ) ;
983964 if ( ! result ) {
984965 error ( res , "Run steering failed" , 500 ) ;
@@ -1024,7 +1005,7 @@ export async function handleAppsRoutes(
10241005 if ( method === "POST" && pathname === "/api/apps/launch" ) {
10251006 try {
10261007 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1027- if ( rawBody === null || rawBody === undefined ) return true ;
1008+ if ( rawBody === null ) return true ;
10281009 const parsed = PostLaunchAppRequestSchema . safeParse ( rawBody ) ;
10291010 if ( ! parsed . success ) {
10301011 const issue = parsed . error . issues [ 0 ] ;
@@ -1053,7 +1034,7 @@ export async function handleAppsRoutes(
10531034 if ( method === "POST" && pathname === "/api/apps/install" ) {
10541035 try {
10551036 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1056- if ( rawBody === null || rawBody === undefined ) return true ;
1037+ if ( rawBody === null ) return true ;
10571038 const parsed = PostInstallAppRequestSchema . safeParse ( rawBody ) ;
10581039 if ( ! parsed . success ) {
10591040 const issue = parsed . error . issues [ 0 ] ;
@@ -1117,7 +1098,7 @@ export async function handleAppsRoutes(
11171098
11181099 if ( method === "POST" && pathname === "/api/apps/stop" ) {
11191100 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1120- if ( rawBody === null || rawBody === undefined ) return true ;
1101+ if ( rawBody === null ) return true ;
11211102 const parsed = PostStopAppRequestSchema . safeParse ( rawBody ) ;
11221103 if ( ! parsed . success ) {
11231104 const issue = parsed . error . issues [ 0 ] ;
@@ -1227,7 +1208,7 @@ export async function handleAppsRoutes(
12271208
12281209 if ( method === "POST" && pathname === "/api/apps/relaunch" ) {
12291210 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1230- if ( rawBody === null || rawBody === undefined ) return true ;
1211+ if ( rawBody === null ) return true ;
12311212 const parsed = PostRelaunchAppRequestSchema . safeParse ( rawBody ) ;
12321213 if ( ! parsed . success ) {
12331214 const issue = parsed . error . issues [ 0 ] ;
@@ -1363,7 +1344,7 @@ export async function handleAppsRoutes(
13631344 // the zod schema in @elizaos /shared so the wire shape is the
13641345 // single source of truth (see contracts/app-permissions-routes.ts).
13651346 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1366- if ( rawBody === null || rawBody === undefined ) return true ;
1347+ if ( rawBody === null ) return true ;
13671348 const parsed = PutAppPermissionsRequestSchema . safeParse ( rawBody ) ;
13681349 if ( ! parsed . success ) {
13691350 const issue = parsed . error . issues [ 0 ] ;
@@ -1395,7 +1376,7 @@ export async function handleAppsRoutes(
13951376 // The schema handles the required check, the absolute-path check,
13961377 // and rejects extra unknown fields via .strict().
13971378 const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1398- if ( rawBody === null || rawBody === undefined ) return true ;
1379+ if ( rawBody === null ) return true ;
13991380 const parsed = PostLoadFromDirectoryRequestSchema . safeParse ( rawBody ) ;
14001381 if ( ! parsed . success ) {
14011382 const issue = parsed . error . issues [ 0 ] ;
@@ -1530,16 +1511,20 @@ export async function handleAppsRoutes(
15301511 }
15311512
15321513 if ( method === "POST" && pathname === "/api/apps/create" ) {
1533- const body = await readJsonBody < { intent ?: string ; editTarget ?: string } > (
1534- req ,
1535- res ,
1536- ) ;
1537- if ( ! body ) return true ;
1538- const intent = body . intent ?. trim ( ) ?? "" ;
1539- if ( ! intent ) {
1540- error ( res , "intent is required" ) ;
1514+ const rawBody = await readJsonBody < Record < string , unknown > > ( req , res ) ;
1515+ if ( rawBody === null ) return true ;
1516+ const parsed = PostCreateAppRequestSchema . safeParse ( rawBody ) ;
1517+ if ( ! parsed . success ) {
1518+ const issue = parsed . error . issues [ 0 ] ;
1519+ const issuePath = issue ?. path ?. join ( "." ) ?? "<root>" ;
1520+ error (
1521+ res ,
1522+ `Invalid request body at ${ issuePath } : ${ issue ?. message ?? "validation failed" } ` ,
1523+ 400 ,
1524+ ) ;
15411525 return true ;
15421526 }
1527+ const { intent, editTarget } = parsed . data ;
15431528
15441529 const runtimeWithActions = runtime as {
15451530 actions ?: Array < {
@@ -1583,11 +1568,11 @@ export async function handleAppsRoutes(
15831568 parameters : {
15841569 mode : "create" ,
15851570 intent,
1586- ...( body . editTarget ? { editTarget : body . editTarget } : { } ) ,
1571+ ...( editTarget ? { editTarget } : { } ) ,
15871572 } ,
15881573 mode : "create" ,
15891574 intent,
1590- ...( body . editTarget ? { editTarget : body . editTarget } : { } ) ,
1575+ ...( editTarget ? { editTarget } : { } ) ,
15911576 } ,
15921577 callback ,
15931578 ) ) as { success ?: boolean ; text ?: string ; data ?: unknown } | undefined ;
0 commit comments