[object Object]

← back to Marketing Command Center

channels: three-valued is_valid guard so a Graph rate-limit/error can't false-flip a valid Meta token to needsReconnect

f872cf0bc78c77c363447667133696dfc858ccc3 · 2026-07-14 13:12:23 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit f872cf0bc78c77c363447667133696dfc858ccc3
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 14 13:12:23 2026 -0700

    channels: three-valued is_valid guard so a Graph rate-limit/error can't false-flip a valid Meta token to needsReconnect
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 modules/channels/index.js | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/modules/channels/index.js b/modules/channels/index.js
index c69a918..03fd2bf 100644
--- a/modules/channels/index.js
+++ b/modules/channels/index.js
@@ -293,12 +293,21 @@ async function metaTokenHealth() {
   try {
     const r = await fetch(`${GRAPH}/debug_token?input_token=${encodeURIComponent(token)}&access_token=${encodeURIComponent(appId + '|' + secret)}`);
     const j = await r.json().catch(() => ({}));
-    const d = j.data || {};
+    // Graph signals rate-limits / app-token problems as a TOP-LEVEL {error} (no
+    // throw, no data.is_valid) — that means we COULDN'T verify, not that the user
+    // token is bad. Treat is_valid as three-valued: only a definitive boolean
+    // false flips a token; a missing/indeterminate verdict → ok:null (unknown),
+    // leaving the presence-based status untouched (fail-safe).
+    if (j.error || !j.data || typeof j.data.is_valid !== 'boolean') {
+      const v = { present: true, ok: null, reason: j.error?.message || 'validity indeterminate — Graph returned no verdict' };
+      _metaHealth = { token, at: now, v }; return v;
+    }
+    const d = j.data;
     const v = {
       present: true,
-      ok: d.is_valid === true,
+      ok: d.is_valid,
       expiresAt: d.expires_at ? d.expires_at * 1000 : null,
-      reason: d.error?.message || (d.is_valid === false ? 'token invalid/expired' : null),
+      reason: d.is_valid ? null : (d.error?.message || 'token invalid/expired'),
     };
     _metaHealth = { token, at: now, v }; return v;
   } catch (e) {                       // network failure → unknown, keep prior belief

← c60d8ff Expand Sounds catalog: +6 royalty-free libraries & SFX, live  ·  back to Marketing Command Center  ·  chore: lint fixes (jget r.ok guard, .env value quoting per u df1e623 →