← back to Tk10640 Redirect Prune

probe-source-liveness.mjs

30 lines

// READ-ONLY bounded probe: of the /products/<handle> -> "/" redirects, how many SOURCE
// handles are DEAD (404, safe prune) vs LIVE (redirect hijacks a live product -> BUG).
import { readFileSync } from 'node:fs';
const txt=readFileSync(`${process.env.HOME}/Projects/secrets-manager/.env`,'utf8');
const env={}; for(const l of txt.split('\n')){const m=l.match(/^([A-Z0-9_]+)=(.*)$/); if(m) env[m[1]]=m[2].replace(/^["']|["']$/g,'');}
const STORE=env.SHOPIFY_STORE_DOMAIN, TOKEN=env.SHOPIFY_FULL_ACCESS_TOKEN, API='2024-10';
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function gql(q,v={}){for(let a=0;;a++){const res=await fetch(`https://${STORE}/admin/api/${API}/graphql.json`,{method:'POST',headers:{'Content-Type':'application/json','X-Shopify-Access-Token':TOKEN},body:JSON.stringify({query:q,variables:v})});const j=await res.json();if(j.errors){if(/THROTTLED/i.test(JSON.stringify(j.errors))&&a<8){await sleep(1500*(a+1));continue;}throw new Error(JSON.stringify(j.errors));}return j.data;}}
const N=Number((process.argv.find(a=>a.startsWith('--n='))||'').split('=')[1]||300);
const rows=readFileSync('data/redirects-dump.jsonl','utf8').trim().split('\n').map(JSON.parse);
const norm=s=>(s||'').split('?')[0].split('#')[0];
const prodToRoot=rows.filter(r=>{const t=norm(r.target);return (!t||t==='/')&&/^\/products\//.test(r.path);});
const handles=[...new Set(prodToRoot.map(r=>r.path.replace(/^\/products\//,'').split('?')[0].split('#')[0]))];
process.stderr.write(`/products->/ redirects: ${prodToRoot.length}, unique source handles: ${handles.length}. Probing first ${N}...\n`);
let dead=0, live=0;
for(let i=0;i<Math.min(N,handles.length);i++){
  const h=handles[i];
  const d=await gql(`query($h:String!){ productByHandle(handle:$h){ id status } }`,{h});
  if(d.productByHandle) live++; else dead++;
  if(i%50===49) process.stderr.write(`  probed ${i+1}: dead=${dead} live=${live}\n`);
}
const probed=Math.min(N,handles.length);
console.log(JSON.stringify({
  products_to_root_redirects: prodToRoot.length,
  unique_source_handles: handles.length,
  probed, dead_source_404: dead, live_source_HIJACK: live,
  dead_ratio:+(dead/probed).toFixed(3), live_ratio:+(live/probed).toFixed(3),
  interpretation: 'dead_source=safe prune (URL 404s anyway); live_source=redirect HIDES a live product page behind homepage (bug, delete restores it)'
},null,2));