← back to Koroseal Goodrich Audit
tk10347/apply_ed0104.mjs
51 lines
#!/usr/bin/env node
// TK-10347 — TAK-ED01-04: upload cropped cream weave (Steve ruled crop), feature, remove wrong ED01-01.
import fs from 'node:fs';
const ENV = fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env','utf8');
const TOKEN = (ENV.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]?.trim().replace(/^["']|["']$/g,'');
const STORE='designer-laboratory-sandbox.myshopify.com', API='2024-10';
const URL=`https://${STORE}/admin/api/${API}/graphql.json`;
const PID='gid://shopify/Product/7519950602291';
const WRONG='gid://shopify/MediaImage/24773828804659';
const FILE='/tmp/korpg/verify/TAKUMI_TAK-ED01-04_CREAM_cropped.jpg';
const FNAME='TAKUMI_TAK-ED01-04_CREAM_cropped.jpg';
const APPLY=process.argv.includes('--apply');
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function gql(query,variables){
const r=await fetch(URL,{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) throw new Error(JSON.stringify(j.errors)); return j.data;
}
async function run(){
const bytes=fs.statSync(FILE).size;
console.log('APPLY',APPLY,'file',bytes,'bytes');
if(!APPLY){ console.log('DRY: staged upload + createMedia + reorder0 + delete',WRONG); return; }
// 1. staged upload target
const su=await gql(`mutation($input:[StagedUploadInput!]!){ stagedUploadsCreate(input:$input){ stagedTargets{ url resourceUrl parameters{ name value } } userErrors{ message } } }`,
{input:[{filename:FNAME, mimeType:'image/jpeg', resource:'IMAGE', httpMethod:'POST', fileSize:String(bytes)}]});
if(su.stagedUploadsCreate.userErrors.length) throw new Error('staged: '+JSON.stringify(su.stagedUploadsCreate.userErrors));
const t=su.stagedUploadsCreate.stagedTargets[0];
// 2. POST file to staged target
const fd=new FormData();
for(const p of t.parameters) fd.append(p.name,p.value);
fd.append('file', new Blob([fs.readFileSync(FILE)],{type:'image/jpeg'}), FNAME);
const up=await fetch(t.url,{method:'POST',body:fd});
if(!(up.status>=200&&up.status<300)) throw new Error('upload status '+up.status+' '+(await up.text()).slice(0,200));
console.log('uploaded to staged target', up.status, 'resourceUrl', t.resourceUrl);
// 3. create media from resourceUrl
const cm=await gql(`mutation($pid:ID!,$m:[CreateMediaInput!]!){ productCreateMedia(productId:$pid,media:$m){ media{ ... on MediaImage{ id status } } mediaUserErrors{ message } } }`,
{pid:PID, m:[{originalSource:t.resourceUrl, mediaContentType:'IMAGE', alt:'Dapper Paper Weave Cream TAK-ED01-04'}]});
if(cm.productCreateMedia.mediaUserErrors.length) throw new Error('createMedia: '+JSON.stringify(cm.productCreateMedia.mediaUserErrors));
const newId=cm.productCreateMedia.media[0].id; console.log('created',newId);
for(let i=0;i<30;i++){ const p=await gql(`query($id:ID!){ node(id:$id){ ... on MediaImage{ status image{ url } } } }`,{id:newId});
if(p.node.status==='READY'){ console.log('READY',(p.node.image?.url||'').slice(-70)); break; }
if(p.node.status==='FAILED') throw new Error('media FAILED'); await sleep(2000); }
// 4. feature + delete wrong
await gql(`mutation($id:ID!,$moves:[MoveInput!]!){ productReorderMedia(id:$id,moves:$moves){ mediaUserErrors{ message } } }`,{id:PID,moves:[{id:newId,newPosition:'0'}]});
console.log('reordered ->0'); await sleep(2500);
const dd=await gql(`mutation($pid:ID!,$ids:[ID!]!){ productDeleteMedia(productId:$pid,mediaIds:$ids){ deletedMediaIds mediaUserErrors{ message } } }`,{pid:PID,ids:[WRONG]});
console.log('deleted wrong', dd.productDeleteMedia.deletedMediaIds);
const fm=await gql(`query($id:ID!){ product(id:$id){ featuredMedia{ ... on MediaImage{ image{ url } } } media(first:5){ edges{ node{ id } } } } }`,{id:PID});
console.log('NOW featured', fm.product.featuredMedia.image.url, '| imgs', fm.product.media.edges.length);
}
run().catch(e=>{console.error('ERROR',e.message);process.exit(1);});