← back to Dw Signup Fulfillment
verification/tk10836/verify-app-inventory.js
43 lines
#!/usr/bin/env node
// TK-11366 HUNT: what changed around 2026-08-18? Enumerate installed apps + their timestamps and
// access scopes, looking for anything shipping/delivery/checkout-related installed or updated in
// the window. READ-ONLY.
const fs=require('fs'),os=require('os');
for (const line of fs.readFileSync(os.homedir()+'/Projects/secrets-manager/.env','utf8').split('\n')) {
const m=line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)$/); if(!m) continue;
let v=m[2].trim().replace(/^['"]|['"]$/g,''); if(!process.env[m[1]]) process.env[m[1]]=v;
}
const STORE=process.env.SHOPIFY_STORE_DOMAIN, TOKEN=process.env.SHOPIFY_FULL_ACCESS_TOKEN, API='2024-10';
async function gql(q,v={}){const r=await fetch(`https://${STORE}/admin/api/${API}/graphql.json`,{method:'POST',
headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});
const j=await r.json(); if(j.errors)console.error('ERR:',JSON.stringify(j.errors).slice(0,500)); return j.data;}
(async()=>{
const d=await gql(`query{ currentAppInstallation{ id app{ title } } }`);
console.log('current app:', JSON.stringify(d?.currentAppInstallation?.app||null));
// Full app installation inventory
let c=null, apps=[];
do{
const r=await gql(`query($c:String){ appInstallations(first:50, after:$c){
pageInfo{hasNextPage endCursor}
nodes{ id
app{ title handle developerName embedded webhookApiVersion }
accessScopes{ handle }
launchUrl } } }`,{c});
if(!r?.appInstallations){ console.log('appInstallations unavailable to this token'); break; }
apps.push(...r.appInstallations.nodes);
c=r.appInstallations.pageInfo.hasNextPage?r.appInstallations.pageInfo.endCursor:null;
}while(c);
console.log(`\n### ${apps.length} app installation(s) visible ###`);
const SHIP=/ship|deliver|checkout|rate|cart|carrier|post|freight/i;
for(const a of apps){
const scopes=(a.accessScopes||[]).map(s=>s.handle);
const shipScopes=scopes.filter(s=>SHIP.test(s));
const flag = SHIP.test(a.app?.title||'') || SHIP.test(a.app?.handle||'') || shipScopes.length;
console.log(`${flag?'>>> ':' '}${a.app?.title} [${a.app?.handle}] by ${a.app?.developerName||'?'}`);
if(shipScopes.length) console.log(` shipping/checkout scopes: ${shipScopes.join(', ')}`);
}
console.log('\n(">>>" = app whose name/handle or scopes touch shipping/delivery/checkout/rates)');
})();