← back to Tk10630 Sku Suffix Canary

shopify.mjs

54 lines

// Read-only Shopify Admin GraphQL helper (shared by query + canary).
import { readFileSync } from 'node:fs';

function loadEnv() {
  const txt = readFileSync(`${process.env.HOME}/Projects/secrets-manager/.env`, 'utf8');
  const env = {};
  for (const line of txt.split('\n')) {
    const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
    if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
  }
  return env;
}

const env = loadEnv();
export const STORE = env.SHOPIFY_STORE_DOMAIN;
// Token selection: default SHOPIFY_ADMIN_TOKEN; override via SHOPIFY_TOKEN_VAR
// (e.g. SHOPIFY_TOKEN_VAR=SHOPIFY_FULL_ACCESS_TOKEN for the write_inventory variant phase).
const TOKEN_VAR = process.env.SHOPIFY_TOKEN_VAR || 'SHOPIFY_ADMIN_TOKEN';
const TOKEN = env[TOKEN_VAR];
export const TOKEN_NAME = TOKEN_VAR;
const API = '2024-10';

export async function gql(query, variables = {}) {
  const res = await fetch(`https://${STORE}/admin/api/${API}/graphql.json`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Shopify-Access-Token': TOKEN,
    },
    body: JSON.stringify({ query, variables }),
  });
  const json = await res.json();
  if (json.errors) throw new Error('GraphQL errors: ' + JSON.stringify(json.errors));
  const throttle = json.extensions?.cost?.throttleStatus;
  return { data: json.data, throttle };
}

export async function getProductByHandle(handle) {
  const q = `query($h:String!){
    productByHandle(handle:$h){
      id title handle status vendor productType
      variants(first:50){
        nodes{
          id title sku price
          selectedOptions{ name value }
          inventoryItem{ id sku }
        }
      }
    }
  }`;
  const { data } = await gql(q, { h: handle });
  return data.productByHandle;
}