diff --git a/apps/p2/README.md b/apps/p2/README.md index 5cdfc62e3..72dbf311d 100644 --- a/apps/p2/README.md +++ b/apps/p2/README.md @@ -113,8 +113,14 @@ The TUI launcher requires **Node >=26.5.1**; the server still supports Node 22.1 npm run tui # device owner on http://127.0.0.1:$PORT (8788 when unset) npm run tui -- https://your-domain # prompts for an owner link if no valid cookie is saved npm run tui -- https://your-domain --owner-link 'https://your-domain/owner#' +npm run tui -- --radius # through Radius: your only online server, or --radius ``` +With `--radius` the TUI reaches a server signed in with `npm run radius:login`, from anywhere and without a tunnel or +owner link. The first run signs the TUI in to Radius by device code (saved in `~/.pi/p2-tui/radius.json`); Radius +admits only the server's owner. For now each request is its own Radius connection, so a new server bundle shows up +within 10 seconds rather than one (see [p2 notes](docs/p2-notes.md#tui-through-radius)). + Direct loopback auto-signs in as the device owner without a link prompt; a proxy marker cannot use that path. For remote URLs (HTTPS required), get an owner link on the host, then pass `--owner-link` or paste it at the prompt. The TUI stores only its cookie per origin in `~/.pi/p2-tui/config.json` (0600, directory 0700; diff --git a/apps/p2/docs/p2-notes.md b/apps/p2/docs/p2-notes.md index ab009ad48..ef4b93d55 100644 --- a/apps/p2/docs/p2-notes.md +++ b/apps/p2/docs/p2-notes.md @@ -432,6 +432,25 @@ npm start admission and provider access, HTTP credit in both directions, congestion, forwards, redirects, WebSockets, unavailable ports and anonymous public/private gates. All listeners use port 0 and private temporary data. +### TUI through Radius + +`npm run tui -- --radius []` reaches the server through Radius, without a tunnel or owner link. The +launcher signs in to Radius itself (device code, saved in `~/.pi/p2-tui/radius.json`, separate from any server's +`radius.json`), picks the given server or the user's only online one (`GET /v1/servers`), and connects to +`/v1/servers//connect` with its bearer token (`pi-server.client.v2`). Radius admits only the server's owner and +opens a `ws` channel without a request; the brain ("Client channels" in `brain.ts`) reads the request from the +client's first message and makes it a loopback request marked like the owner's browser requests, without a shell +origin (`access: "relay"`: no owner links). The launcher's requests go through a transport (`tui-transport.ts`, +`tui-radius.ts`); the direct cookie transport is unchanged. Only v5 relays (channel sockets) carry client channels. + +**Temporary: one Radius connection per request.** Radius allows 120 new connections a minute per user, shared with +the server's own reconnects, so through Radius the launcher checks for a new bundle every 10 s instead of every +second, and every request (owner check, manifest, bundle, downloads, uploads) and every chord link reconnect costs a +connection setup. The proper form keeps one connection per launcher and carries all of its requests and its chord +link over it: every message labelled with the request it belongs to, both sides sorting them, and large transfers +taking turns with the chord link so a download cannot hold up live output. Then the 1 s bundle check returns. +`test/p2/radius.test.ts` and `test/p2/tui-radius.test.ts` cover client channels with the same fake relay. + ## Browser navigation `src/web/navigation.ts` is an independent, minimized copy of Pi Mobile's stack. `src/runtime/web.tsx` exposes diff --git a/apps/p2/plugins/radius/brain.ts b/apps/p2/plugins/radius/brain.ts index b41db86b9..b3ed6d44a 100644 --- a/apps/p2/plugins/radius/brain.ts +++ b/apps/p2/plugins/radius/brain.ts @@ -105,6 +105,25 @@ import { * (`pub--