[object Object]

← back to Wallco Ai

admin pages: q() now anchors '/'-prefixed paths to location.origin — strips embedded Basic Auth credentials from the document base URL so JS fetch can construct Requests (Fetch spec rejects credentialed URLs in Request constructor; manifests as 'Failed to execute fetch on Window: Request cannot be constructed from a URL that includes credentials' when page is loaded via http://admin:pw@host/...). Applied to cactus-curator, drunk-curator, rooms, etsy-bucket, etsy-setup, seam-debug

77dbbabfa96c16ee64b04ebb49db3e0cae35e47e · 2026-05-28 10:07:58 -0700 · Steve Abrams

Files touched

Diff

commit 77dbbabfa96c16ee64b04ebb49db3e0cae35e47e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu May 28 10:07:58 2026 -0700

    admin pages: q() now anchors '/'-prefixed paths to location.origin — strips embedded Basic Auth credentials from the document base URL so JS fetch can construct Requests (Fetch spec rejects credentialed URLs in Request constructor; manifests as 'Failed to execute fetch on Window: Request cannot be constructed from a URL that includes credentials' when page is loaded via http://admin:pw@host/...). Applied to cactus-curator, drunk-curator, rooms, etsy-bucket, etsy-setup, seam-debug
---
 public/admin/cactus-curator.html | 9 ++++++++-
 public/admin/drunk-curator.html  | 9 ++++++++-
 public/admin/etsy-bucket.html    | 9 ++++++++-
 public/admin/etsy-setup.html     | 9 ++++++++-
 public/admin/rooms.html          | 9 ++++++++-
 public/admin/seam-debug.html     | 9 ++++++++-
 6 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/public/admin/cactus-curator.html b/public/admin/cactus-curator.html
index f90d8b3..d76c33a 100644
--- a/public/admin/cactus-curator.html
+++ b/public/admin/cactus-curator.html
@@ -194,7 +194,14 @@
 const ADMIN = new URLSearchParams(location.search).get('admin');
 // Collection is a URL param — this curator now serves cactus, drunk-animals, etc.
 const CATEGORY = (new URLSearchParams(location.search).get('category') || 'cactus');
-const q = s => ADMIN ? (s + (s.includes('?')?'&':'?') + 'admin=' + encodeURIComponent(ADMIN)) : s;
+// q(path) — build a fetchable URL. Anchors '/'-prefixed paths to location.origin
+// so URLs are credentials-free; the Fetch spec rejects Request construction
+// when the resolved URL contains userinfo (happens when the page was loaded
+// via http://admin:pw@host/...). Appends ?admin=<token> when present.
+const q = s => {
+  const path = s.startsWith('/') ? location.origin + s : s;
+  return ADMIN ? path + (path.includes('?') ? '&' : '?') + 'admin=' + encodeURIComponent(ADMIN) : path;
+};
 const $ = id => document.getElementById(id);
 const grid = $('grid');
 
diff --git a/public/admin/drunk-curator.html b/public/admin/drunk-curator.html
index d38f7b2..e1e7c7e 100644
--- a/public/admin/drunk-curator.html
+++ b/public/admin/drunk-curator.html
@@ -162,7 +162,14 @@
 const $=s=>document.querySelector(s);
 const ADMIN=new URLSearchParams(location.search).get('admin');
 const CATEGORY=new URLSearchParams(location.search).get('category')||'';
-const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
+// q(path) — build a fetchable URL. Anchors '/'-prefixed paths to location.origin
+// so URLs are credentials-free; the Fetch spec rejects Request construction
+// when the resolved URL contains userinfo (happens when the page was loaded
+// via http://admin:pw@host/...). Appends ?admin=<token> when present.
+const q = s => {
+  const path = s.startsWith('/') ? location.origin + s : s;
+  return ADMIN ? path + (path.includes('?') ? '&' : '?') + 'admin=' + encodeURIComponent(ADMIN) : path;
+};
 let QUEUE=[], RAW_ITEMS=[], i=0, hot=0, not=0, streak=0, decided={};
 // Sort + filter — client-side over RAW_ITEMS so changes are instant. Persist in localStorage.
 let SORT_MODE = localStorage.getItem('drunk_sort') || 'density';
diff --git a/public/admin/etsy-bucket.html b/public/admin/etsy-bucket.html
index 110bb85..355fc73 100644
--- a/public/admin/etsy-bucket.html
+++ b/public/admin/etsy-bucket.html
@@ -47,7 +47,14 @@
 <div class="grid" id="grid"></div>
 <script>
 const ADMIN=new URLSearchParams(location.search).get('admin');
-const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
+// q(path) — build a fetchable URL. Anchors '/'-prefixed paths to location.origin
+// so URLs are credentials-free; the Fetch spec rejects Request construction
+// when the resolved URL contains userinfo (happens when the page was loaded
+// via http://admin:pw@host/...). Appends ?admin=<token> when present.
+const q = s => {
+  const path = s.startsWith('/') ? location.origin + s : s;
+  return ADMIN ? path + (path.includes('?') ? '&' : '?') + 'admin=' + encodeURIComponent(ADMIN) : path;
+};
 const $=id=>document.getElementById(id);
 $('density').value=+(localStorage.getItem('etsy_density')||5); document.documentElement.style.setProperty('--cols',$('density').value);
 $('density').addEventListener('input',e=>{localStorage.setItem('etsy_density',e.target.value);document.documentElement.style.setProperty('--cols',e.target.value);});
diff --git a/public/admin/etsy-setup.html b/public/admin/etsy-setup.html
index 6249f0c..b94c920 100644
--- a/public/admin/etsy-setup.html
+++ b/public/admin/etsy-setup.html
@@ -160,7 +160,14 @@
 </main>
 <script>
 const ADMIN=new URLSearchParams(location.search).get('admin');
-const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
+// q(path) — build a fetchable URL. Anchors '/'-prefixed paths to location.origin
+// so URLs are credentials-free; the Fetch spec rejects Request construction
+// when the resolved URL contains userinfo (happens when the page was loaded
+// via http://admin:pw@host/...). Appends ?admin=<token> when present.
+const q = s => {
+  const path = s.startsWith('/') ? location.origin + s : s;
+  return ADMIN ? path + (path.includes('?') ? '&' : '?') + 'admin=' + encodeURIComponent(ADMIN) : path;
+};
 const $=id=>document.getElementById(id);
 
 function setStatus(id, label, kind){ const e=$('st-'+id); if(e){ e.textContent=label; e.className='status '+(kind||''); } }
diff --git a/public/admin/rooms.html b/public/admin/rooms.html
index ab5b8ea..941b2b6 100644
--- a/public/admin/rooms.html
+++ b/public/admin/rooms.html
@@ -46,7 +46,14 @@
 <div class="grid" id="grid"></div>
 <script>
 const ADMIN=new URLSearchParams(location.search).get('admin');
-const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
+// q(path) — build a fetchable URL. Anchors '/'-prefixed paths to location.origin
+// so URLs are credentials-free; the Fetch spec rejects Request construction
+// when the resolved URL contains userinfo (happens when the page was loaded
+// via http://admin:pw@host/...). Appends ?admin=<token> when present.
+const q = s => {
+  const path = s.startsWith('/') ? location.origin + s : s;
+  return ADMIN ? path + (path.includes('?') ? '&' : '?') + 'admin=' + encodeURIComponent(ADMIN) : path;
+};
 const $=id=>document.getElementById(id);
 let ALL=[];
 $('density').value=+(localStorage.getItem('rooms_density')||4); document.documentElement.style.setProperty('--cols',$('density').value);
diff --git a/public/admin/seam-debug.html b/public/admin/seam-debug.html
index 7e5f510..5dc7582 100644
--- a/public/admin/seam-debug.html
+++ b/public/admin/seam-debug.html
@@ -88,7 +88,14 @@
 const ADMIN=new URLSearchParams(location.search).get('admin');
 const ID0=new URLSearchParams(location.search).get('id')||location.pathname.match(/\/(\d+)$/)?.[1]||'';
 const $=id=>document.getElementById(id);
-const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
+// q(path) — build a fetchable URL. Anchors '/'-prefixed paths to location.origin
+// so URLs are credentials-free; the Fetch spec rejects Request construction
+// when the resolved URL contains userinfo (happens when the page was loaded
+// via http://admin:pw@host/...). Appends ?admin=<token> when present.
+const q = s => {
+  const path = s.startsWith('/') ? location.origin + s : s;
+  return ADMIN ? path + (path.includes('?') ? '&' : '?') + 'admin=' + encodeURIComponent(ADMIN) : path;
+};
 $('idin').value=ID0;
 $('t_box').addEventListener('change',redraw);
 $('t_seam').addEventListener('change',redraw);

← f55c3ff etsyEligible: graceful fallback when seam-defect-boxes.py is  ·  back to Wallco Ai  ·  deploy: ship scripts/seam-defect-boxes.py to prod (used by / da0674d →