← back to Designerwallcoverings
lib/shopify: probe SHOPIFY_FULL_ACCESS_TOKEN once, fall back to SHOPIFY_ADMIN_TOKEN on a definitive 401
cb3710a78531b36d0b153de9cc980445b35706e1 · 2026-09-24 16:02:08 -0700 · Steve Abrams
The preferred token (…2ea5) is dead, which broke all 88 importers. Only a 401 triggers
the fallback; network errors and other statuses keep the preferred token.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SrEDNvrmHyv2QgB23Lm151
Files touched
M scripts/lib/shopify.mjs
Diff
commit cb3710a78531b36d0b153de9cc980445b35706e1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 24 16:02:08 2026 -0700
lib/shopify: probe SHOPIFY_FULL_ACCESS_TOKEN once, fall back to SHOPIFY_ADMIN_TOKEN on a definitive 401
The preferred token (…2ea5) is dead, which broke all 88 importers. Only a 401 triggers
the fallback; network errors and other statuses keep the preferred token.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SrEDNvrmHyv2QgB23Lm151
---
scripts/lib/shopify.mjs | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/scripts/lib/shopify.mjs b/scripts/lib/shopify.mjs
index 15f1908..dddad4e 100644
--- a/scripts/lib/shopify.mjs
+++ b/scripts/lib/shopify.mjs
@@ -24,9 +24,20 @@ const _env = fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env'
// Prefer the full-scope token (write_inventory + all others); fall back to the narrow custom-app token.
// TK-11055: onboarders that call inventoryItemUpdate need write_inventory scope, which the narrow
// SHOPIFY_ADMIN_TOKEN (…7d19, 4 scopes) lacks. SHOPIFY_FULL_ACCESS_TOKEN has 139 scopes.
-export const TOKEN = (
- _env.match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m) || _env.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m) || []
-)[1]?.trim();
+// A dead preferred token (…2ea5 went 401 in Sep 2026) used to break every importer, so probe it
+// once: on a definitive 401 fall back to SHOPIFY_ADMIN_TOKEN (now the 139-scope "Full Access" app).
+// A network error or any other status keeps the preferred token so a blip can't silently swap it.
+const _full = _env.match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m)?.[1]?.trim();
+const _admin = _env.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)?.[1]?.trim();
+async function _pickToken() {
+ if (!_full || !_admin) return _full || _admin;
+ try {
+ const r = await fetch(`https://${SHOP}/admin/api/${VER}/shop.json`, { headers: { 'X-Shopify-Access-Token': _full }, signal: AbortSignal.timeout(10000) });
+ if (r.status === 401) { console.error(`[lib/shopify] SHOPIFY_FULL_ACCESS_TOKEN (…${_full.slice(-4)}) returned 401 — using SHOPIFY_ADMIN_TOKEN (…${_admin.slice(-4)})`); return _admin; }
+ } catch { /* keep the preferred token */ }
+ return _full;
+}
+export const TOKEN = await _pickToken();
if (!TOKEN) { console.error('no SHOPIFY_FULL_ACCESS_TOKEN or SHOPIFY_ADMIN_TOKEN in ~/Projects/secrets-manager/.env'); process.exit(1); }
export const ENDPOINT = `https://${SHOP}/admin/api/${VER}`;
← 398290e night-pdp-verify: unknown expected price -> NOT-MEASURED, ke
·
back to Designerwallcoverings
·
auto-data-snapshot: 2026-09-24T17:57:06 (1 data files) — dat 7e676fe →