[Personal-WP] Add Remote Access#3758
Open
akirk wants to merge 73 commits into
Open
Conversation
aa0319e to
07016be
Compare
927b078 to
cb50804
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Implements “Personal WP desktop access” via a signaling-only PHP relay plus a direct browser-to-browser WebRTC DataChannel tunnel, enabling desktop viewing/control of the phone-hosted Playground runtime.
Changes:
- Add a service-worker “desktop relay” request bridge for
/scope:default/*traffic. - Add phone (host) and desktop (guest) tunnel implementations using WebRTC DataChannels, including approval + backup download over the tunnel.
- Add a minimal PHP/MySQL relay for session rendezvous + signaling (with Apache rewrite routing).
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.base.json | Adds a TS path alias for importing the remote service worker entry. |
| packages/playground/remote/src/lib/desktop-relay.ts | Implements service-worker-side mapping, probing, and request forwarding to the desktop client. |
| packages/playground/remote/src/lib/desktop-relay.spec.ts | Adds unit tests for header/body serialization helpers used by the desktop relay. |
| packages/playground/remote/service-worker.ts | Wires desktop relay messaging + fetch interception into the remote service worker. |
| packages/playground/personal-wp/vite.config.ts | Configures worker bundling so the imported service worker builds to sw.js. |
| packages/playground/personal-wp/src/main.tsx | Routes /connect and ?share= viewer flows outside the normal app shell. |
| packages/playground/personal-wp/src/lib/desktop-access-tunnel-utils.ts | Adds shared helpers for attempt scoping, verification codes, filenames, and ICE candidate buffering. |
| packages/playground/personal-wp/src/lib/desktop-access-service.ts | Adds a thin app-facing service wrapper to start/stop/approve desktop access. |
| packages/playground/personal-wp/src/lib/desktop-access-direct-tunnel.ts | Implements WebRTC signaling + DataChannel HTTP tunneling and backup transfer (host + guest). |
| packages/playground/personal-wp/src/lib/desktop-access-direct-tunnel.spec.ts | Adds unit tests for desktop access helper utilities (attempt scoping, codes, filenames, ICE buffering). |
| packages/playground/personal-wp/src/components/site-manager/site-info-panel/style.module.css | Adds UI styles for desktop access controls + diagnostics within Site Tools. |
| packages/playground/personal-wp/src/components/site-manager/site-info-panel/index.tsx | Adds the “Use on desktop” section, start/stop/share/copy, and approval UI. |
| packages/playground/personal-wp/src/components/desktop-access-viewer/style.module.css | Adds desktop viewer layout styles, status/diagnostics UI, and overlays. |
| packages/playground/personal-wp/src/components/desktop-access-viewer/index.tsx | Implements the desktop viewer: SW registration, request bridging, WebRTC guest, and backup download. |
| packages/playground/personal-wp/src/components/desktop-access-connect/style.module.css | Adds styling for the /connect access-code entry page. |
| packages/playground/personal-wp/src/components/desktop-access-connect/index.tsx | Implements /connect access-code resolution and route detection helpers. |
| packages/playground/personal-wp/src/components/desktop-access-connect/index.spec.ts | Adds tests for /connect route + code normalization/formatting helpers. |
| packages/playground/personal-wp/public/relay.php | Adds the signaling-only PHP relay backed by normalized MySQL tables. |
| packages/playground/personal-wp/.htaccess | Routes /relay/* requests to relay.php. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
07a1cc4 to
9a8b364
Compare
adamziel
reviewed
Jun 12, 2026
adamziel
reviewed
Jun 12, 2026
adamziel
reviewed
Jun 12, 2026
adamziel
reviewed
Jun 12, 2026
Member
Author
|
Thanks, @adamziel! I fixed what your review revealed and was also finally able to find a workaround for Chrome renderer crashes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Demo
mywp-connect.mp4
What It Does
This is a more privacy friendly alternative to #3746. It keeps the same product goal: let someone open the Personal WP instance running on one device from another browser while the host device remains nearby and connected.
The main difference is transport. #3746 proxies WordPress HTTP requests and responses through the PHP relay. This PR uses the PHP relay only for rendezvous and WebRTC signaling, then sends WordPress HTTP traffic over a direct browser-to-browser WebRTC DataChannel.
Related PRs:
Important Implementation Notes
seqvalues are only used as polling cursors/order markers.SIGNAL_RETENTION_MS, not modulo slots or a retained sequence tail.Originhosts, returns generic messages for unexpected 500s, logs detailed server errors witherror_log, and binds millisecond timestamp values as strings for BIGINT-safe MySQL handling.@wp-playground/remote-access, so other packages can reuse them without publishing a public npm API.packages/playground/remote-access/relay.phpintowebsite-deployment/my-wordpress-net/before upload, and the deployment script copies it to the production site root.Shared Remote Access Package
This PR introduces the private workspace package
@wp-playground/remote-accessas the reusable boundary for the transport. It is private on purpose: the goal is to share Remote Access implementation code inside the monorepo without committing to a public npm API yet.The package owns the signaling relay source, WebRTC host/guest transport, host controller state, access-code helpers, URL routing helpers, and service-worker relay helpers. The product UI remains app-specific. Personal WP currently supplies the host controls,
/connectpage, viewer header, and deployment wiring; other packages can reuse the transport pieces and provide their own screens around them.The package README at
packages/playground/remote-access/README.mddocuments the pieces a consuming package needs to wire up: deployingrelay.php, startingRemoteAccessHostControllerfrom a running Playground client, resolving codes on/connect, registering the service worker in the viewer, mapping scoped iframe requests, and using the URL helpers for/connectand/scope:default/routing.User Flow
On the host device:
Remote Accesssection, start remote access./connectplus a six-digit access code.On the remote browser:
/connecton the same Personal WP deployment.42.Allow, or press Enter.Download backupin the remote viewer header to request and download a zip backup from the running host site over the WebRTC tunnel.While connected, the remote page renders the WordPress instance that is still running on the host device. The visible remote URL is normalized to
/connectwhile connecting, then cleaned up to paths like/connect/wp-admin/once the iframe navigates so the user can tell where they are without seeing the long session id. These are currently transient viewer URLs; reload is not expected to restore the session.Architecture
The PHP relay is only a rendezvous/signaling service. It creates short-lived sessions, resolves six-digit access codes, records host/guest heartbeats, and stores small WebRTC signaling messages while the browser peers connect.
It does not expose a
/relay/:session/request/*HTTP proxy in this branch.The request path is:
/scope:default/....playgroundClient.request(...).Responsefor the iframe.So WordPress request/response bodies are intended to stay out of PHP and MySQL in this approach.
Relay Storage
The relay uses three MySQL tables instead of a session-level JSON blob. There is no migration in this PR; the schema creates the Remote Access table names directly. The reusable relay PHP source and my.wordpress.net schema are checked in at:
playground_remote_access_sessionsStores session metadata and the host heartbeat. Session ids are UUIDs and access codes are stored in
123-456form.playground_remote_access_signalsStores ordered WebRTC/control messages addressed from one peer to the other.
signal_datais bounded asVARCHAR(8192)and relay PHP validates/canonicalizes the payload shape before insert:offer/answer:{ attemptId, payload: { type, sdp } }candidate:{ attemptId, payload: { candidate, sdpMid, sdpMLineIndex, usernameFragment? } }retry-request:{ guestId }seqis only the delivery cursor/order marker for polling. Cleanup is time-based: old signal rows are deleted afterSIGNAL_RETENTION_MSinstead of keeping a sequence-number tail.playground_remote_access_guestsStores remote viewer heartbeats.
For my.wordpress.net,
deploy-my-wordpress-net.ymlstagesrelay.phpinto the uploadedwebsite-deployment/my-wordpress-net/directory. Thenmy-wordpress-net/apply-update.shcopies it to the staged site root and applies this schema during deploy, alongside the existing event stats schema.Pairing and Approval
The six-digit access code is only the rendezvous step. It lets a remote browser find the current host session, but it is not enough to access WordPress.
After the WebRTC channel opens:
This is meant to protect against brute-forcing the six-digit rendezvous code. A guessed code can reach the approval gate, but the user still has to confirm the remote browser from the host device.
Remote Viewer Details
The remote viewer registers the Playground service worker at
/sw.jswith root scope and verifies that/scope:default/is controlled before loading the iframe.The iframe starts at
about:blankand is only navigated once the service worker and DataChannel are ready. This avoids accidentally booting a local Playground instance in the remote iframe.The viewer preserves the loaded iframe during reconnects. Reconnect state is shown in the header while the already-loaded page stays visible.
Privacy and Data Handling
This approach reduces what the relay sees. MySQL temporarily stores:
It should not store WordPress HTTP bodies, cookies, admin requests, HTML, CSS, JS, media, form submissions, or backup zip contents. The remote browser and host exchange those request/response payloads and remote-requested backup chunks directly over the WebRTC DataChannel.
Server Configuration
The relay reads DB configuration from these env/server variables, in order:
PLAYGROUND_RELAY_DB_HOST,DB_HOSTPLAYGROUND_RELAY_DB_USER,DB_USERPLAYGROUND_RELAY_DB_PASSWORD,DB_PASSWORDPLAYGROUND_RELAY_DB_NAME,DB_NAMEPLAYGROUND_RELAY_DB_PORT,DB_PORTPLAYGROUND_RELAY_PUBLIC_BASE_URLmay be set to force generated remote access share URLs. For my.wordpress.net, use:With that value, relay-created share URLs are
https://my.wordpress.net/?share=<session-id>.Caveats
This is a prototype.
The WebRTC peer connection uses public STUN servers, including Cloudflare and Google STUN. There is still no TURN server. That means direct connection setup should work on more networks than host-candidate-only WebRTC, but it can still fail when the peers need a relay. Adding TURN would improve reliability further, but TURN would relay encrypted WebRTC traffic and change the privacy tradeoff.
The host tab must stay open. The remote browser is a viewer/control surface for the running host Playground runtime.
The clean remote URL, such as
/connect/wp-admin/, is currently cosmetic/transient. Reloading it is not expected to restore the remote session.Installing apps via postMessage from the remote viewer is still reported as unsupported for now.
Validation
Ran during this branch:
php -l packages/playground/remote-access/relay.phpnpm exec nx test playground-remote-accessnpm exec nx lint playground-remote-accessnpm exec nx build playground-remote-accessnpm exec nx typecheck playground-personal-wpnpm exec nx typecheck playground-remotenpm exec nx lint playground-personal-wpgit diff --checkI did not run the full build or deployment scripts.