← 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
M public/admin/cactus-curator.htmlM public/admin/drunk-curator.htmlM public/admin/etsy-bucket.htmlM public/admin/etsy-setup.htmlM public/admin/rooms.htmlM public/admin/seam-debug.html
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 →