From 7a08b90ce705064e9f7e9590ef7d502b83235575 Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Fri, 5 Jun 2026 11:50:30 -0400 Subject: [PATCH] fix(panel): surface mam-api clip-push error body instead of bare HTTP 400 API.pushClips threw 'Clip push HTTP 400' and discarded the response body, hiding the server's specific reason (e.g. "All clip assets must belong to the sequence's project"). Now parse and include the {error} text so conform failures are actionable. No behaviour change to the recorder/capture path. --- services/premiere-plugin-uxp/src/api.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/services/premiere-plugin-uxp/src/api.js b/services/premiere-plugin-uxp/src/api.js index eb10f2b..cfb4cd6 100644 --- a/services/premiere-plugin-uxp/src/api.js +++ b/services/premiere-plugin-uxp/src/api.js @@ -1,4 +1,4 @@ -// Dragonflight API client — v2.1.4 +// Dragonflight API client — v2.1.5 // UXP fetch() notes: // • redirect:'manual' is NOT a supported option — UXP auto-follows redirects // • Authorization is stripped by UXP on cross-origin redirects (security fix) @@ -31,6 +31,21 @@ function trimUrl(u) { return String(u || '').replace(/\/+$/, ''); } + // Pull the human-readable error string out of an API error response. + // mam-api returns { error: "..." } (sometimes with a code); fall back to + // the raw text, then to the HTTP status line. + async function _errText(r) { + const raw = await r.text().catch(() => ''); + if (raw) { + try { + const j = JSON.parse(raw); + if (j && (j.error || j.message)) return j.error || j.message; + } catch (_) { /* not JSON — use raw */ } + return raw.slice(0, 240); + } + return 'HTTP ' + r.status; + } + // Core request — adds Bearer only for same-server URLs. // No redirect option — UXP handles redirects automatically. API.request = async function (urlOrPath, opts) { @@ -143,7 +158,11 @@ headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(clips), }); - if (!r.ok) throw new Error('Clip push HTTP ' + r.status); + if (!r.ok) { + // Surface the server's real reason (e.g. cross-project asset, bad frame + // fields) instead of a bare status code — conform failures were opaque. + throw new Error('Clip push failed (HTTP ' + r.status + '): ' + (await _errText(r))); + } return r.json(); };