Finding (from the #1189 RN/Metro async review of PR #1346)
TowerClient.subscribeEvents consumes the SSE stream via res.body.getReader() (packages/sdk/src/tower-client.ts, ~line 815). All six client subpaths Metro-bundle cleanly (verified empirically against the PR branch tarball in an Expo SDK 57 app), so this is NOT a bundle-time problem. It is a runtime one: React Native's built-in fetch does not implement streaming response bodies, so on RN res.body is undefined and subscribeEvents breaks at call time.
Why the current design almost solves it already
The injected-transport seam (fetchFn?: typeof fetch) is exactly right. expo/fetch (Expo SDK 52+) advertises WinterCG-compliant streaming responses, so mobile likely just injects it: new TowerClient({ fetchFn: expoFetch }). This needs one empirical verification (planned for the RN feed spike) before it is relied on.
Asks
subscribeEvents should fail with a descriptive capability error when res.body is missing ("this environment's fetch does not support streaming; inject a streaming-capable fetchFn"), not an undefined-property throw.
- Document the RN profile in the module header alongside the existing per-environment auth profiles (browser / Node / VS Code): RN = inject a streaming-capable fetch.
- Related, same seam family:
getAuthKey?: () => string | null is sync-only, while RN secure storage (Keychain / Keystore via expo-secure-store) is async-only. Mobile can preload the key into memory before constructing the client, but accepting string | null | Promise<string | null> would remove the workaround. Low priority; noting here to keep the adapter-seam review in one place.
Verification record
Empirical probe (2026-08-05): sdk tarball built from builder/pir-1189, installed into a fresh Expo SDK 57 scaffold; expo export --platform ios bundles tower-client, sse, constants, escape-buffer, reconnect-policy, workspace cleanly; @cluesmith/codev-sdk/node fails loudly at bundle time on node:fs exactly as the quarantine intends.
Finding (from the #1189 RN/Metro async review of PR #1346)
TowerClient.subscribeEventsconsumes the SSE stream viares.body.getReader()(packages/sdk/src/tower-client.ts, ~line 815). All six client subpaths Metro-bundle cleanly (verified empirically against the PR branch tarball in an Expo SDK 57 app), so this is NOT a bundle-time problem. It is a runtime one: React Native's built-infetchdoes not implement streaming response bodies, so on RNres.bodyis undefined andsubscribeEventsbreaks at call time.Why the current design almost solves it already
The injected-transport seam (
fetchFn?: typeof fetch) is exactly right.expo/fetch(Expo SDK 52+) advertises WinterCG-compliant streaming responses, so mobile likely just injects it:new TowerClient({ fetchFn: expoFetch }). This needs one empirical verification (planned for the RN feed spike) before it is relied on.Asks
subscribeEventsshould fail with a descriptive capability error whenres.bodyis missing ("this environment's fetch does not support streaming; inject a streaming-capable fetchFn"), not an undefined-property throw.getAuthKey?: () => string | nullis sync-only, while RN secure storage (Keychain / Keystore via expo-secure-store) is async-only. Mobile can preload the key into memory before constructing the client, but acceptingstring | null | Promise<string | null>would remove the workaround. Low priority; noting here to keep the adapter-seam review in one place.Verification record
Empirical probe (2026-08-05): sdk tarball built from
builder/pir-1189, installed into a fresh Expo SDK 57 scaffold;expo export --platform iosbundlestower-client,sse,constants,escape-buffer,reconnect-policy,workspacecleanly;@cluesmith/codev-sdk/nodefails loudly at bundle time onnode:fsexactly as the quarantine intends.