[object Object]

← back to Fineartamerica Price Sync

auto-save: 2026-07-16T09:12:20 (3 files) — bin/faa-fetch-all.js bin/faa-fill-gaps.js data/

cc498838881ebdefa7ab321ba0b7e588b4160f43 · 2026-07-16 09:12:23 -0700 · Steve Abrams

Files touched

Diff

commit cc498838881ebdefa7ab321ba0b7e588b4160f43
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 16 09:12:23 2026 -0700

    auto-save: 2026-07-16T09:12:20 (3 files) — bin/faa-fetch-all.js bin/faa-fill-gaps.js data/
---
 bin/faa-fetch-all.js | 45 +++++++++++++++++++++++++++++++++++++++++++++
 bin/faa-fill-gaps.js | 44 ++++++++++++++++++++++++++++++++++++++++++++
 data/seed-urls.txt   | 11 +++++++++++
 3 files changed, 100 insertions(+)

diff --git a/bin/faa-fetch-all.js b/bin/faa-fetch-all.js
new file mode 100644
index 0000000..5a7f04c
--- /dev/null
+++ b/bin/faa-fetch-all.js
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// Fetch FAA costs for EVERY FAA-signature product on the store (free HTTP).
+// Framed cost is artwork-independent (verified: same size/frame/mat/finish =>
+// same price across artworks), so we price each distinct config SIGNATURE once
+// and map it onto every variant's configKey — ~36 fetches instead of ~468.
+
+const { openSession, priceFramedConfig } = require('../lib/faa-http');
+const { parseSku, configKey } = require('../lib/parse-sku');
+const { loadCache, saveCache } = require('../lib/faa-cost');
+const { listFaaProducts } = require('../lib/shopify');
+
+// Per-artwork page URL — size ladders are artwork-aspect-specific, so each
+// artwork needs its own configurator session (verified: seeding all off one
+// artwork drops the odd-aspect sizes like 24x30/32x40).
+const artUrl = id => `https://fineartamerica.com/art/${id}`;
+
+(async () => {
+  const ps = await listFaaProducts();
+  const byArtwork = new Map();     // artworkid -> distinct cfgs (deduped)
+  let total = 0;
+  for (const p of ps) for (const v of p.variants) {
+    const c = parseSku(v.sku); if (!c) continue;
+    total++;
+    const a = c.artworkid || 'NONE';
+    if (!byArtwork.has(a)) byArtwork.set(a, new Map());
+    byArtwork.get(a).set(configKey(c), c);
+  }
+  console.log(`${ps.length} FAA products, ${total} variants across ${byArtwork.size} artworks`);
+
+  const cache = loadCache();
+  let priced = 0, failed = 0;
+  for (const [artworkId, cfgs] of byArtwork) {
+    const s = await openSession(artUrl(artworkId));
+    let a = 0, f = 0;
+    for (const c of cfgs.values()) {
+      if (c.productid !== 'printframed') { f++; continue; }
+      const cost = await priceFramedConfig(s, c);
+      if (cost != null) { cache[configKey(c)] = cost; a++; } else f++;
+    }
+    priced += a; failed += f;
+    console.log(`  artwork ${artworkId}: ${a} priced, ${f} failed`);
+    saveCache(cache); // checkpoint after each artwork
+  }
+  console.log(`\npriced ${priced} variants (${failed} failed) across ${byArtwork.size} artworks. ($0 — free HTTP)`);
+})().catch(e => { console.error(e); process.exit(1); });
diff --git a/bin/faa-fill-gaps.js b/bin/faa-fill-gaps.js
new file mode 100644
index 0000000..7a33d33
--- /dev/null
+++ b/bin/faa-fill-gaps.js
@@ -0,0 +1,44 @@
+#!/usr/bin/env node
+// Fill any still-uncached FAA configs by seeding sessions from a set of
+// varied-aspect artwork pages. Framed cost is artwork-independent, so whichever
+// seed artwork natively offers a given size returns that size's (correct) cost.
+// Odd-aspect sizes (24x30, 32x40, 26x48…) aren't in the 7x8 ladder, so we need
+// landscape/other-aspect seeds to reach them.
+
+const fs = require('fs');
+const { openSession, priceFramedConfig } = require('../lib/faa-http');
+const { parseSku, configKey, configLabel } = require('../lib/parse-sku');
+const { loadCache, saveCache } = require('../lib/faa-cost');
+const { listFaaProducts } = require('../lib/shopify');
+
+const SEEDS = [
+  'https://fineartamerica.com/featured/3-george-washington-steve-abrams.html',
+  ...fs.readFileSync(__dirname + '/../data/seed-urls.txt', 'utf8').trim().split('\n').filter(Boolean),
+];
+
+(async () => {
+  const ps = await listFaaProducts();
+  const cache = loadCache();
+  // distinct missing configs
+  const missing = new Map();
+  for (const p of ps) for (const v of p.variants) {
+    const c = parseSku(v.sku); if (!c) continue;
+    if (cache[configKey(c)] == null) missing.set(configKey(c), c);
+  }
+  console.log(`${missing.size} distinct configs still missing; sweeping ${SEEDS.length} seed artworks`);
+
+  for (const url of SEEDS) {
+    if (missing.size === 0) break;
+    let s; try { s = await openSession(url); } catch { console.log('  seed fail', url); continue; }
+    if (!s.sessionId) { console.log('  no session from', url.split('/').pop()); continue; }
+    let got = 0;
+    for (const [k, c] of [...missing]) {
+      const cost = await priceFramedConfig(s, c);
+      if (cost != null) { cache[configKey(c)] = cost; missing.delete(k); got++; }
+    }
+    console.log(`  ${url.split('/').pop().replace('.html','')}: filled ${got}, ${missing.size} left`);
+    saveCache(cache);
+  }
+  console.log(`\ndone. ${missing.size} configs still unpriced.`);
+  if (missing.size) for (const c of missing.values()) console.log('  UNPRICED', configLabel(c));
+})().catch(e => { console.error(e); process.exit(1); });
diff --git a/data/seed-urls.txt b/data/seed-urls.txt
new file mode 100644
index 0000000..7b32714
--- /dev/null
+++ b/data/seed-urls.txt
@@ -0,0 +1,11 @@
+https://fineartamerica.com/featured/american-gothic-grant-wood.html
+https://fineartamerica.com/featured/cafe-terrace-at-night-vincent-van-gogh.html
+https://fineartamerica.com/featured/dancers-in-blue-edgar-degas.html
+https://fineartamerica.com/featured/girl-with-a-pearl-earing-johannes-vermeer.html
+https://fineartamerica.com/featured/indiana-hoosiers-2026-national-champions-gannett-usa.html
+https://fineartamerica.com/featured/indiana-university-2026-college-football-playoffs-national-championship-commemorative-issue-cover-sports-illustrated.html
+https://fineartamerica.com/featured/irises-vincent-van-gogh.html
+https://fineartamerica.com/featured/mona-lisa-leonardo-da-vinci.html
+https://fineartamerica.com/featured/nighthawks-edward-hopper.html
+https://fineartamerica.com/featured/the-birth-of-venus-sandro-botticelli.html
+https://fineartamerica.com/featured/the-kiss-gustav-klimt.html

← 54dfec4 Free HTTP FAA cost fetcher (stateful configurator) — pilot:  ·  back to Fineartamerica Price Sync  ·  Harden apply (retry/continue); purge invalid $0 costs; all 4 802216f →