← back to Majilite Onboard
scripts/collection.js
34 lines
const fs=require('fs'),path=require('path');
const STORE='designer-laboratory-sandbox.myshopify.com';
const TOKEN=(fs.readFileSync(path.join(process.env.HOME,'Projects/secrets-manager/.env'),'utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1].replace(/["']/g,'').trim();
const GQL=`https://${STORE}/admin/api/2024-10/graphql.json`;
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function gql(q,v){const r=await fetch(GQL,{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)throw new Error(JSON.stringify(j.errors).slice(0,200));return j.data;}
(async()=>{
const desc='<p>The <strong>Metallic Specialties I</strong> collection from Majilite — <em>The Nytek®</em> engineered Nylon-Fiber-Matrix faux leather. 160 luxurious, breathable, durable metallic & neutral finishes for wall coverings, seating, flat surfaces and displays. PFAS-, PVC- and plasticizer-free. Sample swatches; sold by the yard (54" wide).</p>';
// idempotent: reuse if handle exists
let d=await gql(`mutation($input:CollectionInput!){ collectionCreate(input:$input){ collection{ id handle title } userErrors{field message} } }`,
{input:{ title:'Majilite Metallic Specialties I', handle:'majilite-metallic-specialties-i', descriptionHtml:desc,
ruleSet:{ appliedDisjunctively:false, rules:[
{column:'TAG', relation:'EQUALS', condition:'Metallic Specialties I'},
{column:'VENDOR', relation:'EQUALS', condition:'Majilite'}
]}}});
let ue=d.collectionCreate.userErrors;
let col=d.collectionCreate.collection;
if(ue&&ue.length){ console.log('create userErrors:',JSON.stringify(ue)); if(!col){console.log('aborting');return;} }
console.log('collection:', col.id, col.handle, '·', col.title);
// publish collection to Online Store + Google & YouTube
const pd=await gql(`{ publications(first:20){ nodes{ id name } } }`);
const targets=pd.publications.nodes.filter(p=>/online store|google/i.test(p.name));
const pp=await gql(`mutation($id:ID!,$pubs:[PublicationInput!]!){ publishablePublish(id:$id, input:$pubs){ userErrors{field message} } }`,
{id:col.id, pubs:targets.map(t=>({publicationId:t.id}))});
console.log('published to:', targets.map(t=>t.name).join(', '), pp.publishablePublish.userErrors.length?JSON.stringify(pp.publishablePublish.userErrors):'ok');
// smart-collection population is async; poll count
for(let i=0;i<6;i++){ await sleep(2500);
const c=await gql(`query($id:ID!){ collection(id:$id){ productsCount{count} } }`,{id:col.id});
const n=c.collection.productsCount.count; console.log(' products in collection:', n);
if(n>=160) break;
}
console.log('STOREFRONT: https://'+STORE+'/collections/'+col.handle);
})();