|
| 1 | +# Local Viewer Connection Landing |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Make a bare `local.sentry.dev` visit useful without weakening the existing |
| 6 | +CLI-paired local receiver boundary. The common case should connect to a |
| 7 | +running default receiver without a URL fragment; custom local and remote |
| 8 | +streams remain an explicit user choice. |
| 9 | + |
| 10 | +## Connection policy |
| 11 | + |
| 12 | +The viewer resolves one endpoint in this order: |
| 13 | + |
| 14 | +1. A valid CLI-provided `#stream` fragment. |
| 15 | +2. A saved loopback endpoint from local storage. |
| 16 | +3. The default receiver, `http://localhost:8969/stream`. |
| 17 | + |
| 18 | +The UI removes the fragment from the address bar after reading it. A |
| 19 | +successfully connected loopback endpoint is saved in local storage so a later |
| 20 | +bare visit can reconnect. The default is saved only after it opens |
| 21 | +successfully. |
| 22 | + |
| 23 | +Users can submit an endpoint through the connection landing page. Loopback |
| 24 | +`http` or `https` endpoints with a `/stream` path are accepted and persisted. |
| 25 | +Remote endpoints must use `https`, have no embedded user credentials, and are |
| 26 | +kept only in session storage. Remote streams connect directly from the browser; |
| 27 | +`local.sentry.dev` never proxies them or receives their endpoint. |
| 28 | + |
| 29 | +Remote servers are responsible for allowing the viewer origin with CORS. This |
| 30 | +MVP does not support custom authorization headers because native `EventSource` |
| 31 | +does not provide them. A user may paste an HTTPS stream URL with its own query |
| 32 | +parameters when their receiver uses a URL-scoped token. |
| 33 | + |
| 34 | +## User experience |
| 35 | + |
| 36 | +When no receiver has opened yet, render one centered connection landing panel |
| 37 | +instead of separate setup and empty-feed surfaces. |
| 38 | + |
| 39 | +- Start by showing that the default receiver is being checked. |
| 40 | +- When it opens, move directly to the normal event workspace and its |
| 41 | + `Waiting for events` state. |
| 42 | +- When it cannot open, reveal a prefilled endpoint field, concise error text, |
| 43 | + a Connect button, and a copyable `sentry local serve --open` command. |
| 44 | +- An Advanced disclosure explains custom local versus remote endpoints and the |
| 45 | + remote HTTPS requirement. |
| 46 | +- A connected, empty workspace still offers a small Change receiver action, |
| 47 | + rather than forcing users to edit the browser URL. |
| 48 | + |
| 49 | +The landing form has a visible label, validation feedback, keyboard submission, |
| 50 | +and equivalent light and dark presentation. |
| 51 | + |
| 52 | +## Components and boundaries |
| 53 | + |
| 54 | +`apps/local/src/lib/spotlight.ts` owns endpoint parsing and classification. It |
| 55 | +returns a normalized endpoint and persistence policy (`loopback` or `remote`) |
| 56 | +without knowing about React or storage. |
| 57 | + |
| 58 | +`App.tsx` owns resolution order, storage reads/writes, EventSource lifecycle, |
| 59 | +and the state transition between connecting, connected, and failed states. |
| 60 | +The connection landing component is presentational: it receives the input, |
| 61 | +status, validation message, and callbacks. It does not create EventSources or |
| 62 | +access storage directly. |
| 63 | + |
| 64 | +The local CLI and receiver remain unchanged. Their existing `--open` fragment |
| 65 | +continues to be the authoritative pairing path, and receiver CORS remains |
| 66 | +limited to its existing read-only `/stream` policy for `local.sentry.dev`. |
| 67 | + |
| 68 | +## Failure handling |
| 69 | + |
| 70 | +Malformed URLs, non-loopback HTTP remote endpoints, credential-bearing URLs, |
| 71 | +and paths other than `/stream` are rejected before a connection attempt. A |
| 72 | +failed EventSource displays actionable status while retaining the entered URL. |
| 73 | +Submitting another endpoint closes the prior EventSource before opening the |
| 74 | +next one. Clearing the feed does not discard a selected receiver. |
| 75 | + |
| 76 | +## Verification |
| 77 | + |
| 78 | +- Pure tests cover source priority, loopback/remote classification, malformed |
| 79 | + endpoint rejection, persistence policy, and query-token preservation. |
| 80 | +- Integration tests cover default connection, fallback form, manual local |
| 81 | + reconnection after reload, remote session-only behavior, error recovery, and |
| 82 | + clean EventSource replacement. |
| 83 | +- Run the local app test suite, lint, and production build, plus the focused |
| 84 | + CLI local receiver tests. |
| 85 | +- Manually verify the no-receiver, default-receiver, custom-receiver, and |
| 86 | + failed-receiver views in both light and dark themes. |
0 commit comments