[object Object]

← back to Flockedwallpaper

flockedwallpaper: rebuild data from live catalog (0 banned 'Wallpaper' titles, drop archived/deleted) + wire /img proxy route

fcffa623ad7ab41ed4859ac6cb4c73d678d9129c · 2026-06-22 10:39:40 -0700 · Steve Studio

- flocked_products PG table rebuilt from live dw_unified shopify_products mirror:
  synced 106 ACTIVE rows to current 'Wallcovering' titles, dropped 117 archived/deleted/draft + 4 orphans
- server.js: wire the redact module's /img/<token> image-proxy route (was unrouted in this
  raw-http server -> product images 404'd) + pre-warm token map at boot
- result: 106 products, 0 'Wallpaper' titles, images 200 via Cloudflare

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit fcffa623ad7ab41ed4859ac6cb4c73d678d9129c
Author: Steve Studio <steve@designerwallcoverings.com>
Date:   Mon Jun 22 10:39:40 2026 -0700

    flockedwallpaper: rebuild data from live catalog (0 banned 'Wallpaper' titles, drop archived/deleted) + wire /img proxy route
    
    - flocked_products PG table rebuilt from live dw_unified shopify_products mirror:
      synced 106 ACTIVE rows to current 'Wallcovering' titles, dropped 117 archived/deleted/draft + 4 orphans
    - server.js: wire the redact module's /img/<token> image-proxy route (was unrouted in this
      raw-http server -> product images 404'd) + pre-warm token map at boot
    - result: 106 products, 0 'Wallpaper' titles, images 200 via Cloudflare
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 server.js | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/server.js b/server.js
index 80ad649..f78e58d 100644
--- a/server.js
+++ b/server.js
@@ -3,11 +3,31 @@ const fs = require('fs');
 const path = require('path');
 require('dotenv').config({ path: process.env.DOTENV_PATH || '/root/DW-Agents/claudette-agent/.env' });
 const { Pool } = require('pg');
-const { redact } = require('../_shared/api-vendor-redact'); // scrub DW vendor names from /api responses (standing rule; raw-http server, so applied by hand)
+const apiVendorRedact = require('../_shared/api-vendor-redact'); // default export = Express-style middleware; also handles GET /img/<token> image proxy
+const { redact } = apiVendorRedact; // scrub DW vendor names from /api responses (standing rule; raw-http server, so applied by hand)
 
 const PORT = process.env.PORT || 3200;
 const pool = new Pool({ connectionString: process.env.DB_URL || process.env.DATABASE_URL });
 
+// Pre-warm the /img token map at boot so /img/<token> resolves immediately after a
+// pm2 restart (closes the cold-start 404 window). warm(products) registers token->url
+// for every product image url. Safe no-op if the catalog can't load.
+async function warmImgMap() {
+    if (typeof apiVendorRedact.warm !== 'function') return;
+    try { apiVendorRedact.warm(await getProducts()); } catch (e) { /* cold map; lazily filled by /api/products */ }
+}
+
+// Serve GET /img/<token> by delegating to the redact module's image proxy. The module's
+// default export is Express-style middleware that handles /img/ when req.path starts with
+// it; we adapt the raw-http req/res to the minimal shape it needs (req.path, res.status,
+// res.setHeader, res.end). On an unknown token the middleware calls next() -> 404 here.
+function serveImg(req, requestPath, res) {
+    const shimReq = { method: 'GET', path: requestPath };
+    res.status = (code) => { res.statusCode = code; return res; };
+    const next = () => { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('<h1>404 - File Not Found</h1>', 'utf-8'); };
+    return apiVendorRedact(shimReq, res, next);
+}
+
 let productsCache = null;
 let productsCacheAt = 0;
 async function getProducts() {
@@ -53,6 +73,14 @@ const server = http.createServer((req, res) => {
     res.setHeader('Pragma', 'no-cache');
     res.setHeader('Expires', '0');
 
+    // Vendor-neutral image proxy: /img/<token> streams the original CDN image without
+    // exposing the supplier name in the url (the redact module rewrites image urls to
+    // these tokens in /api/products). serveImg sets its own immutable Cache-Control.
+    const imgPath = req.url.split('?')[0];
+    if (req.method === 'GET' && imgPath.indexOf('/img/') === 0) {
+        return serveImg(req, imgPath, res);
+    }
+
     if (req.url === '/api/products' || req.url.startsWith('/api/products?')) {
         getProducts()
             .then(rows => {
@@ -119,4 +147,5 @@ server.listen(PORT, '0.0.0.0', () => {
     console.log(`  Local: http://localhost:${PORT}/`);
     console.log(`  External: http://45.61.58.125:${PORT}/`);
     console.log('Press Ctrl+C to stop the server');
+    warmImgMap().then(() => console.log('  /img token map pre-warmed'));
 });

← 78c5957 leak fix: 404-guard raw catalog json (flocked-products.json  ·  back to Flockedwallpaper  ·  corner-nav: move login to its own hamburger in upper-left (p adf4683 →