← back to Dw Kravet Hires
scripts/live-featured-check.mjs
41 lines
#!/usr/bin/env node
// TK-11658 cycle3 — READ-ONLY: measure the CURRENT live featured-image width for every
// Phase-1 swappable product, to establish ground truth (already-hi-res vs still-low-res)
// instead of assuming. $0 (Admin API reads on our own store). NO writes.
import fs from 'fs'; import path from 'path'; import os from 'os';
const SHOP='designer-laboratory-sandbox', API='2024-10';
const env=fs.readFileSync(path.join(os.homedir(),'Projects/secrets-manager/.env'),'utf8');
const TOK=((env.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]||(env.match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m)||[])[1]||'').trim();
async function gql(q,v){const r=await fetch(`https://${SHOP}.myshopify.com/admin/api/${API}/graphql.json`,{method:'POST',headers:{'X-Shopify-Access-Token':TOK,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v}),signal:AbortSignal.timeout(60000)});const j=await r.json();if(j.errors)throw new Error(JSON.stringify(j.errors));return j.data;}
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
const doc=JSON.parse(fs.readFileSync(path.resolve('data/kravet-hires-swap-map.json'),'utf8'));
const sw=doc.rows.filter(r=>r.swappable_from_local_staging===true);
const ids=sw.map(r=>r.shopify_id);
const Q=`query($ids:[ID!]!){nodes(ids:$ids){... on Product{id media(first:5){nodes{mediaContentType ... on MediaImage{image{width height url}}}}}}}`;
const out=[];
for(let i=0;i<ids.length;i+=50){
const d=await gql(Q,{ids:ids.slice(i,i+50)});
for(const n of d.nodes){
if(!n)continue;
const imgs=(n.media?.nodes||[]).filter(x=>x.mediaContentType==='IMAGE');
const f=imgs[0]?.image||null;
out.push({shopify_id:n.id, feat_w:f?.width??null, feat_h:f?.height??null, feat_le:f?Math.max(f.width,f.height):null, feat_url:f?.url||null, img_count:imgs.length});
}
process.stderr.write(` checked ${Math.min(i+50,ids.length)}/${ids.length}\n`);
await sleep(300);
}
fs.writeFileSync('data/phase1-live-featured-state.json',JSON.stringify({ticket:'TK-11658',cycle:3,checked_at:new Date().toISOString(),total:out.length,rows:out},null,1));
// join to preflight disposition
const pf=JSON.parse(fs.readFileSync('data/phase1-preflight-measured.json','utf8'));
const disp=new Map(pf.rows.map(r=>[r.shopify_id,{status:r.status,disp:r.disposition,ok:r.ok}]));
let hi=0,lo=0,noimg=0, cleanHi=0,cleanLo=0, flagHi=0,flagLo=0;
for(const r of out){
const d=disp.get(r.shopify_id)||{};
if(r.feat_le===null){noimg++;continue;}
const isHi=r.feat_le>=1200;
if(isHi)hi++;else lo++;
if(d.ok){isHi?cleanHi++:cleanLo++;}else{isHi?flagHi++:flagLo++;}
}
console.log(JSON.stringify({total:out.length, live_hi_res_ge1200:hi, live_low_res_lt1200:lo, no_image:noimg,
clean_alreadyHi:cleanHi, clean_stillLow:cleanLo, flagged_alreadyHi:flagHi, flagged_stillLow:flagLo},null,2));