← back to Dw Signup Fulfillment

scripts/production-validation.js

59 lines

'use strict';

const crypto = require('crypto');
const config = require('../lib/config');

// Free-sample entitlement is granted by the Regios tag-gated discount (see DEPLOY.md
// "Option C: verify -> tag -> Regios"): every live sample grant is titled "Free sample".
// The "DW Free Samples" Shopify Function nodes (fn 01a0475d-d202-743e-bdc8-7a659f6ff512)
// were RETIRED alternates and were archived 2026-09-10 (TK-11361) after proving, against
// 40 real orders, that they granted nothing (their titles never appeared on any order).
// So this gate no longer asserts a DW Function discount node exists. The "no re-armed DW
// node" invariant is now owned by the dw-free-samples-fn-guard canary.
const CALLBACK = 'https://signup.designerwallcoverings.com/webhooks/orders-paid';

function check(condition, message) { if (!condition) throw new Error(message); }
async function graphql(query, variables = {}) {
  const r = await fetch(`https://${config.SHOP_DOMAIN}/admin/api/2026-07/graphql.json`, {
    method: 'POST', headers: { 'content-type': 'application/json', 'x-shopify-access-token': config.SHOPIFY_FULFILLMENT_TOKEN },
    body: JSON.stringify({ query, variables }),
  });
  const j = await r.json();
  check(r.ok && !j.errors, `admin_graphql_${r.status}`);
  return j.data;
}

async function run(pass) {
  const health = await fetch('https://signup.designerwallcoverings.com/healthz');
  const healthBody = await health.json();
  check(health.status === 200 && healthBody.ok && healthBody.dry_run === false, 'service_not_live');

  const body = JSON.stringify({ id: 987654321, customer: null, line_items: [] });
  const bad = await fetch(CALLBACK, { method: 'POST', headers: { 'content-type': 'application/json', 'x-shopify-hmac-sha256': 'bad' }, body });
  check(bad.status === 401, `bad_hmac_${bad.status}`);
  const sig = crypto.createHmac('sha256', config.SHOPIFY_SIGNUP_APP_CLIENT_SECRET).update(body).digest('base64');
  const good = await fetch(CALLBACK, { method: 'POST', headers: { 'content-type': 'application/json', 'x-shopify-hmac-sha256': sig }, body });
  const goodBody = await good.json();
  check(good.status === 200 && goodBody.status === 'ignored', `signed_webhook_${good.status}`);

  const data = await graphql(`query Validation($customer: ID!) {
    webhookSubscriptions(first: 20, topics: [ORDERS_PAID]) { nodes { topic uri } }
    customer(id: $customer) { createdAt tags metafield(namespace: "custom", key: "free_samples_used") { value } }
  }`, { customer: 'gid://shopify/Customer/740096475248' });
  const webhook = data.webhookSubscriptions.nodes.find(x => x.uri === CALLBACK);
  check(webhook?.topic === 'ORDERS_PAID', 'paid_webhook_missing');
  check(data.customer?.createdAt?.startsWith('2018-'), 'old_account_fixture_changed');
  check(!data.customer.tags.includes('trade_approved'), 'temporary_trade_tag_not_restored');

  const home = await fetch(`https://www.designerwallcoverings.com/?validation_pass=${pass}`, { headers: { 'user-agent': 'DW production validation/1.0' } });
  const html = await home.text();
  check(home.ok && html.includes('DW-SAMPLES-BANNER v1'), `storefront_banner_${home.status}`);
  check(html.includes('Existing customer? Sign in. New here? Create an account.'), 'existing_account_copy_missing');
  check(html.includes('Approved design professionals receive unlimited samples.'), 'designer_copy_missing');

  return { pass, health: true, webhookHmac: true, ledgerEndpoint: true, oldAccount2018: true, legacyTradeNotApproved: true, storefrontUx: true };
}

const pass = Number(process.argv[2] || 1);
run(pass).then(result => console.log(JSON.stringify(result))).catch(error => { console.error(`PASS ${pass} FAILED: ${error.message}`); process.exit(1); });