← back to Hollywood Wallcoverings
CustomCreator: drop dead wallco.ai origin, serve local cache / wallpapersback
b36fd93c25f184a05f84a6efaa9b68b1ac271a16 · 2026-06-30 16:48:57 -0700 · Steve Abrams
Files touched
Diff
commit b36fd93c25f184a05f84a6efaa9b68b1ac271a16
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 30 16:48:57 2026 -0700
CustomCreator: drop dead wallco.ai origin, serve local cache / wallpapersback
---
customcreator.js | 44 +++++++++++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 17 deletions(-)
diff --git a/customcreator.js b/customcreator.js
index 0dc8fe9..19d583e 100644
--- a/customcreator.js
+++ b/customcreator.js
@@ -2,16 +2,20 @@
/**
* Hollywood Wallcoverings — Custom Creator (made-to-measure murals), mounted at /CustomCreator.
*
- * CONTENT = wallco.ai original AI designs ONLY. The eligible set is the wallco.ai snapshot filtered
- * to is_published && !user_removed — which is exactly "published + seam/settlement-clean", because
- * wallco.ai only flips is_published after the settlement gate (settlement_verdict='OK') and seam
- * checks pass. (NOT the general Rebel Walls Shopify murals — those were deliberately dropped.)
+ * CONTENT = the original AI design library (the published, seam/settlement-clean snapshot — filtered
+ * to is_published && !user_removed, which is exactly "published + settlement_verdict='OK' + seam-pass"
+ * since the design store only flips is_published after the settlement gate and seam checks pass).
+ * (NOT the general Rebel Walls Shopify murals — those were deliberately dropped.)
* hollywoodwallcoverings.com is the sole home of this content.
*
* Design images are PROXIED through this origin (/CustomCreator/img/<file>) so the customer never
- * sees a wallco.ai URL. Each design is sold as a made-to-measure mural at a flat $83.38/m²,
+ * sees the upstream image host. Each design is sold as a made-to-measure mural at a flat $83.38/m²,
* recomputed SERVER-SIDE from clamped dims so the browser can never set the price.
*
+ * Image origin: served local-cache-first; the remote fallback is wallpapersback.com — the LIVE
+ * AI-design storefront, which serves the identical /designs/img/<file>.png paths (verified
+ * byte-identical 2026-06-30). The retired wallco.ai host (HTTP 410 Gone) is no longer referenced.
+ *
* Checkout uses the SHOPIFY_DRAFT_TOKEN already present on the Hollywood prod process env
* (write_draft_orders) — no new secrets, no nginx change.
*/
@@ -19,14 +23,18 @@ const fs = require('fs');
const path = require('path');
const CC_DIR = path.join(__dirname, 'customcreator');
-const WALLCO_ORIGIN = 'https://wallco.ai';
+// Remote image origin for the design library. Local cache is always tried first (CACHE_DIR);
+// this is only the write-through fallback for a cold-cache id. wallco.ai is RETIRED (HTTP 410) —
+// the live AI-design storefront wallpapersback.com serves the identical /designs/img/<file> paths.
+// Override via env only if the design host ever moves again.
+const IMG_ORIGIN = (process.env.CC_IMG_ORIGIN || 'https://wallpapersback.com').replace(/\/+$/, '');
const STORE = (process.env.SHOPIFY_STORE || 'designer-laboratory-sandbox.myshopify.com').replace(/^https?:\/\//, '');
const EP = 'https://' + STORE + '/admin/api/2024-10/graphql.json';
const DRAFT_TOKEN = process.env.SHOPIFY_DRAFT_TOKEN || process.env.SHOPIFY_ADMIN_TOKEN;
const RATE_SQM = 83.38, SAMPLE = 4.25, CM_PER_IN = 2.54;
const MIN_CM = 50, MAX_CM = 1200;
-const HOUSE = 'Made to Measure'; // customer-facing vendor label (never "wallco.ai")
+const HOUSE = 'Made to Measure'; // customer-facing vendor label (never the upstream host)
const GALLERY_LIMIT = 120; // page size for the browse grid (catalog is ~12k, paginated)
function ftIn(inch) { let f = Math.floor(inch / 12), i = Math.round(inch - f * 12); if (i === 12) { f++; i = 0; } return `${f}′ ${i}″`; }
@@ -35,14 +43,14 @@ const ID_RE = /^\d+$/;
const CACHE_DIR = path.join(CC_DIR, 'designs-img'); // local write-through cache (Kamatera); not in git/rsync
try { fs.mkdirSync(CACHE_DIR, { recursive: true }); } catch (e) {}
-// Eligible wallco.ai designs (prebuilt: is_published && !user_removed, newest-first).
+// Eligible designs (prebuilt: is_published && !user_removed, newest-first).
let DESIGNS = [], BY_KEY = new Map(), SRC = new Map();
try {
DESIGNS = JSON.parse(fs.readFileSync(path.join(CC_DIR, 'wallco-designs.json'), 'utf8'));
for (const d of DESIGNS) { BY_KEY.set(String(d.handle).toLowerCase(), d); BY_KEY.set(String(d.id), d); SRC.set(String(d.id), d.src); }
-} catch (e) { console.log('[CustomCreator] wallco-designs load:', e.message); }
+} catch (e) { console.log('[CustomCreator] designs load:', e.message); }
-const imgUrl = id => '/CustomCreator/img/' + id; // id-keyed; the route caches locally + falls back to wallco.ai
+const imgUrl = id => '/CustomCreator/img/' + id; // id-keyed; the route serves local cache, else fetches IMG_ORIGIN
// Category facets (sorted by count) for the browse dropdown.
const CATS = (() => {
@@ -120,7 +128,7 @@ async function makeDraft(body) {
line = { title: `${pattern} — Custom Mural ${wDim} × ${hDim}`, originalUnitPrice: price.toFixed(2), quantity: 1, requiresShipping: true, taxable: true,
customAttributes: [{ key: 'Design', value: sku }, { key: 'Width', value: wDim }, { key: 'Height', value: hDim }, { key: 'Area', value: `${(area * 10.7639).toFixed(1)} sq ft` }, { key: 'Rate', value: `$${RATE_SQM}/m²` }] };
}
- const j = await gql(CREATE, { i: { lineItems: [line], tags: ['custom-mural', 'hollywood-custom-creator', 'wallco-design'] } }, DRAFT_TOKEN);
+ const j = await gql(CREATE, { i: { lineItems: [line], tags: ['custom-mural', 'hollywood-custom-creator', 'original-design'] } }, DRAFT_TOKEN);
const ue = j.data && j.data.draftOrderCreate && j.data.draftOrderCreate.userErrors;
if (ue && ue.length) return { error: ue.map(e => e.message).join('; ') };
if (j.errors) return { error: (j.errors[0] && j.errors[0].message) || 'graphql error', scopeHint: /access denied|write_draft_orders/i.test(JSON.stringify(j.errors)) };
@@ -135,9 +143,11 @@ function mount(app, express) {
app.use('/CustomCreator/rooms', express.static(path.join(CC_DIR, 'rooms'), { maxAge: '1d' }));
// Image route — id-keyed write-through cache. Serves the locally cached file if present;
- // otherwise fetches the design's CORRECT wallco source (ts-file OR /by-id/), streams it to the
- // client, and writes it into the local cache. Once the cache is fully warmed, wallco.ai can be
- // retired with zero image breakage. No wallco.ai URL is ever exposed to the customer.
+ // otherwise fetches the design's source path from IMG_ORIGIN (wallpapersback.com — the live
+ // AI-design storefront, which serves the identical /designs/img/<file> paths), streams it to the
+ // client, and writes it into the local cache. Once the cache is fully warmed the remote is never
+ // hit. The retired wallco.ai host is no longer referenced; the upstream host is never exposed to
+ // the customer. If the remote fetch fails, fail gracefully — no dead-origin retry.
app.get('/CustomCreator/img/:id', async (req, res) => {
const id = req.params.id;
if (!ID_RE.test(id)) return res.status(400).type('text/plain').send('bad request');
@@ -146,8 +156,8 @@ function mount(app, express) {
const src = SRC.get(id);
if (!src) return res.status(404).type('text/plain').send('not found');
try {
- const r = await fetch(`${WALLCO_ORIGIN}${src}`);
- if (!r.ok) return res.status(r.status).type('text/plain').send('not found');
+ const r = await fetch(`${IMG_ORIGIN}${src}`);
+ if (!r.ok) return res.status(r.status === 410 ? 404 : r.status).type('text/plain').send('not found');
const buf = Buffer.from(await r.arrayBuffer());
res.set('Content-Type', r.headers.get('content-type') || 'image/png');
res.set('Cache-Control', 'public, max-age=604800');
@@ -198,7 +208,7 @@ function mount(app, express) {
.catch(e => res.status(500).json({ error: e.message }));
});
- console.log(`[CustomCreator] mounted at /CustomCreator (wallco.ai designs: ${DESIGNS.length} eligible · draft:${DRAFT_TOKEN ? 'ok' : 'MISSING'})`);
+ console.log(`[CustomCreator] mounted at /CustomCreator (designs: ${DESIGNS.length} eligible · img-origin:${IMG_ORIGIN} · draft:${DRAFT_TOKEN ? 'ok' : 'MISSING'})`);
}
module.exports = { mount };
← a36d0d1 add Hollywood Wallcoverings Constant Contact campaign draft
·
back to Hollywood Wallcoverings
·
corner-nav: move login to its own hamburger in upper-left (p d4954e6 →