From 9b5e16b1c1985268b683adeda58f9fdd4476c6e1 Mon Sep 17 00:00:00 2001 From: MOHAN Date: Fri, 12 Jun 2026 20:52:18 +0530 Subject: [PATCH] feat: auto-inject chat widget on all storefronts via Shopify ScriptTag API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - auth.js: register chat widget ScriptTag during OAuth callback so every new install automatically gets the floating chat button — no manual theme editing required - server.js: GET /chat/backfill-scripttags endpoint to register the widget on all already-installed shops in one hit Co-Authored-By: Claude Sonnet 4.6 --- auth.js | 25 ++++++++++++++++++++++++- server.js | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/auth.js b/auth.js index 21cea43..b9a05d5 100755 --- a/auth.js +++ b/auth.js @@ -38,7 +38,30 @@ router.get('/auth/callback', async (req, res) => { saveToken(shop, access_token, scope); log(shop, '💾 Token saved to data/tokens.json'); - // 2) Create fulfillment service (existing step) + // 2) Register chat widget ScriptTag so it auto-injects on every storefront page + try { + const WIDGET_SRC = `https://backend.data4autos.com/chat/widget.js?shop=${encodeURIComponent(shop)}`; + // Check if already registered to avoid duplicates + const existingResp = await axios.get( + `https://${shop}/admin/api/2025-10/script_tags.json?src=${encodeURIComponent(WIDGET_SRC)}`, + { headers: { 'X-Shopify-Access-Token': access_token, 'Content-Type': 'application/json' } } + ); + const already = existingResp.data?.script_tags?.length > 0; + if (!already) { + await axios.post( + `https://${shop}/admin/api/2025-10/script_tags.json`, + { script_tag: { event: 'onload', src: WIDGET_SRC } }, + { headers: { 'X-Shopify-Access-Token': access_token, 'Content-Type': 'application/json' } } + ); + log(shop, '💬 Chat widget ScriptTag registered on storefront'); + } else { + log(shop, '💬 Chat widget ScriptTag already registered, skipping'); + } + } catch (stErr) { + log(shop, `⚠️ ScriptTag registration failed (non-fatal): ${stErr.message}`); + } + + // 3) Create fulfillment service (existing step) const { fulfillmentService, locationId } = await createFulfillmentService(shop, access_token); console.log(`Custom Location created: ${locationId}`); saveToken(shop, access_token, scope, fulfillmentService, locationId); diff --git a/server.js b/server.js index 90917b3..edfbebc 100755 --- a/server.js +++ b/server.js @@ -108,6 +108,29 @@ app.get('/chat/widget.js', (req, res) => { })();`); }); +// One-time backfill: register chat widget ScriptTag on all already-installed shops +// Hit: GET /chat/backfill-scripttags (admin use only — no sensitive data exposed) +app.get('/chat/backfill-scripttags', async (req, res) => { + const { getToken, listTokens } = require('./tokenStore'); + const axios = require('axios'); + const stores = listTokens(); + const results = []; + for (const [shop, record] of Object.entries(stores)) { + if (!record.accessToken) { results.push({ shop, status: 'no-token' }); continue; } + const WIDGET_SRC = `https://backend.data4autos.com/chat/widget.js?shop=${encodeURIComponent(shop)}`; + const headers = { 'X-Shopify-Access-Token': record.accessToken, 'Content-Type': 'application/json' }; + try { + const ex = await axios.get(`https://${shop}/admin/api/2025-10/script_tags.json?src=${encodeURIComponent(WIDGET_SRC)}`, { headers }); + if (ex.data?.script_tags?.length > 0) { results.push({ shop, status: 'already-exists' }); continue; } + await axios.post(`https://${shop}/admin/api/2025-10/script_tags.json`, { script_tag: { event: 'onload', src: WIDGET_SRC } }, { headers }); + results.push({ shop, status: 'registered' }); + } catch (e) { + results.push({ shop, status: 'error', error: e.response?.data || e.message }); + } + } + res.json({ results }); +}); + // Health check app.get('/health', (req, res) => { res.json({ ok: true, uptime: process.uptime(), timestamp: new Date().toISOString() });