← 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); });