[object Object]

← back to Dw Domain Fleet

render.js+server.js: eliminate data-handle/data-sku DOM vendor leak via clean-slug + /buy/:slug server-side redirect (DTD verdict B), reconciled on top of verdict-A slug-cleaning

56504dec8909ead297e91e0298d44b5850a83bb5 · 2026-05-29 22:42:17 -0700 · Steve Abrams

data-handle + data-sku now carry the vendor-free productSlug instead of the raw
Shopify handle; the quick-view buy-sample CTA links to the fleet's own /buy/:slug
route, which resolves the real handle server-side and 302-redirects to the DW
store — so the raw vendor-laden handle never reaches the rendered DOM. Folds in
the parallel session's productSlug \s+ re-hyphenate refinement (verdict A). Closed
redirect: target host hardcoded, slug validated, 404 on miss.

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

Files touched

Diff

commit 56504dec8909ead297e91e0298d44b5850a83bb5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri May 29 22:42:17 2026 -0700

    render.js+server.js: eliminate data-handle/data-sku DOM vendor leak via clean-slug + /buy/:slug server-side redirect (DTD verdict B), reconciled on top of verdict-A slug-cleaning
    
    data-handle + data-sku now carry the vendor-free productSlug instead of the raw
    Shopify handle; the quick-view buy-sample CTA links to the fleet's own /buy/:slug
    route, which resolves the real handle server-side and 302-redirects to the DW
    store — so the raw vendor-laden handle never reaches the rendered DOM. Folds in
    the parallel session's productSlug \s+ re-hyphenate refinement (verdict A). Closed
    redirect: target host hardcoded, slug validated, 404 on miss.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 server.js        | 14 ++++++++++++++
 shared/render.js | 16 ++++++++++------
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/server.js b/server.js
index 23c9a0a..38de191 100644
--- a/server.js
+++ b/server.js
@@ -103,6 +103,20 @@ app.get('/product/:handle', (req, res) => {
   res.type('html').send(render.productPage(cfg, p, related));
 });
 
+// Buy-sample redirect: the quick-view CTA links here with the CLEAN productSlug
+// (data-handle no longer carries the raw vendor-laden Shopify handle — settlement
+// vendor-confidentiality, DTD verdict B). We resolve the real handle SERVER-SIDE
+// and 302 to the DW store, so the vendor token never reaches the rendered DOM.
+// Closed redirect — target host is hardcoded, slug is validated, 404 on miss.
+app.get('/buy/:slug', (req, res) => {
+  const key = String(req.params.slug || '').slice(0, 200);
+  const p = POOL.find(x => render.productSlug(x) === key)
+         || POOL.find(x => x.handle === key);
+  if (!p || !p.handle) return res.status(404).type('html').send(render.aboutPage(cfg));
+  res.redirect(302, 'https://designerwallcoverings.com/products/'
+    + encodeURIComponent(p.handle) + '#sample');
+});
+
 app.get('/about', (req, res) => {
   res.type('html').send(render.aboutPage(cfg));
 });
diff --git a/shared/render.js b/shared/render.js
index a6ce14f..f31bdd5 100644
--- a/shared/render.js
+++ b/shared/render.js
@@ -21,7 +21,8 @@ function clean(s) {
  */
 function productSlug(p) {
   const h = (p && p.handle) || '';
-  let s = scrubVendor(h).replace(/wallpapers/gi, 'wallcoverings').replace(/wallpaper/gi, 'wallcovering');
+  let s = scrubVendor(h).replace(/wallpapers/gi, 'wallcoverings').replace(/wallpaper/gi, 'wallcovering')
+    .replace(/\s+/g, '-');   // scrubVendor leaves a space where each vendor token was — re-hyphenate for a clean slug
   s = s.replace(/-{2,}/g, '-').replace(/^-+|-+$/g, '');
   if (s) return s;
   // The ENTIRE handle was a vendor name (e.g. "brunschwig-fils") → scrubbing it
@@ -328,8 +329,11 @@ function jsonld(cfg) {
  * split by the browser's Adoption Agency Algorithm into sibling grid items.
  * The crawlable link is an inner <a class=card-link> pointing at
  * /product/:slug (productSlug — "wallpaper"-free) so search engines reach
- * every per-SKU page on a clean URL. data-handle still carries the real
- * Shopify handle for the quick-view modal's buy-sample link.
+ * every per-SKU page on a clean URL. data-handle carries the CLEAN productSlug
+ * (vendor-free) — the quick-view buy-sample link points at the fleet's own
+ * /buy/:slug route, which resolves the real Shopify handle SERVER-SIDE and
+ * 302-redirects to the DW store, so the raw vendor-laden handle never reaches
+ * the rendered DOM (2026-05-29 settlement vendor-confidentiality, DTD verdict B).
  */
 function card(p) {
   const hx = dominantHex(p);
@@ -337,8 +341,8 @@ function card(p) {
             || scrubVendor((p.sku||p.handle||'').replace(/-Sample$/i,''))
             || 'Designer Wallcovering';
   const href = '/product/' + encodeURIComponent(productSlug(p));
-  return `<div class="card" data-handle="${esc(p.handle)}"
-    data-title="${esc(t)}" data-sku="${esc(p.sku||p.handle)}"
+  return `<div class="card" data-handle="${esc(productSlug(p))}"
+    data-title="${esc(t)}" data-sku="${esc(scrubVendor(p.sku||p.handle))}"
     data-img="${esc(p.image_url)}" data-tags="${esc(scrubTags(p.tags).slice(0,12).join(', '))}"
     data-price="${esc(p.price)}">
   <a class="card-link" href="${esc(href)}" aria-label="${esc(t)}">
@@ -576,7 +580,7 @@ function nsModal(cfg){
     var chips=document.getElementById('nsmChips');chips.innerHTML='';
     (c.dataset.tags||'').split(',').map(function(s){return s.trim();}).filter(Boolean).slice(0,8)
       .forEach(function(t){var s=document.createElement('span');s.textContent=t;chips.appendChild(s);});
-    document.getElementById('nsmCta').href='${DW}/products/'+c.dataset.handle+'#sample';
+    document.getElementById('nsmCta').href='/buy/'+encodeURIComponent(c.dataset.handle);
     back.classList.add('open');
   }
   // cards are real crawlable links to /product/:handle — they navigate.

← a2b73c4 Park C (vendor handle source-rename) plan — DTD verdict A's  ·  back to Dw Domain Fleet  ·  Close C: 'A is enough' (Steve 2026-05-29). Source handle ren 5aee355 →