99} from '@sim/workflow-authz'
1010import { and , eq , isNull } from 'drizzle-orm'
1111import { type NextRequest , NextResponse } from 'next/server'
12- import { updateScheduleContract } from '@/lib/api/contracts/schedules'
12+ import { getScheduleByIdContract , updateScheduleContract } from '@/lib/api/contracts/schedules'
1313import { parseRequest } from '@/lib/api/server'
1414import { getSession } from '@/lib/auth'
1515import { generateRequestId } from '@/lib/core/utils/request'
@@ -27,16 +27,7 @@ const logger = createLogger('ScheduleAPI')
2727
2828export const dynamic = 'force-dynamic'
2929
30- type ScheduleRow = {
31- id : string
32- workflowId : string | null
33- status : string
34- cronExpression : string | null
35- timezone : string | null
36- sourceType : string | null
37- sourceWorkspaceId : string | null
38- jobTitle : string | null
39- }
30+ type ScheduleRow = typeof workflowSchedule . $inferSelect
4031
4132async function fetchAndAuthorize (
4233 requestId : string ,
@@ -45,16 +36,7 @@ async function fetchAndAuthorize(
4536 action : 'read' | 'write'
4637) : Promise < { schedule : ScheduleRow ; workspaceId : string | null } | NextResponse > {
4738 const [ schedule ] = await db
48- . select ( {
49- id : workflowSchedule . id ,
50- workflowId : workflowSchedule . workflowId ,
51- status : workflowSchedule . status ,
52- cronExpression : workflowSchedule . cronExpression ,
53- timezone : workflowSchedule . timezone ,
54- sourceType : workflowSchedule . sourceType ,
55- sourceWorkspaceId : workflowSchedule . sourceWorkspaceId ,
56- jobTitle : workflowSchedule . jobTitle ,
57- } )
39+ . select ( )
5840 . from ( workflowSchedule )
5941 . where ( and ( eq ( workflowSchedule . id , scheduleId ) , isNull ( workflowSchedule . archivedAt ) ) )
6042 . limit ( 1 )
@@ -103,6 +85,37 @@ async function fetchAndAuthorize(
10385 return { schedule, workspaceId : authorization . workflow . workspaceId ?? null }
10486}
10587
88+ export const GET = withRouteHandler (
89+ async ( request : NextRequest , context : { params : Promise < { id : string } > } ) => {
90+ const requestId = generateRequestId ( )
91+
92+ try {
93+ const session = await getSession ( )
94+ if ( ! session ?. user ?. id ) {
95+ return NextResponse . json ( { error : 'Unauthorized' } , { status : 401 } )
96+ }
97+
98+ const parsed = await parseRequest ( getScheduleByIdContract , request , context , {
99+ validationErrorResponse : ( ) =>
100+ NextResponse . json ( { error : 'Invalid request' } , { status : 400 } ) ,
101+ } )
102+ if ( ! parsed . success ) return parsed . response
103+
104+ const { id : scheduleId } = parsed . data . params
105+
106+ // fetchAndAuthorize already loads the full row (and 404s if missing), so
107+ // return it directly — no second query.
108+ const authResult = await fetchAndAuthorize ( requestId , scheduleId , session . user . id , 'read' )
109+ if ( authResult instanceof NextResponse ) return authResult
110+
111+ return NextResponse . json ( { schedule : authResult . schedule } )
112+ } catch ( error ) {
113+ logger . error ( `[${ requestId } ] Failed to get schedule` , { error } )
114+ return NextResponse . json ( { error : 'Failed to get schedule' } , { status : 500 } )
115+ }
116+ }
117+ )
118+
106119export const PUT = withRouteHandler (
107120 async ( request : NextRequest , context : { params : Promise < { id : string } > } ) => {
108121 const requestId = generateRequestId ( )
0 commit comments