← back to Dw Silver Mylar Rename

lib.mjs

46 lines

// Shared lib: token load, GraphQL client, transform.
import { readFileSync } from 'node:fs';

const ENV = readFileSync(process.env.HOME + '/Projects/secrets-manager/.env', 'utf8');
function envVal(k) {
  const m = ENV.match(new RegExp('^' + k + '=(.*)$', 'm'));
  return m ? m[1].trim().replace(/^["']|["']$/g, '') : undefined;
}
// Prefer FULL access (write_products); fall back to admin token.
export const TOKEN = envVal('SHOPIFY_FULL_ACCESS_TOKEN') || envVal('SHOPIFY_ADMIN_TOKEN');
export const TOKEN_NAME = envVal('SHOPIFY_FULL_ACCESS_TOKEN') ? 'SHOPIFY_FULL_ACCESS_TOKEN' : 'SHOPIFY_ADMIN_TOKEN';
export const DOMAIN = 'designer-laboratory-sandbox.myshopify.com';
export const API = '2024-10';
const GQL = `https://${DOMAIN}/admin/api/${API}/graphql.json`;

if (!TOKEN) { console.error('NO SHOPIFY TOKEN FOUND'); process.exit(1); }

export async function gql(query, variables = {}) {
  for (let attempt = 0; attempt < 6; attempt++) {
    const res = await fetch(GQL, {
      method: 'POST',
      headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' },
      body: JSON.stringify({ query, variables }),
    });
    if (res.status === 429 || res.status >= 500) {
      await new Promise(r => setTimeout(r, 2000 * (attempt + 1)));
      continue;
    }
    const j = await res.json();
    if (j.errors) throw new Error('GQL errors: ' + JSON.stringify(j.errors));
    // throttle courtesy
    const cost = j.extensions?.cost?.throttleStatus;
    if (cost && cost.currentlyAvailable < 200) await new Promise(r => setTimeout(r, 800));
    return j.data;
  }
  throw new Error('GQL retries exhausted');
}

// SUBSTRING swap: case-insensitive match, normalized replacement, preserve surrounding text.
export const RE = /silver mylar/gi;
export function swap(s) {
  if (s == null) return s;
  return s.replace(RE, 'Silver Metallic');
}
export function has(s) { return s != null && /silver mylar/i.test(s); }