[object Object]

← back to CelebritySignatures

chore: lint, refactor, session-close fixes, v1.0.2 → v1.0.3 (TK-10286)

0770f004b6ca5f81e8309c118ff842eb27764f2d · 2026-08-10 16:14:59 -0700 · Steve Abrams

Session-close quality gate on the Printful POD wiring:
- FIX (critical, caught by lint): submit-pod-draft.mjs now appends a SUBMITTED marker after each successful Printful POST + filters it out on the DRAFT_UNSENT read — a rerun can no longer double-submit an already-sent order (proven: rerun sends nothing)
- FIX: /wear-checkout returns 400 on unknown size (was silently falling back to sizes[0] → wrong fulfillment)
- FIX: /wear-success no longer swallows errors silently (console.error) so a paid-but-draft-write-failed case is visible in the log
- refactor: envVal() consolidated to the for-of form (behavior-identical)
- node --check clean on all; dry-run still submits nothing

Files touched

Diff

commit 0770f004b6ca5f81e8309c118ff842eb27764f2d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Aug 10 16:14:59 2026 -0700

    chore: lint, refactor, session-close fixes, v1.0.2 → v1.0.3 (TK-10286)
    
    Session-close quality gate on the Printful POD wiring:
    - FIX (critical, caught by lint): submit-pod-draft.mjs now appends a SUBMITTED marker after each successful Printful POST + filters it out on the DRAFT_UNSENT read — a rerun can no longer double-submit an already-sent order (proven: rerun sends nothing)
    - FIX: /wear-checkout returns 400 on unknown size (was silently falling back to sizes[0] → wrong fulfillment)
    - FIX: /wear-success no longer swallows errors silently (console.error) so a paid-but-draft-write-failed case is visible in the log
    - refactor: envVal() consolidated to the for-of form (behavior-identical)
    - node --check clean on all; dry-run still submits nothing
---
 package.json                 |  2 +-
 scripts/submit-pod-draft.mjs | 16 +++++++++++-----
 server.js                    |  5 +++--
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/package.json b/package.json
index 522e898..2f140a8 100644
--- a/package.json
+++ b/package.json
@@ -1 +1 @@
-{"name":"celebrity-signatures","version":"1.0.2","type":"module","private":true}
\ No newline at end of file
+{"name":"celebrity-signatures","version":"1.0.3","type":"module","private":true}
\ No newline at end of file
diff --git a/scripts/submit-pod-draft.mjs b/scripts/submit-pod-draft.mjs
index d685277..e22faf6 100644
--- a/scripts/submit-pod-draft.mjs
+++ b/scripts/submit-pod-draft.mjs
@@ -13,7 +13,7 @@
 // Even when applied, orders are created with confirm=false — i.e. a DRAFT order in
 // the Printful dashboard, NOT auto-fulfilled and NOT auto-charged. A human confirms
 // each order in Printful. Provider: PRINTFUL (Steve's call 2026-08-10, TK-10286).
-import { readFile } from 'node:fs/promises';
+import { readFile, appendFile } from 'node:fs/promises';
 import { fileURLToPath } from 'node:url';
 import { join } from 'node:path';
 import { readFileSync } from 'node:fs';
@@ -25,9 +25,9 @@ const PRINTFUL_ORDERS_URL = 'https://api.printful.com/orders';
 
 function envVal(name) {
   if (process.env[name]) return process.env[name];
-  try { const m = readFileSync(join(ROOT, '.env'), 'utf8').match(new RegExp('^' + name + '=(.+)$', 'm')); if (m) return m[1].trim(); } catch {}
-  // also read the master secrets .env if present
-  try { const p = join(ROOT, '..', 'secrets-manager', '.env'); const m = readFileSync(p, 'utf8').match(new RegExp('^' + name + '=(.+)$', 'm')); if (m) return m[1].trim(); } catch {}
+  for (const p of [join(ROOT, '.env'), join(ROOT, '..', 'secrets-manager', '.env')]) {
+    try { const m = readFileSync(p, 'utf8').match(new RegExp('^' + name + '=(.+)$', 'm')); if (m) return m[1].trim(); } catch {}
+  }
   return null;
 }
 
@@ -73,7 +73,11 @@ function buildPayload(tpl, d) {
 async function main() {
   let lines = [];
   try { lines = (await readFile(join(DATA, 'pod-order-drafts.jsonl'), 'utf8')).trim().split('\n').filter(Boolean); } catch {}
-  const drafts = lines.map(l => JSON.parse(l)).filter(d => d.status === 'DRAFT_UNSENT');
+  const all = lines.map(l => JSON.parse(l));
+  // Orders already sent to Printful get a SUBMITTED marker line appended below.
+  // Exclude them so a rerun (network glitch, human re-run) NEVER double-submits.
+  const submitted = new Set(all.filter(d => d.status === 'SUBMITTED').map(d => d.orderId));
+  const drafts = all.filter(d => d.status === 'DRAFT_UNSENT' && !submitted.has(d.orderId));
   const tpl = await templates();
   console.log(`POD drafts pending: ${drafts.length} (provider: Printful)`);
 
@@ -96,6 +100,8 @@ async function main() {
     });
     const j = await resp.json().catch(() => ({}));
     if (!resp.ok) { console.error(`  PRINTFUL ERROR ${resp.status}: ${j.error?.message || j.result || 'unknown'}`); continue; }
+    // Mark this order SUBMITTED so a rerun skips it (append-only, matches the draft log).
+    await appendFile(join(DATA, 'pod-order-drafts.jsonl'), JSON.stringify({ orderId: d.orderId, status: 'SUBMITTED', printfulId: j.result?.id, submittedAt: new Date().toISOString() }) + '\n');
     console.log(`  ✓ Printful DRAFT order created: id=${j.result?.id} status=${j.result?.status} (confirm it in the Printful dashboard to fulfill).`);
   }
 
diff --git a/server.js b/server.js
index fefb588..297b175 100644
--- a/server.js
+++ b/server.js
@@ -802,7 +802,8 @@ ${paid ? `<div class="ok">✓</div><h1>Order confirmed</h1>
       const garment = (tpl.garments || []).find(g => g.id === String(b.garment || ''));
       if (!garment) return sendJSON(res, 400, { ok: false, error: 'unknown garment' });
       const color = (garment.colors || []).find(c => c.id === String(b.color || '')) || garment.colors[0];
-      const size = (garment.sizes || []).includes(String(b.size)) ? String(b.size) : garment.sizes[0];
+      if (!(garment.sizes || []).includes(String(b.size))) return sendJSON(res, 400, { ok: false, error: 'unknown size' });
+      const size = String(b.size);
       const amountCents = Math.round((garment.priceUsd || WEAR_GARMENT_DEFAULT_PRICE_USD) * 100);
       const u = await currentUser(req);
       const list = await load('wear-orders.json', []);
@@ -871,7 +872,7 @@ ${paid ? `<div class="ok">✓</div><h1>Order confirmed</h1>
               await store('wear-orders.json', list);
             }
           }
-        } catch {}
+        } catch (e) { console.error('wear-success', e.message); }
       }
       const body = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
 <title>${paid ? 'Order received' : 'Order'} — Celebrity Signatures</title><link rel="icon" href="/assets/favicon.png">

← 0fa8dbf wear/POD: wire Printful sender + go-live path (gated OFF) —  ·  back to CelebritySignatures  ·  CelebritySignatures mobile: early-game respects Difficulty + 93f7578 →