[object Object]

← back to Interiordesignershowroom

chore: lint, refactor, v0.2.0 (session close)

562d72320303b83c05a05dae8af921d2058d6423 · 2026-08-03 09:40:13 -0700 · Steve

Lint: colon-safe Basic-auth parse. Refactor (behavior-preserving): move
AFFILIATE_ENABLED const above buildWhere; NUL->KEY_SEP; chip param key->netKey;
dedup joinedNets label. Verified: auth 401/200, /shop + affiliates + suggested
200, toggle round-trip. Minor bump — session shipped the affiliate on/off admin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 562d72320303b83c05a05dae8af921d2058d6423
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Aug 3 09:40:13 2026 -0700

    chore: lint, refactor, v0.2.0 (session close)
    
    Lint: colon-safe Basic-auth parse. Refactor (behavior-preserving): move
    AFFILIATE_ENABLED const above buildWhere; NUL->KEY_SEP; chip param key->netKey;
    dedup joinedNets label. Verified: auth 401/200, /shop + affiliates + suggested
    200, toggle round-trip. Minor bump — session shipped the affiliate on/off admin.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 lib/catalog.js    | 24 ++++++++++++------------
 package-lock.json |  4 ++--
 package.json      |  2 +-
 routes/admin.js   | 20 +++++++++++++-------
 4 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/lib/catalog.js b/lib/catalog.js
index acb016c..f5454b5 100644
--- a/lib/catalog.js
+++ b/lib/catalog.js
@@ -12,6 +12,17 @@ const PRICE_BUCKETS = [
   ['150', 'Under $150'], ['300', 'Under $300'], ['600', 'Under $600'], ['999999', 'Any price'],
 ];
 
+// Storefront visibility gate: hide any product whose network — or whose specific
+// (network, advertiser) — has been switched OFF in the admin's affiliate_settings.
+// Correlates on the outer `products` row; carries no params (admin state, not user
+// input) so it slots into every buildWhere caller without renumbering placeholders.
+const AFFILIATE_ENABLED = `NOT EXISTS (
+    SELECT 1 FROM affiliate_settings a
+    WHERE a.enabled = FALSE
+      AND a.network = products.network
+      AND (a.advertiser = '' OR a.advertiser = COALESCE(products.advertiser, ''))
+  )`;
+
 // Build a parameterized WHERE from active filters, optionally EXCLUDING one
 // dimension (so a facet's own counts reflect the rest of the query, not itself).
 function buildWhere(f, exclude) {
@@ -27,17 +38,6 @@ function buildWhere(f, exclude) {
   return { sql: where.join(' AND '), params };
 }
 
-// Storefront visibility gate: hide any product whose network — or whose specific
-// (network, advertiser) — has been switched OFF in the admin's affiliate_settings.
-// Correlates on the outer `products` row; carries no params (admin state, not user
-// input) so it slots into every buildWhere caller without renumbering placeholders.
-const AFFILIATE_ENABLED = `NOT EXISTS (
-    SELECT 1 FROM affiliate_settings a
-    WHERE a.enabled = FALSE
-      AND a.network = products.network
-      AND (a.advertiser = '' OR a.advertiser = COALESCE(products.advertiser, ''))
-  )`;
-
 // Serialize filters back to a query string, applying a change (set/clear one key).
 function toQuery(f, change = {}) {
   const merged = { ...f, ...change };
@@ -105,4 +105,4 @@ async function fetchProducts(f, limit = 200) {
   return r.rows;
 }
 
-module.exports = { parseFilters, fetchProducts, facetCounts, facetRail, activeChips, toQuery, productCard };
+module.exports = { parseFilters, fetchProducts, facetCounts, facetRail, activeChips, toQuery, productCard, AFFILIATE_ENABLED, DIMENSIONS };
diff --git a/package-lock.json b/package-lock.json
index b2b7154..72ddafa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "interiordesignershowroom",
-  "version": "0.1.0",
+  "version": "0.2.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "interiordesignershowroom",
-      "version": "0.1.0",
+      "version": "0.2.0",
       "dependencies": {
         "dotenv": "^17.4.2",
         "express": "^4.19.2",
diff --git a/package.json b/package.json
index 32b4d69..556bf61 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "interiordesignershowroom",
-  "version": "0.1.0",
+  "version": "0.2.0",
   "private": true,
   "description": "Curated, editorial affiliate showroom for interior design — multi-network (CJ, Amazon, Rakuten, ShareASale) feed-driven catalog + buying guides.",
   "main": "server.js",
diff --git a/routes/admin.js b/routes/admin.js
index 740e174..7b4b727 100644
--- a/routes/admin.js
+++ b/routes/admin.js
@@ -73,8 +73,11 @@ function auth(req, res, next) {
   const h = req.get('authorization') || '';
   const m = h.match(/^Basic (.+)$/);
   if (m) {
-    const [u, p] = Buffer.from(m[1], 'base64').toString().split(':');
-    if (u != null && p != null && safeEq(u, USER) && safeEq(p, PASS)) {
+    const decoded = Buffer.from(m[1], 'base64').toString();
+    const colonIdx = decoded.indexOf(':');
+    const u = colonIdx === -1 ? decoded : decoded.slice(0, colonIdx);
+    const p = colonIdx === -1 ? undefined : decoded.slice(colonIdx + 1);
+    if (u !== undefined && p !== undefined && safeEq(u, USER) && safeEq(p, PASS)) {
       // Non-secret UI hint: tells the public storefront to show the admin "see-more"
       // bar. NOT a security boundary — every mutation still requires this Basic auth.
       res.cookie('ids_admin_ui', '1', { maxAge: 12 * 3600e3, sameSite: 'lax', path: '/' });
@@ -445,8 +448,10 @@ router.post('/admin/brands/keyword/apply', async (req, res, next) => {
 // storefront, room builder, and brand facet (see the AFFILIATE_ENABLED gate in
 // lib/catalog.js + lib/rooms.js). A product is live only if BOTH its network and
 // its advertiser are on.
-const NUL = '';
-const key = (net, adv) => `${net}${NUL}${adv || ''}`;
+// Null byte as composite-key separator: guaranteed absent from any real network or
+// advertiser string, so the key never collides across its two parts.
+const KEY_SEP = '\x00';
+const key = (net, adv) => `${net}${KEY_SEP}${adv || ''}`;
 
 // A live on/off form button. `disabledOn` (network is off) locks an advertiser's
 // row so you can't pretend a merchant is live while its whole network is dark.
@@ -593,7 +598,7 @@ router.get('/admin/affiliates/suggested', async (req, res, next) => {
     const openCount = enriched.length - joinedCount;
 
     // network filter chips
-    const chip = (key, label, on) => `<a href="/admin/affiliates/suggested${key ? `?network=${key}` : ''}" class="${on ? 'on' : ''}">${esc(label)}</a>`;
+    const chip = (netKey, label, on) => `<a href="/admin/affiliates/suggested${netKey ? `?network=${netKey}` : ''}" class="${on ? 'on' : ''}">${esc(label)}</a>`;
     const chips = `<div class="chips">
       ${chip('', 'All networks', !netFilter)}
       ${Object.keys(NETWORKS).map((k) => chip(k, NETWORKS[k].label, netFilter === k)).join('')}
@@ -604,9 +609,10 @@ router.get('/admin/affiliates/suggested', async (req, res, next) => {
 
     const rows = shown.map((l) => {
       const primary = l.network;
+      const joinedLabel = l.joinedNets.map((k) => (NETWORKS[k] ? NETWORKS[k].label : k)).join(', ');
       const joinBtn = l.joined
-        ? `<span class="subtle" title="Already in your catalog on ${esc(l.joinedNets.map((k) => (NETWORKS[k] ? NETWORKS[k].label : k)).join(', '))}">on ${esc(l.joinedNets.map((k) => (NETWORKS[k] ? NETWORKS[k].label : k)).join(', '))}</span>`
-        : `<a class="ezjoin" href="${esc(NETWORKS[primary].join)}" target="_blank" rel="noopener nofollow" title="Opens ${esc(NETWORKS[primary].label)} — search “${esc(l.name)}” and click Join">EZ Join on ${esc(NETWORKS[primary].label)} →</a>`;
+        ? `<span class=”subtle” title=”Already in your catalog on ${esc(joinedLabel)}”>on ${esc(joinedLabel)}</span>`
+        : `<a class=”ezjoin” href=”${esc(NETWORKS[primary].join)}” target=”_blank” rel=”noopener nofollow” title=”Opens ${esc(NETWORKS[primary].label)} — search “${esc(l.name)}” and click Join”>EZ Join on ${esc(NETWORKS[primary].label)} →</a>`;
       return `<tr class="${l.joined ? 'row-off' : ''}">
         <td><b>${esc(l.name)}</b></td>
         <td>${netBadges(l.nets)}</td>

← 33bf504 IDS admin: confirm CJ PID 101848244, drop bogus 1062321 (TK-  ·  back to Interiordesignershowroom  ·  IDS admin: implement EZ-Join DTD verdict (C+relabel), fix sm 3e86ee5 →