← back to Dw Width Fix

apply.mjs

35 lines

import fs from 'fs';
const env = Object.fromEntries(fs.readFileSync('.env','utf8').split('\n').filter(l=>l.includes('=')&&!l.startsWith('#')).map(l=>{const i=l.indexOf('=');return [l.slice(0,i).trim(), l.slice(i+1).trim()];}));
const TOKEN = env.SHOPIFY_ADMIN_TOKEN;
const DOMAIN='designer-laboratory-sandbox.myshopify.com';
const API=`https://${DOMAIN}/admin/api/2024-10/graphql.json`;
const LIMIT = parseInt(process.argv[2]||'0',10); // 0 = all; else canary N
const DRY = process.env.DRY==='1';

async function gql(query,variables={}){
  const r=await fetch(API,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query,variables})});
  const j=await r.json(); if(j.errors){console.error(JSON.stringify(j.errors));throw new Error('gql');} return j.data;
}
const items = JSON.parse(fs.readFileSync('to-write.json','utf8'));
const batch = LIMIT>0 ? items.slice(0,LIMIT) : items;

// Restore map: capture LIVE current value fresh (re-read, don't trust file) before writing
const restore = fs.existsSync('restore-map.json') ? JSON.parse(fs.readFileSync('restore-map.json','utf8')) : {};
const M_READ=`query($id:ID!){product(id:$id){id handle metafield(namespace:"custom",key:"width"){id value}}}`;
const M_SET=`mutation($mf:[MetafieldsSetInput!]!){metafieldsSet(metafields:$mf){metafields{id key value} userErrors{field message}}}`;

for(const it of batch){
  const cur = await gql(M_READ,{id:it.id});
  const live = cur.product.metafield ? cur.product.metafield.value : null;
  restore[it.id] = {handle:it.handle, oldValue:live, mfId:cur.product.metafield?cur.product.metafield.id:null, newValue:it.newWidth, source:it.source, ts:new Date().toISOString()};
  if(DRY){ console.log(`DRY  ${it.handle}  live=${JSON.stringify(live)} -> ${JSON.stringify(it.newWidth)}`); continue; }
  const res = await gql(M_SET,{mf:[{ownerId:it.id, namespace:'custom', key:'width', type:'single_line_text_field', value:it.newWidth}]});
  const err = res.metafieldsSet.userErrors;
  if(err && err.length){ console.error(`ERR ${it.handle}`, JSON.stringify(err)); }
  else { console.log(`SET  ${it.handle}  ${JSON.stringify(live)} -> ${JSON.stringify(res.metafieldsSet.metafields[0].value)}`); }
  fs.writeFileSync('restore-map.json', JSON.stringify(restore,null,2)); // persist after each
  await new Promise(r=>setTimeout(r,400));
}
fs.writeFileSync('restore-map.json', JSON.stringify(restore,null,2));
console.log(`\n${DRY?'DRY':'APPLIED'} ${batch.length} items. restore-map.json written (${Object.keys(restore).length} entries).`);