[object Object]

← back to Koroseal Goodrich Audit

TK-10347: TAK-ED01-04 cropped cream weave applied live (Steve ruling=crop); ticket complete

367765775b0b774e9c0bcecfbc7965e74321c2b1 · 2026-08-08 07:56:40 -0700 · Steve Abrams

Files touched

Diff

commit 367765775b0b774e9c0bcecfbc7965e74321c2b1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Aug 8 07:56:40 2026 -0700

    TK-10347: TAK-ED01-04 cropped cream weave applied live (Steve ruling=crop); ticket complete
---
 tk10347/TAKUMI_TAK-ED01-04_CREAM_cropped.jpg | Bin 0 -> 336229 bytes
 tk10347/apply_ed0104.mjs                     |  50 +++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/tk10347/TAKUMI_TAK-ED01-04_CREAM_cropped.jpg b/tk10347/TAKUMI_TAK-ED01-04_CREAM_cropped.jpg
new file mode 100644
index 0000000..ec12a86
Binary files /dev/null and b/tk10347/TAKUMI_TAK-ED01-04_CREAM_cropped.jpg differ
diff --git a/tk10347/apply_ed0104.mjs b/tk10347/apply_ed0104.mjs
new file mode 100644
index 0000000..61a557e
--- /dev/null
+++ b/tk10347/apply_ed0104.mjs
@@ -0,0 +1,50 @@
+#!/usr/bin/env node
+// TK-10347 — TAK-ED01-04: upload cropped cream weave (Steve ruled crop), feature, remove wrong ED01-01.
+import fs from 'node:fs';
+const ENV = fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env','utf8');
+const TOKEN = (ENV.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]?.trim().replace(/^["']|["']$/g,'');
+const STORE='designer-laboratory-sandbox.myshopify.com', API='2024-10';
+const URL=`https://${STORE}/admin/api/${API}/graphql.json`;
+const PID='gid://shopify/Product/7519950602291';
+const WRONG='gid://shopify/MediaImage/24773828804659';
+const FILE='/tmp/korpg/verify/TAKUMI_TAK-ED01-04_CREAM_cropped.jpg';
+const FNAME='TAKUMI_TAK-ED01-04_CREAM_cropped.jpg';
+const APPLY=process.argv.includes('--apply');
+const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function gql(query,variables){
+  const r=await fetch(URL,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query,variables})});
+  const j=await r.json(); if(j.errors) throw new Error(JSON.stringify(j.errors)); return j.data;
+}
+async function run(){
+  const bytes=fs.statSync(FILE).size;
+  console.log('APPLY',APPLY,'file',bytes,'bytes');
+  if(!APPLY){ console.log('DRY: staged upload + createMedia + reorder0 + delete',WRONG); return; }
+  // 1. staged upload target
+  const su=await gql(`mutation($input:[StagedUploadInput!]!){ stagedUploadsCreate(input:$input){ stagedTargets{ url resourceUrl parameters{ name value } } userErrors{ message } } }`,
+    {input:[{filename:FNAME, mimeType:'image/jpeg', resource:'IMAGE', httpMethod:'POST', fileSize:String(bytes)}]});
+  if(su.stagedUploadsCreate.userErrors.length) throw new Error('staged: '+JSON.stringify(su.stagedUploadsCreate.userErrors));
+  const t=su.stagedUploadsCreate.stagedTargets[0];
+  // 2. POST file to staged target
+  const fd=new FormData();
+  for(const p of t.parameters) fd.append(p.name,p.value);
+  fd.append('file', new Blob([fs.readFileSync(FILE)],{type:'image/jpeg'}), FNAME);
+  const up=await fetch(t.url,{method:'POST',body:fd});
+  if(!(up.status>=200&&up.status<300)) throw new Error('upload status '+up.status+' '+(await up.text()).slice(0,200));
+  console.log('uploaded to staged target', up.status, 'resourceUrl', t.resourceUrl);
+  // 3. create media from resourceUrl
+  const cm=await gql(`mutation($pid:ID!,$m:[CreateMediaInput!]!){ productCreateMedia(productId:$pid,media:$m){ media{ ... on MediaImage{ id status } } mediaUserErrors{ message } } }`,
+    {pid:PID, m:[{originalSource:t.resourceUrl, mediaContentType:'IMAGE', alt:'Dapper Paper Weave Cream TAK-ED01-04'}]});
+  if(cm.productCreateMedia.mediaUserErrors.length) throw new Error('createMedia: '+JSON.stringify(cm.productCreateMedia.mediaUserErrors));
+  const newId=cm.productCreateMedia.media[0].id; console.log('created',newId);
+  for(let i=0;i<30;i++){ const p=await gql(`query($id:ID!){ node(id:$id){ ... on MediaImage{ status image{ url } } } }`,{id:newId});
+    if(p.node.status==='READY'){ console.log('READY',(p.node.image?.url||'').slice(-70)); break; }
+    if(p.node.status==='FAILED') throw new Error('media FAILED'); await sleep(2000); }
+  // 4. feature + delete wrong
+  await gql(`mutation($id:ID!,$moves:[MoveInput!]!){ productReorderMedia(id:$id,moves:$moves){ mediaUserErrors{ message } } }`,{id:PID,moves:[{id:newId,newPosition:'0'}]});
+  console.log('reordered ->0'); await sleep(2500);
+  const dd=await gql(`mutation($pid:ID!,$ids:[ID!]!){ productDeleteMedia(productId:$pid,mediaIds:$ids){ deletedMediaIds mediaUserErrors{ message } } }`,{pid:PID,ids:[WRONG]});
+  console.log('deleted wrong', dd.productDeleteMedia.deletedMediaIds);
+  const fm=await gql(`query($id:ID!){ product(id:$id){ featuredMedia{ ... on MediaImage{ image{ url } } } media(first:5){ edges{ node{ id } } } } }`,{id:PID});
+  console.log('NOW featured', fm.product.featuredMedia.image.url, '| imgs', fm.product.media.edges.length);
+}
+run().catch(e=>{console.error('ERROR',e.message);process.exit(1);});

← 09a9d53 TK-10347: applied 6 approved Koroseal cross-link image swaps  ·  back to Koroseal Goodrich Audit  ·  TK-10369: Koroseal fleet cross-link scan candidates (22 file 6dc5b68 →