← back to Philipperomano
scripts/sample-add-rollback.mjs
121 lines
/**
* PhilRomano Sample-Add ROLLBACK Script
* TK-10869 — reverses sample-add.mjs via restore-map
*
* Usage:
* node sample-add-rollback.mjs --restore <restore-map.json>
* DRY_RUN=true node sample-add-rollback.mjs
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const SHOP = 'designer-laboratory-sandbox.myshopify.com';
const TOKEN = process.env.SHOPIFY_ADMIN_TOKEN || (() => {
const envPath = '/Users/macstudio3/Projects/secrets-manager/.env';
if (fs.existsSync(envPath)) {
const lines = fs.readFileSync(envPath, 'utf8').split('\n');
for (const l of lines) {
const m = l.match(/^SHOPIFY_ADMIN_TOKEN=(.+)/);
if (m) return m[1].trim();
}
}
throw new Error('SHOPIFY_ADMIN_TOKEN not found');
})();
const DRY_RUN = process.env.DRY_RUN === 'true';
// Find restore map path from args
const args = process.argv.slice(2);
const restoreIdx = args.indexOf('--restore');
const RESTORE_MAP_PATH = restoreIdx >= 0
? args[restoreIdx + 1]
: path.join(__dirname, '../data/sample-add-restore-map.json');
async function shopifyPut(path, body) {
const url = `https://${SHOP}/admin/api/2024-10/${path}`;
const resp = await fetch(url, {
method: 'PUT',
headers: {
'X-Shopify-Access-Token': TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
if (!resp.ok) {
const text = await resp.text();
throw new Error(`PUT ${path} → ${resp.status}: ${text.slice(0, 200)}`);
}
return resp.json();
}
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
async function main() {
console.log('=== PhilRomano Sample-Add ROLLBACK TK-10869 ===');
console.log(`DRY_RUN: ${DRY_RUN}`);
console.log(`Restore map: ${RESTORE_MAP_PATH}`);
if (!fs.existsSync(RESTORE_MAP_PATH)) {
console.error('ERROR: Restore map not found:', RESTORE_MAP_PATH);
process.exit(1);
}
const restoreMap = JSON.parse(fs.readFileSync(RESTORE_MAP_PATH, 'utf8'));
const entries = Object.values(restoreMap);
console.log(`\nRestoring ${entries.length} products...\n`);
let ok = 0, err = 0;
for (const entry of entries) {
const numId = entry.productId;
if (DRY_RUN) {
console.log(`DRY ${numId} — ${entry.productTitle?.slice(0, 50)}`);
ok++;
continue;
}
try {
// Restore original options and variants
const restoreBody = {
product: {
id: numId,
options: entry.originalOptions.map(o => ({
name: o.name,
values: o.values
})),
variants: entry.originalVariants.map(v => ({
id: v.id,
option1: v.option1,
option2: v.option2,
price: v.price,
sku: v.sku,
inventory_management: v.inventory_management,
inventory_policy: v.inventory_policy
}))
}
};
await shopifyPut(`products/${numId}.json`, restoreBody);
console.log(`OK ${numId} — ${entry.productTitle?.slice(0, 50)}`);
ok++;
await sleep(400);
} catch (e) {
console.error(`ERR ${numId}: ${e.message}`);
err++;
await sleep(1000);
}
}
console.log(`\nRollback complete: OK=${ok} ERR=${err}`);
}
main().catch(e => {
console.error('FATAL:', e);
process.exit(1);
});