import { BadRequestException, Body, Controller, Get, Inject, Param, Patch, Post, Req, UseGuards } from "@nestjs/common"; import type { Request } from "express"; import { parseId, requireObject, requireSession } from "../http/validation.js"; import { RbacGuard, RequirePermission, type AuthenticatedRequest } from "../rbac/rbac.guard.js"; import { validateEdlProject } from "./edl.js"; import { EdlService, type EdlLane, type EdlProjectRecord, type EdlProjectView } from "./edl.service.js"; /** * EDL projects (editor-v2 intake): the timeline is the resource, the render is * a queued assemble job. Bodies are parsed with validateEdlProject — closed * enums, integer ms, unknown keys rejected — before anything touches the DB. */ @Controller("video/edl") @UseGuards(RbacGuard) export class EdlController { constructor(@Inject(EdlService) private readonly edl: EdlService) {} @Post() @RequirePermission("media.manage") create( @Req() request: Request & AuthenticatedRequest, @Body() body: unknown, ): Promise { const session = requireSession(request); const project = validateEdlProject(requireObject(body, "body").project); return this.edl.create(session.workspaceId, project, session.userId); } @Patch(":id") @RequirePermission("media.manage") update( @Req() request: Request & AuthenticatedRequest, @Param("id") id: string, @Body() body: unknown, ): Promise { const session = requireSession(request); const project = validateEdlProject(requireObject(body, "body").project); return this.edl.update(session.workspaceId, parseId(id, "id"), project, session.userId); } @Get(":id") @RequirePermission("media.view") get( @Req() request: Request & AuthenticatedRequest, @Param("id") id: string, ): Promise { return this.edl.get(requireSession(request).workspaceId, parseId(id, "id")); } @Post(":id/render") @RequirePermission("media.manage") render( @Req() request: Request & AuthenticatedRequest, @Param("id") id: string, @Body() body: unknown, ): Promise<{ jobId: string }> { const session = requireSession(request); const input = requireObject(body, "body"); const lane: EdlLane | undefined = input.lane === undefined || input.lane === null ? undefined : parseLane(input.lane); return this.edl.render(session.workspaceId, parseId(id, "id"), lane, session.userId); } } function parseLane(value: unknown): EdlLane { if (value !== "local" && value !== "remote") { throw new BadRequestException("lane must be one of local, remote"); } return value; }