← back to Tk10656 Empty Collections

storefront-empty-scan.mjs

31 lines

// TK-10656 — customer-truth scan: for every collection PUBLISHED to Online Store, fetch the
// storefront /collections/<handle>/products.json (published products only). Flag those that
// return 0 products = a live collection page that shows the SHOPPER nothing (hidden dead page
// even if the Admin productsCount>0, because all members are archived/draft/unpublished).
import { readFileSync, writeFileSync } from 'node:fs';
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
const BASE='https://www.designerwallcoverings.com';
const rows=readFileSync('data/collections-dump.jsonl','utf8').trim().split('\n').map(JSON.parse).filter(c=>c.pub);
let checked=0, emptyToShopper=0, errs=0; const empties=[];
for(const c of rows){
  let ok=false;
  for(let a=0;a<4;a++){
    try{
      const r=await fetch(`${BASE}/collections/${c.handle}/products.json?limit=1`,{headers:{'User-Agent':'Mozilla/5.0 dw-audit'}});
      if(r.status===429||r.status>=500){ await sleep(1500*(a+1)); continue; }
      const j=await r.json().catch(()=>null);
      if(!j){ await sleep(1000*(a+1)); continue; }
      const nprod=(j.products||[]).length;
      if(nprod===0){ emptyToShopper++; empties.push({handle:c.handle,title:c.title,admin_count:c.count}); }
      ok=true; break;
    }catch(e){ await sleep(1000*(a+1)); }
  }
  if(!ok) errs++;
  checked++;
  if(checked%100===0) process.stderr.write(`  checked ${checked}/${rows.length}, empty-to-shopper ${emptyToShopper}, errs ${errs}\n`);
  await sleep(120); // gentle
}
writeFileSync('data/empty-to-shopper.json', JSON.stringify(empties,null,2));
console.log(JSON.stringify({published_collections_checked:checked, EMPTY_to_shopper:emptyToShopper, fetch_errors:errs,
  sample:empties.slice(0,25)},null,2));