← 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
M lib/catalog.jsM package-lock.jsonM package.jsonM routes/admin.js
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 = '