← back to Wallsandfabrics
wire api-vendor-redact middleware + filter /api/facets + drop ?vendor= and vendor-field search
945023615b1fb503ee26069e232ef55937a26700 · 2026-05-25 21:40:40 -0700 · steve
Mounts _shared/api-vendor-redact above route registration so /api/* responses
have vendor field replaced with 'Designer Wallcoverings' and the top-level
vendors map dropped, and ?vendor= query param stripped from /api/products.
/api/facets now honours ?q= and ?surface= so surface counts + total reflect
the filtered list instead of the whole catalog.
/api/products no longer indexes the vendor field in text search and no longer
accepts ?vendor= (the upstream middleware also strips it; this is local
defense-in-depth).
Files touched
Diff
commit 945023615b1fb503ee26069e232ef55937a26700
Author: steve <steve@designerwallcoverings.com>
Date: Mon May 25 21:40:40 2026 -0700
wire api-vendor-redact middleware + filter /api/facets + drop ?vendor= and vendor-field search
Mounts _shared/api-vendor-redact above route registration so /api/* responses
have vendor field replaced with 'Designer Wallcoverings' and the top-level
vendors map dropped, and ?vendor= query param stripped from /api/products.
/api/facets now honours ?q= and ?surface= so surface counts + total reflect
the filtered list instead of the whole catalog.
/api/products no longer indexes the vendor field in text search and no longer
accepts ?vendor= (the upstream middleware also strips it; this is local
defense-in-depth).
---
server.js | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/server.js b/server.js
index 09eab29..6e3f3f4 100644
--- a/server.js
+++ b/server.js
@@ -77,6 +77,10 @@ function buildCatalog(raw) {
}
const app = express();
+// Strip vendor names from /api/* responses (Steve standing rule — DW vendor
+// names NEVER in customer-facing UI). MUST sit above any route registration so
+// the res.json() wrapper installs before handlers run.
+app.use(require('../_shared/api-vendor-redact'));
app.use(helmet({ contentSecurityPolicy: false }));
app.use(express.json({ limit: '256kb' }));
@@ -169,14 +173,15 @@ function sortProducts(list, mode) {
app.get('/api/products', (req, res) => {
- const { q, surface, vendor, sort = 'newest', page = 1, limit = 24 } = req.query;
+ // ?vendor= is stripped upstream by _shared/api-vendor-redact and search no
+ // longer indexes the vendor field — DW vendor names stay off customer surfaces.
+ const { q, surface, sort = 'newest', page = 1, limit = 24 } = req.query;
let list = PRODUCTS;
if (q) {
const needle = q.toLowerCase();
- list = list.filter(p => (p.title || '').toLowerCase().includes(needle) || (p.tags || []).some(t => t.toLowerCase().includes(needle)) || (p.vendor || '').toLowerCase().includes(needle));
+ list = list.filter(p => (p.title || '').toLowerCase().includes(needle) || (p.tags || []).some(t => t.toLowerCase().includes(needle)));
}
if (surface && surface !== 'all') list = list.filter(p => p.__surface === surface);
- if (vendor && vendor !== 'all') list = list.filter(p => p.vendor === vendor);
list = sortProducts(list, sort);
const total = list.length;
const pageNum = Math.max(1, parseInt(page) || 1);
@@ -186,9 +191,20 @@ app.get('/api/products', (req, res) => {
});
app.get('/api/facets', (req, res) => {
+ // Honour the same filters /api/products honours so the surface counts +
+ // total reflect the FILTERED list (not the whole catalog). vendor filter
+ // is dropped upstream by api-vendor-redact middleware.
+ const { q, surface } = req.query;
+ let list = PRODUCTS;
+ if (q) {
+ const needle = String(q).toLowerCase();
+ list = list.filter(p => (p.title || '').toLowerCase().includes(needle) || (p.tags || []).some(t => String(t).toLowerCase().includes(needle)));
+ }
+ if (surface && surface !== 'all') list = list.filter(p => p.__surface === surface);
+ const surfaces = list.reduce((acc, p) => { acc[p.__surface] = (acc[p.__surface] || 0) + 1; return acc; }, {});
const vendors = {};
- for (const p of PRODUCTS) vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
- res.json({ surfaces: SURFACE_COUNTS, vendors, total: PRODUCTS.length });
+ for (const p of list) vendors[p.vendor] = (vendors[p.vendor] || 0) + 1;
+ res.json({ surfaces, vendors, total: list.length });
});
app.get('/api/sliders', (req, res) => {
← d276b47 retag aesthetic from PG: 3663 rows updated
·
back to Wallsandfabrics
·
replace per-card vendor label with 'Designer Wallcoverings' 835b059 →