/** * The mobile bridge: the one server `bitmagic dev` exposes to the local network. * * `dev` normally binds nothing outside loopback. vite serves the game on 127.0.0.1 and the editor * sidecar deliberately stays there too — it writes files in the creator's project, and no phone * needs the shell. So rather than opening either of them up, `--mobile` puts THIS in front: a * reverse proxy that terminates the phone's connection, forwards the game, and does the two things * a plain `--host` on vite could not. * * 1. It serves the CDN. A LAN origin is on no bucket's CORS allowlist, so the phone asking the * bucket directly gets nothing (`../local-port.ts` documents what that looks like from the * creator's side: a level with no terrain). Same-origin `/__bm/cdn//` requests * land here instead and are fetched server-side, where CORS does not apply. * 2. It injects `rewrite-shim.ts` into every HTML page it passes through, which is what makes * the engine ask for (1) in the first place. * * WebSocket upgrades are piped straight through to vite, so its HMR client connects from the phone * and the page reloads on a rebuild exactly as the desktop shell does. * * What is NOT here is as deliberate: no route to the sidecar, and therefore no way for anything on * the network to save a scene, start a generation, or read the editor journal. The phone gets the * game and the game's assets. */ import * as http from 'http'; export interface MobileBridgeOptions { /** Where vite is serving the game, on loopback. */ gamePort: number; /** The port to expose on the network. */ port: number; /** The LAN address the printed URL names. The bridge itself listens on every interface. */ address: string; /** A key/cert pair from `dev-cert.ts`, or null to serve plain http (no WebGPU on the device). */ tls: { key: string; cert: string; } | null; log: (message: string) => void; /** * Hands one request to the reload bus as an SSE stream, putting the phone on the SAME push * channel as the desktop shell — the coordinator's, which only fires once a compile has landed. * * Passed as a function rather than the bus itself so this module stays unaware of the editor's * half of `dev`. It is the one sidecar capability the network is given, and it is one-directional * and read-only: nothing on the other end of it can save a scene or read the journal. */ subscribe?: (req: http.IncomingMessage, res: http.ServerResponse) => void; /** Seam for the test; production uses the runtime's own fetch. */ fetchImpl?: typeof globalThis.fetch; } export interface MobileBridge { /** What to print, and what the QR encodes. */ url: string; close(): Promise; } /** * Start the bridge and return the URL to hand the phone. * * Listens on every interface — that is the point of the command — which is why `dev` prints what * that means alongside the URL. */ export declare function startMobileBridge(options: MobileBridgeOptions): Promise;