← back to Tk 10867 Gb Safe Plan
scripts/live-missing-sample-enumerate.mjs
25 lines
#!/usr/bin/env node
// TK-10867 — READ-ONLY live enumeration of Graham & Brown ACTIVE products
// lacking a "Sample" variant. GraphQL query ONLY — zero mutations. $0 (Admin API).
import fs from 'fs';
const SECRETS = '/Users/macstudio3/Projects/secrets-manager/.env';
const DOMAIN = 'designer-laboratory-sandbox.myshopify.com';
const TOKEN = fs.readFileSync(SECRETS,'utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)[1].trim();
const API = `https://${DOMAIN}/admin/api/2024-10/graphql.json`;
async function gql(q,v){for(let a=0;a<4;a++){const r=await fetch(API,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});const j=await r.json();if(j.errors&&/throttl/i.test(JSON.stringify(j.errors))){await new Promise(s=>setTimeout(s,2000));continue;}return j;}throw new Error('throttled out');}
const Q=`query($c:String){products(first:100,after:$c,query:"vendor:'Graham & Brown' status:active"){pageInfo{hasNextPage endCursor} nodes{id title variants(first:30){nodes{sku title selectedOptions{name value}}}}}}`;
let cursor=null,active=0,missing=[],withSample=0;
while(true){
const j=await gql(Q,{c:cursor});
const p=j.data?.products; if(!p){console.error('ERR',JSON.stringify(j.errors||j).slice(0,300));process.exit(1);}
for(const n of p.nodes){active++;
const hasSample=n.variants.nodes.some(v=>/sample/i.test(v.title)||/-sample$/i.test(v.sku||"")||v.selectedOptions.some(o=>/sample/i.test(o.value)));
if(hasSample)withSample++; else missing.push({id:n.id.split('/').pop(),title:n.title,variantCount:n.variants.nodes.length,skus:n.variants.nodes.map(v=>v.sku).filter(Boolean).slice(0,3)});
}
if(!p.pageInfo.hasNextPage)break; cursor=p.pageInfo.endCursor;
}
const out={ticket:'TK-10867',generated:new Date().toISOString(),store:DOMAIN,vendor:'Graham & Brown',active_count:active,with_sample:withSample,missing_sample_count:missing.length,missing_sample:missing};
fs.writeFileSync('data/live-missing-sample.json',JSON.stringify(out,null,2));
console.log(`GB ACTIVE=${active} withSample=${withSample} MISSING_SAMPLE=${missing.length}`);
console.log(missing.slice(0,15).map(m=>` ${m.id} ${m.title} [${m.variantCount}var] ${m.skus.join(',')}`).join('\n'));