Skip to content
This repository was archived by the owner on Oct 11, 2026. It is now read-only.

feat(web): add Switchify Remote browser app - #185

Merged
enaboapps merged 20 commits into
mainfrom
codex/web-app
Oct 9, 2026
Merged

enaboapps merged 20 commits into
mainfrom
codex/web-app

Conversation

@enaboapps

Copy link
Copy Markdown
Contributor

Closes #184

Summary

  • Add Web Bluetooth transport behind the existing platform boundary, including serialized GATT operations, bounded discovery and notification/read-v1 responses.
  • Add encrypted browser pairing storage and web accessibility, focus, diagnostics export and Bluetooth guidance.
  • Preserve native application paths and protocol v1.

Stack and merge blockers

This is the base of the web stack: this PR, then #181, then #183. Do not ship this base alone. #181 fixes live Enter and stalled discovery; #183 fixes real-PC connection handoff.

Validation

  • npm run validate on this exact head
  • Android development build
  • iOS development build
  • Automated coverage uses fake Bluetooth devices, not real input
  • Latest combined stack at 90c14c7 passed lint, TypeScript and 654 tests; Expo Doctor failed existing SDK patch mismatches. This is stack evidence, not an exact-head pass for this PR.
  • User confirmed real-PC pairing and pointer control on the combined stack including fix(web): serialize service discovery before pairing #183. Base alone failed before pairing.
  • Independent review of this entire base PR remains required. Follow-up PR reviews do not cover the entire base implementation.

No merge or release authorized by this PR creation.

OwenMcGirr and others added 13 commits October 7, 2026 21:52
- Add WebBluetoothTransport behind the existing BleTransport interface, chosen by a
  platform factory so the web bundle never loads react-native-ble-plx
- Serialize GATT operations, cap frames at 182 bytes (Web Bluetooth hides the MTU and
  macOS rejects long writes), support notify and read-v1 replies, and reuse devices
  the browser remembers for saved PCs
- Treat a closed device picker as a cancelled selection that returns to idle
- Store pairing secrets on web with a non-extractable AES-GCM key in IndexedDB
- Route alerts, screen-reader announcements and focus moves to the DOM on web, where
  React Native Web leaves them as no-ops
- Download diagnostics on web and use browser-specific Bluetooth guidance

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace the stuck "Searching…" state with "Choose another PC" once the browser
  picker has returned a PC, since Web Bluetooth discovery does not keep scanning
- Add docs/web.md covering supported browsers, how each platform layer differs,
  the fixed 182-byte write size and the hardware checks still needed
- Link the web app from the README and protocol compatibility notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Wait briefly for an in-flight write when cancelling instead of poisoning writes,
  so disconnect cleanup (drag end, modifier up) still reaches the PC
- Give the GATT queue a generation so a stuck operation cannot block later
  connections, and track which attempt owns each device connection so stale or
  abandoned probes close late connections without closing newer ones
- Bound remembered-device checks to 3 seconds so the picker still opens inside the
  browser's tap window, and fail discovery when a chosen device reports an invalid status
- Let web secret storage surface key-load failures instead of treating them as
  missing secrets, resolve first-key races between tabs, and treat only failed
  authentication as an absent value
- Create the live region at startup and name the action in confirm dialogs
- Cover the web transport, secret storage, platform shims, diagnostics export and
  reduced transparency with fake-device and jsdom tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… before use

- Track connection ownership with a token per connect attempt, so a remembered-
  device check that times out cannot close the connection later opened to the same PC
- Treat a picker the browser refuses to open (SecurityError after the tap window)
  like a closed picker, returning to idle so the next tap can try again
- Use a newly created web encryption key only after its IndexedDB transaction
  commits, so values are never encrypted with a key that was not saved

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Report SecurityError from requestDevice as BluetoothPickerBlockedError instead of a
  silent cancellation, since browsers also raise it when Bluetooth is blocked for the site
- Show and announce a failure that asks the person to try again and allow Bluetooth
  for the site, keeping the silent return to idle only for a closed picker
- Cover discovery and connection paths in ConnectionManager tests and update docs/web.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- On the web, React Navigation leaves inactive tab scenes in the page behind the
  focused one and only hides them from screen readers, so Tab reached their buttons
- Wrap tab scenes with a web-only screenLayout that removes unfocused scenes from
  layout while keeping them mounted; native tabs are unchanged
- Test the focus and blur handling and document it in docs/web.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace the effect that set focus state with a focus/blur subscription, fixing the react-hooks/set-state-in-effect lint error from the previous commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- NotFoundError and SecurityError are now interpreted only when the browser's device
  picker raises them; the same names from later GATT steps, such as a missing service
  after the PC restarts, are reported as connection failures instead of a closed picker
- Test that a missing service after choosing a PC is not treated as a cancellation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chore(deps): update Expo SDK 57 patches
fix(web): resolve web stack review findings
…-182

fix(web): serialize service discovery before pairing
fix(web): submit live Enter and isolate stalled probes
@enaboapps
enaboapps marked this pull request as ready for review October 9, 2026 07:50
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[High impact] No reported findings remain blocking, but this base must not ship alone; the stated stack dependencies and required validation still apply, and no merge or release is authorized.

Summary

Adds the browser app through platform-specific Bluetooth, encrypted storage, accessibility, and diagnostics paths while keeping the native paths.

Since the last review:

  • People can find and connect to a PC from a supported browser.
  • Saved PC pairings stay encrypted in the browser.
  • Browser controls expose their state, focus, and announcements correctly.
  • Live typing submits on Enter in the browser.

Both previous findings are addressed in the current code. No new actionable issues are reported. Exact-head tests and physical Bluetooth checks were not run during this review.

enaboapps acknowledges that this base must not ship alone: #181 and #183 address live Enter, stalled discovery, and real-PC connection handoff. The PR description does not authorize merge or release.

Reviews (2) · Last reviewed commit: "fix(web): lock saved-PC changes across t..." · Reviewed by Greptile

Comment thread src/storage/PairingStore.ts Outdated
Comment thread src/transport/WebBluetoothTransport.ts
- Run PairingStore's read-modify-write of the saved-PC index inside a cross-tab Web
  Lock on the web, so two tabs saving different PCs no longer drop one of them;
  native keeps its single-instance queue through a pass-through lock
- Forget a desktop's cached Web Bluetooth device when opening it fails, so a PC whose
  address changed is looked up again or chosen through the picker on the next attempt
- Cover both with regression tests and describe them in docs/web.md

Addresses the two P1 Greptile findings on #185.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps
enaboapps merged commit a8e2d8c into main Oct 9, 2026
4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Switchify Remote web app with Web Bluetooth

2 participants