Skip to content

[Personal-WP] Add Remote Access#3758

Open
akirk wants to merge 73 commits into
WordPress:trunkfrom
akirk:personal-wp-desktop-webrtc-trunk
Open

[Personal-WP] Add Remote Access#3758
akirk wants to merge 73 commits into
WordPress:trunkfrom
akirk:personal-wp-desktop-webrtc-trunk

Conversation

@akirk

@akirk akirk commented Jun 6, 2026

Copy link
Copy Markdown
Member

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

  • The relay is signaling-only. WordPress HTTP request/response bodies go over the WebRTC DataChannel, not through PHP/MySQL.
  • Relay storage is normalized across sessions, signals, and guest heartbeats. There is no session-level JSON payload blob.
  • Signal seq values are only used as polling cursors/order markers.
  • Signal cleanup is time-based via SIGNAL_RETENTION_MS, not modulo slots or a retained sequence tail.
  • The relay only emits CORS access for same-origin Origin hosts, returns generic messages for unexpected 500s, logs detailed server errors with error_log, and binds millisecond timestamp values as strings for BIGINT-safe MySQL handling.
  • Shared WebRTC transport code, host controller state, connect-code helpers, URL routing helpers, service-worker relay helpers, and the PHP relay source live in the private workspace package @wp-playground/remote-access, so other packages can reuse them without publishing a public npm API.
  • The my.wordpress.net deploy workflow stages packages/playground/remote-access/relay.php into website-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-access as 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, /connect page, 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.md documents the pieces a consuming package needs to wire up: deploying relay.php, starting RemoteAccessHostController from 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 /connect and /scope:default/ routing.

User Flow

On the host device:

  1. Open Personal WP.
  2. Open Site Tools.
  3. In the Remote Access section, start remote access.
  4. The host device shows /connect plus a six-digit access code.
  5. Keep the host tab open while using the remote browser.

On the remote browser:

  1. Open /connect on the same Personal WP deployment.
  2. Enter the six-digit code from the host device.
  3. The remote browser opens the viewer and establishes a direct WebRTC DataChannel with the host device.
  4. The remote browser shows a two-digit verification code, for example 42.
  5. The host device shows an approval prompt. Enter the remote verification code and tap Allow, or press Enter.
  6. The remote iframe loads WordPress through the host runtime.
  7. Use Download backup in 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 /connect while 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:

  1. Remote iframe requests /scope:default/....
  2. The Playground service worker sees the scoped request.
  3. The service worker posts a serialized request to the remote viewer page.
  4. The remote viewer sends that request over a WebRTC DataChannel.
  5. The host receives it and calls playgroundClient.request(...).
  6. The host serializes the response and sends it back over the DataChannel.
  7. The remote service worker builds a Response for 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:

packages/playground/remote-access/relay.php
packages/playground/website-deployment/my-wordpress-net/mywp-remote-access-tables.sql

playground_remote_access_sessions

Stores session metadata and the host heartbeat. Session ids are UUIDs and access codes are stored in 123-456 form.

playground_remote_access_signals

Stores ordered WebRTC/control messages addressed from one peer to the other. signal_data is bounded as VARCHAR(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 }

seq is only the delivery cursor/order marker for polling. Cleanup is time-based: old signal rows are deleted after SIGNAL_RETENTION_MS instead of keeping a sequence-number tail.

playground_remote_access_guests

Stores remote viewer heartbeats.

For my.wordpress.net, deploy-my-wordpress-net.yml stages relay.php into the uploaded website-deployment/my-wordpress-net/ directory. Then my-wordpress-net/apply-update.sh copies 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:

  • the remote browser generates and displays a two-digit verification code;
  • the remote browser sends that code to the host over the DataChannel;
  • the host requires the user to enter that exact code before approving;
  • the host rejects WordPress requests until approval is complete.

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.js with root scope and verifies that /scope:default/ is controlled before loading the iframe.

The iframe starts at about:blank and 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:

  • session ids and six-digit access codes;
  • host heartbeat state;
  • remote viewer heartbeat ids;
  • WebRTC signaling/control messages such as offer, answer, ICE candidates, approval, and disconnect.

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_HOST
  • PLAYGROUND_RELAY_DB_USER, DB_USER
  • PLAYGROUND_RELAY_DB_PASSWORD, DB_PASSWORD
  • PLAYGROUND_RELAY_DB_NAME, DB_NAME
  • PLAYGROUND_RELAY_DB_PORT, DB_PORT

PLAYGROUND_RELAY_PUBLIC_BASE_URL may be set to force generated remote access share URLs. For my.wordpress.net, use:

PLAYGROUND_RELAY_PUBLIC_BASE_URL=https://my.wordpress.net

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.php
  • npm exec nx test playground-remote-access
  • npm exec nx lint playground-remote-access
  • npm exec nx build playground-remote-access
  • npm exec nx typecheck playground-personal-wp
  • npm exec nx typecheck playground-remote
  • npm exec nx lint playground-personal-wp
  • git diff --check

I did not run the full build or deployment scripts.

@akirk akirk force-pushed the personal-wp-desktop-webrtc-trunk branch from aa0319e to 07016be Compare June 6, 2026 13:12
@akirk akirk force-pushed the personal-wp-desktop-webrtc-trunk branch 2 times, most recently from 927b078 to cb50804 Compare June 7, 2026 17:27
@akirk akirk changed the title Prototype direct Personal WP desktop access [Personal-WP] Add direct Personal WP desktop access Jun 8, 2026
@akirk akirk marked this pull request as ready for review June 8, 2026 12:41
@akirk akirk requested review from a team, brandonpayton and Copilot June 8, 2026 12:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread packages/playground/personal-wp/src/lib/desktop-access-service.ts Outdated
Comment thread packages/playground/remote/service-worker.ts Outdated
Comment thread packages/playground/remote-access/relay.php Outdated
Comment thread packages/playground/personal-wp/src/components/desktop-access-viewer/index.tsx Outdated
@akirk akirk force-pushed the personal-wp-desktop-webrtc-trunk branch from 07a1cc4 to 9a8b364 Compare June 8, 2026 12:51
@akirk akirk requested a review from adamziel June 12, 2026 09:05
Comment thread packages/playground/remote-access/src/service-worker-relay.ts Outdated
Comment thread packages/playground/remote-access/src/remote-access-direct-tunnel.ts Outdated
Comment thread packages/playground/remote-access/relay.php
Comment thread packages/playground/remote-access/src/service-worker-relay.ts Outdated
@akirk akirk requested a review from Copilot June 12, 2026 14:13
@akirk

akirk commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Thanks, @adamziel! I fixed what your review revealed and was also finally able to find a workaround for Chrome renderer crashes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 38 out of 40 changed files in this pull request and generated 7 comments.

Comment thread packages/playground/remote-access/relay.php
Comment thread packages/playground/remote-access/src/service-worker-relay.ts
Comment thread packages/playground/remote-access/src/service-worker-relay.ts Outdated
Comment thread packages/playground/remote-access/vite.config.ts Outdated
Comment thread packages/playground/remote-access/src/connect-code.ts
Comment thread packages/playground/remote-access/src/connect-code.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants