You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a 'Handling connection and auth errors' section to the client guide
covering rpc.status, rpc.connectionError, the connection:status /
connection:error / rpc:error events, DevframeConnectionError (and its kind),
and the callTimeout option, with one framework-neutral recipe that gates the
UI on status and branches a failing call on error kind. Refresh the now-stale
Events section and options table, and note that a hub viewer can read the same
status centrally via context.connection.
Copy file name to clipboardExpand all lines: docs/guide/client-context.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,6 +53,7 @@ Boot the host once per page: a second boot replaces the published context and lo
53
53
|`panel`| Dock panel state: position, size, drag/resize flags. |
54
54
|`commands`| The command palette: `register()`, `execute()`, `getKeybindings()`. |
55
55
|`when`| The [when-clause](./when-clauses) evaluation context. |
56
+
|`connection`| The client's live [connection status](./client#handling-connection-and-auth-errors) — `status`, `error`, and `events` — so a viewer can render one central connection indicator for every docked plugin. |
Copy file name to clipboardExpand all lines: docs/guide/client.md
+93-1Lines changed: 93 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,7 +49,8 @@ await connectDevframe({
49
49
|`baseURL`| Mount path to probe for `__connection.json`. Accepts an array for fallback. Default: `'./'` — resolved relative to `document.baseURI` so the SPA finds its meta wherever it was deployed. Pass an explicit absolute path (e.g. `'/__devframe/'`) when calling from outside the SPA — say, an embedded webcomponent injected into a host app. |
50
50
|`authToken`| Override the auth token. Defaults to a locally-persisted human-readable id. |
51
51
|`cacheOptions`|`true` to enable caching with defaults, or an options object. |
52
-
|`wsOptions`| Forwarded to the WebSocket transport (reconnect, heartbeat, etc.). |
52
+
|`callTimeout`| Milliseconds after which a pending `rpc.call` rejects with a `DevframeConnectionError` of kind `'timeout'`. Omit (or `0`) to wait indefinitely. See [Handling connection and auth errors](#handling-connection-and-auth-errors). |
53
+
|`wsOptions`| Low-level WebSocket transport overrides — `onConnected` / `onError` / `onDisconnected` lifecycle hooks and the socket URL. |
53
54
|`rpcOptions`| Forwarded to `birpc`. |
54
55
|`connectionMeta`| Pre-known descriptor that skips the `__connection.json` fetch. |
55
56
@@ -229,6 +230,15 @@ The descriptor carries a session-only, pre-approved auth token, so `ensureTruste
229
230
230
231
## Events
231
232
233
+
The client emits over `rpc.events`:
234
+
235
+
| Event | Fires when |
236
+
|-------|------------|
237
+
|`rpc:is-trusted:updated`| Trust is granted, denied, or revoked. Carries the new `isTrusted` boolean. |
238
+
|`connection:status`| The [connection status](#handling-connection-and-auth-errors) changes. Carries `(status, previous)`. |
239
+
|`connection:error`| A connection-level failure occurs — the socket errors, or trust is refused. Carries the `Error`. |
240
+
|`rpc:error`| An `rpc.call` rejects, from the server or a down connection. Carries `(error, method)`. |
`rpc.isTrusted` is the synchronous read. Subscribe to `rpc:is-trusted:updated` to drive reauth flows or gate rendering until the client is trusted.
252
+
253
+
## Handling connection and auth errors
254
+
255
+
A dev-mode client rides a live WebSocket, so it can lose the server mid-session or be refused authentication. Surface those states in your UI — a devtool that keeps spinning with no feedback leaves the user guessing whether it's loading or broken. The client gives you a single status to render from, events to react to, and calls that fail fast instead of hanging.
256
+
257
+
### Connection status
258
+
259
+
`rpc.status` collapses the transport and the trust handshake into one value, and `rpc.connectionError` holds the last connection-level `Error` (or `null` when healthy):
260
+
261
+
| Status | Meaning |
262
+
|--------|---------|
263
+
|`connecting`| Establishing the socket / running the initial handshake. Calls issued now queue until it opens. |
264
+
|`connected`| Socket open and trusted; calls are served. |
265
+
|`unauthorized`| Socket open, but the server refused trust. Prompt for [authentication](#authenticating-with-a-one-time-code). |
266
+
|`disconnected`| The socket closed — dropped mid-session, or never opened. |
267
+
|`error`| A fatal connection error, e.g. the socket errored or the connection meta couldn't load. |
268
+
269
+
A `static` backend has no live socket, so `rpc.status` is `connected` for its whole life — gating on it is a no-op there, and a build-time SPA never shows a connection state.
270
+
271
+
### Calls fail fast
272
+
273
+
Once the socket closes or trust is refused, in-flight and new `rpc.call` promises reject with a `DevframeConnectionError` rather than hanging forever. Its `kind` tells you why, so a `catch` can branch without string-matching:
274
+
275
+
-`'connection'` — the transport is down (`disconnected` / `error`).
276
+
-`'auth'` — the client is `unauthorized`.
277
+
-`'timeout'` — the call outlived the `callTimeout` option.
278
+
279
+
Set `callTimeout` when constructing the client to also cap a live-but-unresponsive server:
throwerror// a real server-side error — surface it.
318
+
}
319
+
}
320
+
```
321
+
322
+
### Recovering
323
+
324
+
Recovery is explicit — the client doesn't reconnect on its own. The simplest path is a full page reload, which re-runs `connectDevframe` and the trust handshake; that's what the built-in plugins do behind their **Reload** button. An app that wants to reconnect without a reload can own it by re-running its connect routine to build a fresh client:
325
+
326
+
```ts
327
+
asyncfunction reconnect() {
328
+
rpc=awaitconnectDevframe() // a new client; re-subscribe your listeners
329
+
render()
330
+
}
331
+
```
332
+
333
+
The five built-in plugins are worked references — each gates its surface on `rpc.status` and offers a reload. In a hub, a viewer can read the same status centrally from [`context.connection`](./client-context#the-client-context) instead of every plugin surfacing its own.
0 commit comments