feat: auto-inject chat widget on all storefronts via Shopify ScriptTag API
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
a27d586c82
commit
9b5e16b1c1
25
auth.js
25
auth.js
@ -38,7 +38,30 @@ router.get('/auth/callback', async (req, res) => {
|
|||||||
saveToken(shop, access_token, scope);
|
saveToken(shop, access_token, scope);
|
||||||
log(shop, '💾 Token saved to data/tokens.json');
|
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);
|
const { fulfillmentService, locationId } = await createFulfillmentService(shop, access_token);
|
||||||
console.log(`Custom Location created: ${locationId}`);
|
console.log(`Custom Location created: ${locationId}`);
|
||||||
saveToken(shop, access_token, scope, fulfillmentService, locationId);
|
saveToken(shop, access_token, scope, fulfillmentService, locationId);
|
||||||
|
|||||||
23
server.js
23
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
|
// Health check
|
||||||
app.get('/health', (req, res) => {
|
app.get('/health', (req, res) => {
|
||||||
res.json({ ok: true, uptime: process.uptime(), timestamp: new Date().toISOString() });
|
res.json({ ok: true, uptime: process.uptime(), timestamp: new Date().toISOString() });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user