Skip to content

fix: support React Native (window without document)#223

Merged
roymiloh merged 1 commit into
mainfrom
fix/react-native-support
Jul 8, 2026
Merged

fix: support React Native (window without document)#223
roymiloh merged 1 commit into
mainfrom
fix/react-native-support

Conversation

@roymiloh

@roymiloh roymiloh commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Makes the SDK import, construct, and make requests on React Native. RN defines a limited window polyfill but has no document, localStorage, or window.location — so the SDK's typeof window === "undefined" guards (which only tell Node/SSR apart from browser) passed in RN and then touched globals that aren't there.

Analytics is disabled on React Native for now (returns a noop module); the rest of the SDK works.

Blockers fixed

  1. Import-time crashanalytics.ts builds its shared state eagerly at module load, and the factory calls getAnalyticsConfigFromUrlParams()window.location.search. Threw the moment the SDK was imported in RN. Now guarded with !window.location.
  2. Construction-time crashcreateAnalyticsModule runs trackInitializationEvent synchronously, reading document.referrer (optional chaining doesn't save an undeclared global → ReferenceError). The module now early-returns a noop { track, cleanup } on RN.
  3. Per-request crash — the axios request interceptor read window.location.href guarded only by typeof window. Now guarded with && window.location.

Design note

Gating is on a new isReactNative = !isNode && typeof document === "undefined" flag, not a plain "no document" check. The SDK's analytics runs headless in Node (queue + flush), and there are tests for it; gating on document alone would have disabled Node analytics too. isReactNative targets precisely the window-without-a-DOM case the existing guards miss.

Known limitation

getAnalyticsSessionId falls back to a fresh UUID per call on RN (no localStorage), so the anonymous-visitor id isn't stable across requests there. It's try/catch-guarded so it won't crash, and authenticated flows use the token instead. A stable id on RN would need an injectable AsyncStorage-style persistence layer — out of scope here.

Testing

  • New tests/unit/react-native.test.ts (3 tests) stubs a window-without-document env, re-imports the SDK, and asserts import + construction + analytics.track don't throw (fails without the fixes).
  • Full suite 167 passed; typecheck, type-tests, build, and lint all clean.

🤖 Generated with Claude Code

React Native defines `window` but not `document`, `localStorage`, or
`window.location`, so the SDK's `typeof window` guards (which only
distinguish Node/SSR from browser) passed and then touched globals that
don't exist. This fixes three React Native blockers:

- Import-time crash: the analytics shared-state factory runs eagerly at
  module load and called `getAnalyticsConfigFromUrlParams()`, which read
  `window.location.search`. Now guarded on `window.location`.
- Construction-time crash: `createAnalyticsModule` synchronously reads
  `document.referrer` on init. Analytics is now disabled on React Native
  (returns a noop `track`/`cleanup`) via a new `isReactNative` flag.
- Per-request crash: the axios interceptor read `window.location.href`
  guarded only by `typeof window`. Now guarded on `window.location`.

Node/SSR analytics behavior is unchanged: `isReactNative` targets only
the window-without-a-DOM case, so headless queue/flush still works.

Adds tests/unit/react-native.test.ts covering import, construction, and
noop analytics under a window-without-document environment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 8, 2026

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/sdk@0.8.36-pr.223.4029308

Prefer not to change any import paths? Install using npm alias so your code still imports @base44/sdk:

npm i "@base44/sdk@npm:@base44-preview/sdk@0.8.36-pr.223.4029308"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "@base44/sdk": "npm:@base44-preview/sdk@0.8.36-pr.223.4029308"
  }
}

Preview published to npm registry — try new features instantly!

@roymiloh roymiloh merged commit 1cc0bbf into main Jul 8, 2026
5 of 7 checks passed
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.

2 participants