← back to Dw Scrape Scheduler
run-vendor.js
47 lines
#!/usr/bin/env node
// Scrape ONE vendor via its feed adapter -> snapshot to data/snapshots/.
// PROOF STAGE: snapshot + count only, NO canonical dw_unified write yet (per-vendor
// staging-table mapping is the next staged increment). Idempotent, $0 local.
const fs = require('fs');
const path = require('path');
const ADAPTERS = { shopify: require('./adapters/shopify'), woo: require('./adapters/woo') };
const { writeStaging } = require('./lib/write-staging');
const SNAP_DIR = path.join(__dirname, 'data', 'snapshots');
// Guard against a broken/partial feed wiping a catalog's freshness: if a scrape
// returns implausibly few products, snapshot it but SKIP the DB write.
const MIN_PLAUSIBLE = 3;
async function runVendor(entry, { db = true } = {}) {
const adapter = ADAPTERS[entry.adapter];
if (!adapter) return { vendor: entry.vendor, ok: false, skipped: true, reason: `adapter '${entry.adapter}' not yet implemented` };
const t0 = Date.now();
try {
const products = await adapter.scrape(entry.base_url);
fs.mkdirSync(SNAP_DIR, { recursive: true });
const stamp = new Date().toISOString().slice(0, 10).replace(/-/g, '');
const file = path.join(SNAP_DIR, `${entry.vendor_code}-${stamp}.json`);
fs.writeFileSync(file, JSON.stringify({ vendor_code: entry.vendor_code, scraped_at: new Date().toISOString(), count: products.length, products }, null, 0));
let staged = null;
if (db) {
if (products.length < MIN_PLAUSIBLE) staged = { skipped: `only ${products.length} products — DB write skipped (feed suspect)` };
else staged = await writeStaging(entry.vendor_code, products);
}
return { vendor: entry.vendor, ok: true, count: products.length, ms: Date.now() - t0, file, staged };
} catch (e) {
return { vendor: entry.vendor, ok: false, reason: e.message, ms: Date.now() - t0 };
}
}
module.exports = { runVendor };
// CLI: node run-vendor.js <vendor_code> (looks the entry up in the manifest)
if (require.main === module) {
const code = process.argv[2];
const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, 'data', 'manifest.json'), 'utf8'));
const entry = [...manifest.tier_a, ...manifest.parked_headless].find(e => e.vendor_code === code);
if (!entry) { console.error(`vendor_code '${code}' not in manifest tier_a/parked_headless`); process.exit(1); }
runVendor(entry).then(r => { console.log(JSON.stringify(r)); process.exit(r.ok ? 0 : 1); });
}