From 96dfd467dff730b0eb620bbbd6cb9ab11f6fe471 Mon Sep 17 00:00:00 2001 From: MOHAN Date: Thu, 2 Jul 2026 23:59:35 +0530 Subject: [PATCH] backfill: clearer logs + token check endpoint --- server.js | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/server.js b/server.js index c8b5190..1668448 100755 --- a/server.js +++ b/server.js @@ -36,13 +36,13 @@ app.get('/free-access/:shop', (req, res) => { // ── BACKFILL: Re-run fulfillment service + locationId for shops that have null ─ // Hit: GET /admin/fix-location → runs all shops with null locationId // Hit: GET /admin/fix-location/:shop → runs one specific shop -async function runFixLocation(req, res) { +async function runFixLocation(req, res) { const stores = listTokens(); const targetShop = req.params.shop ? decodeURIComponent(req.params.shop).toLowerCase().trim() : null; const toFix = Object.entries(stores).filter(([shop, record]) => { if (targetShop) return shop === targetShop; - return !record.locationId; + return !record.locationId; }); if (toFix.length === 0) { @@ -56,22 +56,48 @@ async function runFixLocation(req, res) { continue; } try { - log(shop, `🔧 [BACKFILL] Re-running fulfillment setup for ${shop}`); + log(shop, `🔧 [BACKFILL] Starting fulfillment setup — token: ${record.accessToken?.slice(0,10)}...`); const { fulfillmentService, locationId } = await createFulfillmentService(shop, record.accessToken); + log(shop, `🔧 [BACKFILL] createFulfillmentService returned → fulfillmentService=${JSON.stringify(fulfillmentService?.id || null)}, locationId=${locationId}`); + + if (!locationId) { + log(shop, `❌ [BACKFILL] locationId is STILL null after createFulfillmentService — token is likely expired/revoked for this shop`); + results.push({ shop, status: 'failed', reason: 'locationId still null — token likely revoked, shop must reinstall', locationId: null }); + continue; + } + saveToken(shop, record.accessToken, record.scope, fulfillmentService, locationId); results.push({ shop, status: 'fixed', locationId, fulfillmentServiceId: fulfillmentService?.id || null }); - log(shop, `✅ [BACKFILL] locationId=${locationId}`); + log(shop, `✅ [BACKFILL] SUCCESS — locationId=${locationId}`); } catch (err) { results.push({ shop, status: 'error', error: err.message }); - log(shop, `❌ [BACKFILL] Error: ${err.message}`); + log(shop, `❌ [BACKFILL] Exception: ${err.message}`); } } res.json({ fixed: results.filter(r => r.status === 'fixed').length, total: toFix.length, results }); -} - -app.get('/admin/fix-location', runFixLocation); -app.get('/admin/fix-location/:shop', runFixLocation); +} + +app.get('/admin/fix-location', runFixLocation); +app.get('/admin/fix-location/:shop', runFixLocation); + +// Debug: test if a shop's stored token is still valid +app.get('/admin/check-token/:shop', async (req, res) => { + const shop = decodeURIComponent(req.params.shop).toLowerCase().trim(); + const record = getToken(shop); + if (!record) return res.json({ shop, status: 'not_found' }); + if (!record.accessToken) return res.json({ shop, status: 'no_token' }); + try { + const axios = require('axios'); + const resp = await axios.get(`https://${shop}/admin/api/2025-10/shop.json`, { + headers: { 'X-Shopify-Access-Token': record.accessToken }, + }); + res.json({ shop, status: 'token_valid', shopName: resp.data?.shop?.name, locationId: record.locationId }); + } catch (err) { + const statusCode = err.response?.status; + res.json({ shop, status: 'token_invalid', httpStatus: statusCode, error: err.response?.data || err.message, locationId: record.locationId }); + } +}); // ── PUBLIC CHAT ENDPOINTS (for customer widget) ────────────────────────────── // widget.js MUST be before /chat/:shop — otherwise Express treats "widget.js" as the :shop param