[object Object]

← back to Designerwallcoverings

stout-onboard: fix Sirv (cdn.estout.com) image fetch — add stouttextiles referer+UA, strip thumbnail query (was 403→fail-closed BLOCK on all 180)

acc693b9269c805ad29e7484496d8fb5bd70ba24 · 2026-07-26 16:21:02 -0700 · Steve Abrams

Files touched

Diff

commit acc693b9269c805ad29e7484496d8fb5bd70ba24
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 26 16:21:02 2026 -0700

    stout-onboard: fix Sirv (cdn.estout.com) image fetch — add stouttextiles referer+UA, strip thumbnail query (was 403→fail-closed BLOCK on all 180)
---
 scripts/stout-onboard/create-drafts.mjs   | 6 +++++-
 scripts/stout-onboard/settlement-gate.mjs | 6 +++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/scripts/stout-onboard/create-drafts.mjs b/scripts/stout-onboard/create-drafts.mjs
index de0a9ca..b4945d3 100644
--- a/scripts/stout-onboard/create-drafts.mjs
+++ b/scripts/stout-onboard/create-drafts.mjs
@@ -54,10 +54,14 @@ function dbWriteBack(sku, mfrSku, pid) {
 }
 
 // localize: download the vendor hotlink, POST the bytes (base64) → Shopify re-hosts on its CDN.
+// Sirv (cdn.estout.com) hotlink-protects: needs the stouttextiles.com Referer; the vendor
+// thumbnail query 400s → fetch the bare .jpg (full-res original) so Shopify re-hosts the full image.
+const SIRV_HDRS = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36', 'Referer': 'https://www.stouttextiles.com/' };
+const bareImg = u => String(u).split('?')[0];
 async function attachImage(pid, url, filename) {
   if (!url) return 'no-url';
   try {
-    const resp = await fetch(url, { signal: AbortSignal.timeout(30000) });
+    const resp = await fetch(bareImg(url), { headers: SIRV_HDRS, signal: AbortSignal.timeout(30000) });
     if (!resp.ok) return `dl-${resp.status}`;
     const b64 = Buffer.from(await resp.arrayBuffer()).toString('base64');
     const r = await rest(`/products/${pid}/images.json`, { method: 'POST', body: { image: { attachment: b64, filename } } });
diff --git a/scripts/stout-onboard/settlement-gate.mjs b/scripts/stout-onboard/settlement-gate.mjs
index 88bf129..de7e7be 100644
--- a/scripts/stout-onboard/settlement-gate.mjs
+++ b/scripts/stout-onboard/settlement-gate.mjs
@@ -49,8 +49,12 @@ Acceptable (carveout): Does it clearly contain tree trunks, clearly-drawn branch
 Respond with ONLY this JSON, booleans true/false (never null), plus a 3-6 word evidence string each:
 {"a1":bool,"a2":bool,"a3":bool,"b":bool,"acceptable":bool,"evidence":{"a1":"","a2":"","a3":"","b":"","acceptable":""}}`;
 
+// Sirv (cdn.estout.com) hotlink-protects: it needs the stouttextiles.com Referer, and the
+// vendor thumbnail query (?=&thumbnail=...) 400s — so fetch the bare .jpg (full-res original).
+const SIRV_HDRS = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36', 'Referer': 'https://www.stouttextiles.com/' };
+const bareImg = u => String(u).split('?')[0];
 async function fetchB64(url) {
-  const r = await fetch(url, { signal: AbortSignal.timeout(30000) });
+  const r = await fetch(bareImg(url), { headers: SIRV_HDRS, signal: AbortSignal.timeout(30000) });
   if (!r.ok) throw new Error(`img ${r.status}`);
   const ct = r.headers.get('content-type') || 'image/jpeg';
   const buf = Buffer.from(await r.arrayBuffer());

← cf087fb stout-onboard: full engine (build-payloads/create-drafts/go-  ·  back to Designerwallcoverings  ·  Stroheim onboard: ready-to-run DRAFT scripts (DWST, BUDGET_C 7ec91f4 →