diff --git a/services/mam-api/src/routes/sequences.js b/services/mam-api/src/routes/sequences.js index 6f41189..97fc0bf 100644 --- a/services/mam-api/src/routes/sequences.js +++ b/services/mam-api/src/routes/sequences.js @@ -146,13 +146,30 @@ router.put('/:id', async (req, res, next) => { // ── DELETE /:id ─────────────────────────────────────────────────────────────── router.delete('/:id', async (req, res, next) => { try { - await pool.query(`DELETE FROM sequences WHERE id = $1`, [req.params.id]); + const r = await pool.query(`DELETE FROM sequences WHERE id = $1`, [req.params.id]); + if (!r.rowCount) return res.status(404).json({ error: 'Sequence not found' }); res.json({ ok: true }); } catch (e) { next(e); } }); // ── PUT /:id/clips – full replace of clip array (single transaction) ────────── router.put('/:id/clips', async (req, res, next) => { + // Verify sequence exists first (before acquiring transaction client) + const seqCheck = await pool.query(`SELECT id FROM sequences WHERE id = $1`, [req.params.id]); + if (!seqCheck.rows.length) return res.status(404).json({ error: 'Sequence not found' }); + + const clips = Array.isArray(req.body) ? req.body : []; + for (const c of clips) { + if (!c.asset_id) return res.status(400).json({ error: 'Each clip must have asset_id' }); + if (!Number.isFinite(Number(c.timeline_in_frames)) || !Number.isFinite(Number(c.timeline_out_frames)) || + !Number.isFinite(Number(c.source_in_frames)) || !Number.isFinite(Number(c.source_out_frames))) { + return res.status(400).json({ error: 'Clip frame fields must be finite numbers' }); + } + if (!Number.isInteger(Number(c.track)) || Number(c.track) < 0) { + return res.status(400).json({ error: 'Clip track must be a non-negative integer' }); + } + } + const client = await pool.connect(); try { await client.query('BEGIN'); @@ -160,7 +177,6 @@ router.put('/:id/clips', async (req, res, next) => { `DELETE FROM sequence_clips WHERE sequence_id = $1`, [req.params.id] ); - const clips = Array.isArray(req.body) ? req.body : []; for (const c of clips) { await client.query( `INSERT INTO sequence_clips