Skip to content

fix(storage): write strings raw so current_tenant does not double-encode - #237

Open
sonegillis1 wants to merge 1 commit into
mainfrom
chore/bump-agent-ai-2.9.0
Open

fix(storage): write strings raw so current_tenant does not double-encode#237
sonegillis1 wants to merge 1 commit into
mainfrom
chore/bump-agent-ai-2.9.0

Conversation

@sonegillis1

Copy link
Copy Markdown
Contributor

The bug

LocalStorageService was asymmetric — getItem read raw, setItem JSON-stringified:

async getItem<T>(key: string)          { return window.localStorage.getItem(key) as T; }
async setItem<T>(key: string, item: T) { window.localStorage.setItem(key, JSON.stringify(item)); }

So every string written through the SDK came back double-encoded.

That fed an infinite refresh loop in the SDK's syncCookiesToLocalStorage. From a console capture of a mentor embed on a different tenant — 120 iterations in 112 seconds:

cookieCurrentTenant  {"key":"gillis",...}          ← JSON string
localCurrentTenant   "{\"key\":\"gillis\",...}"    ← JSON string of a JSON string
Cookie sync detected changes from another SPA, refreshing page

Identical values, reported as different, forever:

  1. the tenant keys genuinely differ, so the sync writes the cookie value to storage
  2. setItem stringifies that string → stored double-encoded
  3. next poll, one JSON.parse yields the JSON string, not an object, so .key is undefined
  4. "gillis" !== undefined → "changed" → write → refresh → back to 2, forever

It also fired 118 interval redirecting to auth spa attempts, stopped only by the login-timestamp guard.

The fix

Strings are written as-is, so they round-trip through getItem. Non-strings are still serialised, so object callers are unaffected.

This matches how the other SPAs implement the same interface (mentorai, apps/auth both write raw).

Verified

  • tsc --noEmit clean
  • full suite 3032 passed / 10 skipped
  • new case asserting a JSON string round-trips (setItemgetItemJSON.parse gives the object back); the existing non-string case still asserts stringification

Related

iblai/iblai-web-frontend#2059 hardens the SDK's comparison so no host adapter can spin this loop again, and fixes a second issue in the same capture where a tenant switch offered to the host was never taken.

🤖 Generated with Claude Code

getItem reads raw but setItem JSON-stringified, so every string written through the SDK came back double-encoded. The SDK's cookie sync then parsed current_tenant to a string rather than an object, read key as undefined, treated every poll as a cross-SPA change, wrote it back and refreshed the page — 120 times in under two minutes when a mentor embed was on a different tenant.

Strings are now written as-is; non-strings are still serialised so object callers are unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant