← back to Designer Wallcoverings

mailers/upload-hero-to-shopify.js

39 lines

// Upload the generated Hollywood room-setting hero to Shopify Files → prints the CDN URL.
// Run:  node upload-hero-to-shopify.js
// Reads SHOPIFY_ADMIN_TOKEN + SHOPIFY_STORE_DOMAIN from the secrets-manager .env.
const fs = require('fs');
const env = Object.fromEntries(
  fs.readFileSync('/Users/macstudio3/Projects/secrets-manager/.env', 'utf8')
    .split('\n').filter(l => l.includes('=')).map(l => { const i = l.indexOf('='); return [l.slice(0, i).trim(), l.slice(i + 1).trim()]; })
);
const STORE = env.SHOPIFY_STORE_DOMAIN || 'designer-laboratory-sandbox.myshopify.com';
const TOKEN = env.SHOPIFY_ADMIN_TOKEN;
const API = `https://${STORE}/admin/api/2024-10/graphql.json`;
const file = __dirname + '/hollywood-room-hero.jpg';
const bytes = fs.statSync(file).size;
const gql = (q, v) => fetch(API, { method: 'POST', headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' }, body: JSON.stringify({ query: q, variables: v }) }).then(r => r.json());
(async () => {
  const s = await gql(`mutation($i:[StagedUploadInput!]!){stagedUploadsCreate(input:$i){stagedTargets{url resourceUrl parameters{name value}} userErrors{message}}}`,
    { i: [{ resource: 'FILE', filename: 'hollywood-room-hero.jpg', mimeType: 'image/jpeg', httpMethod: 'POST', fileSize: String(bytes) }] });
  const t = s.data?.stagedUploadsCreate?.stagedTargets?.[0];
  if (!t) { console.log('staged err', JSON.stringify(s)); process.exit(1); }
  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' }), 'hollywood-room-hero.jpg');
  const up = await fetch(t.url, { method: 'POST', body: fd });
  if (up.status >= 400) { console.log('upload POST failed', up.status, (await up.text()).slice(0, 300)); process.exit(1); }
  const c = await gql(`mutation($f:[FileCreateInput!]!){fileCreate(files:$f){files{... on MediaImage{id image{url} fileStatus}} userErrors{message}}}`,
    { f: [{ originalSource: t.resourceUrl, contentType: 'IMAGE', alt: 'Hollywood Wallcoverings Artisma Croco room setting' }] });
  const id = c.data?.fileCreate?.files?.[0]?.id;
  if (!id) { console.log('fileCreate err', JSON.stringify(c)); process.exit(1); }
  console.log('fileCreate ok id', id);
  for (let i = 0; i < 14; i++) {
    await new Promise(r => setTimeout(r, 2500));
    const q = await gql(`query($id:ID!){node(id:$id){... on MediaImage{fileStatus image{url}}}}`, { id });
    const n = q.data?.node;
    if (n?.image?.url) { console.log('\n=== READY — paste this URL back to Claude ===\n' + n.image.url + '\n'); process.exit(0); }
    process.stdout.write(`.${n?.fileStatus || '?'}`);
  }
  console.log('\nstill processing — re-run query later for id', id);
})();