Skip to content

Commit 8600b67

Browse files
committed
docs: apply review — hub UI provider, hosted/standalone adapters, MessageChannel
Adopts antfu's review on the Terms page: the hub UI implementation term becomes "hub UI provider" repo-wide ("external viewer" survives for cross-origin surfaces and gains its own terms row), the mount-context row reads "hosted / standalone adapters", and the in-page channel lists MessageChannel alongside BroadcastChannel. Diagnostic fix strings and code comments follow; API names (initHub's ui.viewer slot, registerDevframeViewerOrigin) are unchanged.
1 parent 42577e5 commit 8600b67

63 files changed

Lines changed: 125 additions & 125 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Positioning
44

5-
**`devframe`** is the framework-neutral container for one devtool integration, portable across viewers. Build a single tool (its RPC, its SPA, its diagnostics, its CLI/build/embedded outputs) without caring how it'll be displayed. A devframe runs standalone (CLI, static deploy, embedded SPA) just as well as it mounts inside a hub.
5+
**`devframe`** is the framework-neutral container for one devtool integration, portable across hub UI providers. Build a single tool (its RPC, its SPA, its diagnostics, its CLI/build/embedded outputs) without caring how it'll be displayed. A devframe runs standalone (CLI, static deploy, embedded SPA) just as well as it mounts inside a hub.
66

7-
**`@devframes/hub`** is the framework-neutral hub layer that sits on top of devframe and provides the multi-devframe orchestration (docks, terminals, messages, commands). It does not ship UI - viewers (e.g. `@vitejs/devtools-kit`) provide their own UI on top of the hub's RPC + shared-state protocol. It does ship a **headless client runtime** (`createDevframeClientHost()` from `@devframes/hub/client`): booted in the host page, it assembles the shared `DevframeClientContext` (panel, docks, commands, when) and imports each dock entry's client script (`action` / `custom-render` / iframe `clientScript`) into that page - how a built-in devframe like the a11y inspector runs its page script inside the user app's page. See `examples/hub-vite/` for a working ~120-line Vite host demonstrating the protocol end to end.
7+
**`@devframes/hub`** is the framework-neutral hub layer that sits on top of devframe and provides the multi-devframe orchestration (docks, terminals, messages, commands). It does not ship UI - hub UI providers (e.g. `@vitejs/devtools-kit`) provide their own UI on top of the hub's RPC + shared-state protocol. It does ship a **headless client runtime** (`createDevframeClientHost()` from `@devframes/hub/client`): booted in the host page, it assembles the shared `DevframeClientContext` (panel, docks, commands, when) and imports each dock entry's client script (`action` / `custom-render` / iframe `clientScript`) into that page - how a built-in devframe like the a11y inspector runs its page script inside the user app's page. See `examples/hub-vite/` for a working ~120-line Vite host demonstrating the protocol end to end.
88

99
## Terminology
1010

@@ -15,7 +15,7 @@ The docs' canonical vocabulary lives in [`docs/content/1.guide/1.terms.md`](docs
1515
- **host framework** is the environment a devframe or hub mounts into (a Vite dev server, a Next.js app, a Hono server); named forms like "the Vite host" are fine. **host page** is the browser document where the client runtime boots; **user app** is the application being developed and inspected.
1616
- A devframe's two halves are the **node side** and the **browser side**.
1717
- Browser-side terms: **client runtime** (`createDevframeClientHost()`), **client context**, **client script**, **page script** (a devframe's script in the user app's page - never "agent"; **coding agent** is the only agent), **RPC client** (`connectDevframe()`), **SPA**, **panel** (a devframe's SPA as a rendered surface), **surface** (any rendered browser view - say "API", not "API surface").
18-
- Hub terms: **viewer** (a hub UI implementation - never "shell"), **dock entry** / **dock rail** / **dock panel**, **mounted devframe** (never "frame").
18+
- Hub terms: **hub UI provider** (a hub UI implementation - never "shell" or bare "viewer"; "external viewer" stays for cross-origin surfaces in the security docs), **dock entry** / **dock rail** / **dock panel**, **mounted devframe** (never "frame").
1919
- The three communication paths: **RPC** (browser side ↔ node side), the **client context** (client scripts ↔ client runtime), and the **in-page channel** (page script ↔ panel, same-origin in-browser).
2020
- Storage scopes: **workspace scope** (committable, per-repo), **project scope** (per-checkout), **global scope** (per-user) - never describe the project scope as "per-workspace".
2121
- **framework kits** are `@devframes/vite` / `@devframes/nuxt` / `@devframes/next`; refer to external products by their full names (`@vitejs/devtools-kit`, `@nuxt/devtools`).
@@ -72,8 +72,8 @@ The framework kits - `@devframes/vite`, `@devframes/nuxt`, `@devframes/next` - e
7272
- **`.../single`** - **build & dev-serve a single devframe's SPA** with that tool (the "I'm authoring one devframe" scope). Vite: the `devframeVitePlugin` / `devframeViteBridge` / `devframeVite` plugins. Next: `withDevframe` + `createDevframeNextHandler`, with its React client at `.../single/client`. Nuxt: the Nuxt module (registered as `modules: ['@devframes/nuxt/single']`).
7373
- **`.../hub`** - **mount a whole `@devframes/hub` (many devframes) inside that tool** (the "I'm standing up devtools" scope). Wraps `initHub`, defaults the UI slot to `@devframes/hub-ui`'s `createUi()` (overridable via `ui`, or `ui: false` for headless), and ships a browser client helper at `.../hub/client` (a thin, lifecycle-managing wrapper over `@devframes/hub/client`'s `createDevframeClientHost`). `@devframes/hub` and `@devframes/hub-ui` are **optional peers** of these packages; `hub-ui` is loaded lazily (a bundler-ignored dynamic `import()` in the Next hub) so it stays optional and its `import.meta.url` asset lookups resolve at request time.
7474
- **The bare root (`.`) throws** a helpful error pointing at the two subpaths - never put real code on it.
75-
- **Vite and Nuxt already have native hub viewers** (`@vitejs/devtools-kit`, `@nuxt/devtools`), so `@devframes/vite/hub` and `@devframes/nuxt/hub` still work but emit a one-time `console.warn` recommending those (silence with `{ quiet: true }`). `@devframes/next/hub` has no native counterpart, so it warns nothing.
76-
- The **full hub examples** (`examples/hub-vite`, `examples/hub-next`) consume `.../hub` on the node side but keep hand-rolling their own viewer against `@devframes/hub/client` with `ui: false` - that hand-rolled viewer is the whole point of those reference hosts. The **minimal** ones (`examples/hub-*-minimal`) consume `.../hub` with the default `@devframes/hub-ui` and inject its `embedded.js`, needing no browser-side code.
75+
- **Vite and Nuxt already have native hub UI providers** (`@vitejs/devtools-kit`, `@nuxt/devtools`), so `@devframes/vite/hub` and `@devframes/nuxt/hub` still work but emit a one-time `console.warn` recommending those (silence with `{ quiet: true }`). `@devframes/next/hub` has no native counterpart, so it warns nothing.
76+
- The **full hub examples** (`examples/hub-vite`, `examples/hub-next`) consume `.../hub` on the node side but keep hand-rolling their own hub UI provider against `@devframes/hub/client` with `ui: false` - that hand-rolled hub UI provider is the whole point of those reference hosts. The **minimal** ones (`examples/hub-*-minimal`) consume `.../hub` with the default `@devframes/hub-ui` and inject its `embedded.js`, needing no browser-side code.
7777

7878
### Design system
7979

@@ -95,7 +95,7 @@ All five built-in plugins - and every example under `examples/` - share one desi
9595

9696
### Devframe design principles
9797

98-
These reinforce devframe's positioning as "the container for one devtool integration, portable to multiple viewers". When in doubt, err on the side of "devframe provides primitives, the hub provides UX".
98+
These reinforce devframe's positioning as "the container for one devtool integration, portable to multiple hub UI providers". When in doubt, err on the side of "devframe provides primitives, the hub provides UX".
9999

100100
- **Single-integration scope.** Devframe describes one tool. If a feature only makes sense when multiple tools share a UI - docking, a unified command palette, cross-tool toasts, terminal aggregation - it belongs in a hub package, not here.
101101
- **Headless by default.** No default startup banners, no opinionated logging to stdout, no default styling. Provide hooks (`onReady`, `cli.configure`, etc.); let the application print its own branding. Structured diagnostics via `nostics` are fine - ad-hoc `console.log`s baked into adapters are not.

‎docs/content/1.guide/1.terms.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Every concept in these docs has exactly one name. This page fixes that vocabular
1717
| **framework kit** | Framework conventions over the standard handler, each split into a `/single` and a `/hub` scope. | `@devframes/vite`, `@devframes/nuxt`, `@devframes/next` |
1818
| **opt-in package** | A capability shipped as its own package and added when needed. | `@devframes/json-render` |
1919
| **hub** | The composition layer that puts many devframes behind one handler; *a hub* is one `initHub()` instance. | `@devframes/hub`, `initHub()` |
20-
| **viewer** | A hub UI implementation: the node-side `ui` slot plus the browser-side context contract. `@devframes/hub-ui` is the reference viewer. | `initHub({ ui })` |
20+
| **hub UI provider** | A hub UI implementation: the node-side `ui` slot plus the browser-side context contract. `@devframes/hub-ui` is the reference hub UI provider. | `initHub({ ui })` |
2121

2222
## Node side
2323

@@ -29,7 +29,7 @@ A devframe has two halves: the **node side** registers RPC functions and owns st
2929
| **host framework** | The environment a devframe or hub mounts into: a Vite dev server, a Next.js app, a Hono server. Named forms — *the Vite host*, *a Next.js host* — refer to a specific one. | `DevframeHost` |
3030
| **dev server** | The standalone HTTP server the dev adapter starts. | `createDevServer()` |
3131
| **side-car server** | The separate RPC/WebSocket process used when a host framework's handlers never see upgrade requests. | — |
32-
| **hosted / standalone** | The two mount contexts: hosted adapters (vite, embedded) default the base path to `/__<id>/`; standalone adapters (cli, build) default to `/`. | `resolveBasePath()` |
32+
| **hosted / standalone adapters** | The two mount contexts: hosted adapters (vite, embedded) default the base path to `/__<id>/`; standalone adapters (cli, build) default to `/`. | `resolveBasePath()` |
3333
| **workspace scope** | Committable per-repository storage. | `DevframeStorageScope` |
3434
| **project scope** | Per-checkout storage, gitignored. | `DevframeStorageScope` |
3535
| **global scope** | Per-user storage. | `DevframeStorageScope` |
@@ -49,6 +49,7 @@ A devframe has two halves: the **node side** registers RPC functions and owns st
4949
| **SPA** | A devframe's built web interface; `clientAssets` says where it lives. | `clientAssets` |
5050
| **panel** | A devframe's SPA as a rendered surface — in a dock panel or standalone. | — |
5151
| **surface** | Any rendered browser view: a panel, a dock iframe, a standalone SPA. | — |
52+
| **external viewer** | A cross-origin surface (a browser extension, a separate devtools page) connecting from its own origin. | `registerDevframeViewerOrigin()` |
5253
| **coding agent** | An agent consuming a devframe over MCP — the only agent in these docs. | `createMcpServer()` |
5354

5455
## Hub
@@ -68,4 +69,4 @@ Three distinct paths connect the pieces; each has its own name.
6869
|------|---------|-----------|
6970
| **RPC** | browser side ↔ node side | WebSocket or static snapshot, via `connectDevframe()` |
7071
| **client context** | client scripts ↔ client runtime | a shared object inside the host page |
71-
| **in-page channel** | page script ↔ panel | same-origin, entirely in-browser (e.g. a `BroadcastChannel`) |
72+
| **in-page channel** | page script ↔ panel | same-origin, entirely in-browser (e.g. a `MessageChannel` or `BroadcastChannel`) |

‎docs/content/1.guide/13.client.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ One SPA artifact serves at `/`, `/__<id>/`, or any subpath, no rebuild. Build wi
2525

2626
### Sharing a connection with an external viewer
2727

28-
`setupDevframeConnection()` prepares a serializable connection for a cross-origin viewer:
28+
`setupDevframeConnection()` prepares a serializable connection for an external viewer:
2929

3030
```ts
3131
import { setupDevframeConnection } from 'devframe/client'
@@ -35,7 +35,7 @@ const connection = await setupDevframeConnection({
3535
})
3636
```
3737

38-
In the viewer:
38+
In the external viewer:
3939

4040
```ts
4141
import { connectDevframe } from 'devframe/client'
@@ -240,7 +240,7 @@ const rpc = await connectDevframe()
240240
// Already wired to the local dev server via the injected descriptor.
241241
```
242242

243-
The descriptor's session-only, pre-approved token makes `ensureTrusted()` resolve immediately. An external hub builds a viewer URL from a trusted connection with `buildRemoteDevframeUrl()`, keeping the token in the URL fragment:
243+
The descriptor's session-only, pre-approved token makes `ensureTrusted()` resolve immediately. An external hub builds an external-viewer URL from a trusted connection with `buildRemoteDevframeUrl()`, keeping the token in the URL fragment:
244244

245245
```ts
246246
import {
@@ -352,4 +352,4 @@ async function reconnect() {
352352
}
353353
```
354354

355-
In a hub, a viewer reads this status from [`context.connection`](/guide/client-context#the-client-context).
355+
In a hub, a hub UI provider reads this status from [`context.connection`](/guide/client-context#the-client-context).

‎docs/content/1.guide/17.hub.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
22
title: 'Hub'
3-
description: '@devframes/hub orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI — viewers provide their own atop the hub''s RPC + shared-state protocol.'
3+
description: '@devframes/hub orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI — hub UI providers provide their own atop the hub''s RPC + shared-state protocol.'
44
---
55

6-
`@devframes/hub` orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI — viewers provide their own atop the hub's RPC + shared-state protocol.
6+
`@devframes/hub` orchestrates many devtools sharing a UI: a dock registry, terminal aggregation, message/toast queue, and command palette. It ships no UI — hub UI providers provide their own atop the hub's RPC + shared-state protocol.
77

88
![Hub screenshot](/screenshots/hub-1.png)
99

@@ -71,7 +71,7 @@ A `type: 'launcher'` dock entry is a one-click action tile. Three optional `laun
7171

7272
| Field | Purpose |
7373
|---|---|
74-
| `command` | Bound command id; out-of-process viewers dispatch via `hub:commands:execute` (register a handler via `ctx.commands`). |
74+
| `command` | Bound command id; out-of-process hub UI providers dispatch via `hub:commands:execute` (register a handler via `ctx.commands`). |
7575
| `terminalSessionId` | Tracked session id; a "view in terminal" action calls `hub:docks:activate` with the terminals dock id and `{ sessionId }`. |
7676
| `digest` | Latest progress line, shown inline; patch via `docks.update()`. |
7777

@@ -120,7 +120,7 @@ const ctx = await createHubContext({ cwd, host, mode: 'dev' })
120120
await ctx.install(myDevframe)
121121
```
122122

123-
Framework kits and viewers wrap this (e.g. `@vitejs/devtools-kit`'s `createPluginFromDevframe`).
123+
Framework kits and hub UI providers wrap this (e.g. `@vitejs/devtools-kit`'s `createPluginFromDevframe`).
124124

125125
### Connecting embedded SPAs
126126

@@ -237,9 +237,9 @@ Group and members stay independent top-level entries in `devframe:docks`; `defau
237237

238238
Framework kits can interleave category ids or override weights; an unknown category sorts as `0`.
239239

240-
## The protocol — what the viewer sees
240+
## The protocol — what the hub UI provider sees
241241

242-
A viewer imports no hub classes; it reads these shared-state keys and RPC methods:
242+
A hub UI provider imports no hub classes; it reads these shared-state keys and RPC methods:
243243

244244
| Channel | Type | What it carries |
245245
|---|---|---|

‎docs/content/1.guide/18.client-context.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ For a URL, attach it via `ctx.install(myDevframe, { dock: { clientScript: { impo
8383

8484
### Bare npm specifiers
8585

86-
Resolving a bare specifier is the **host framework's capability**: a host framework advertises a resolution template at `ConnectionMeta.configs.dock.clientModuleResolution` (loaders replace `{specifier}` before import). A Vite host declares this by default (`@devframes/vite/hub`) as `initHub({ clientModuleResolution: '/@id/{specifier}' })`; then use the specifier alone as `importFrom`. A host framework with no template (Next.js) supports the URL shape only, warning [`DF8111`](/errors/DF8111) on a specifier. A viewer can override with `createDevframeClientHost({ resolveClientModule })`.
86+
Resolving a bare specifier is the **host framework's capability**: a host framework advertises a resolution template at `ConnectionMeta.configs.dock.clientModuleResolution` (loaders replace `{specifier}` before import). A Vite host declares this by default (`@devframes/vite/hub`) as `initHub({ clientModuleResolution: '/@id/{specifier}' })`; then use the specifier alone as `importFrom`. A host framework with no template (Next.js) supports the URL shape only, warning [`DF8111`](/errors/DF8111) on a specifier. A hub UI provider can override with `createDevframeClientHost({ resolveClientModule })`.
8787

8888
Client scripts execute in the user app's page realm (`window`); anchor shared state on `globalThis`.
8989

@@ -103,10 +103,10 @@ A tool with many internal views (Nuxt DevTools' tabs) can surface each as a hub
103103
|---|---|---|
104104
| `ready` / `manifest` | iframe → host page | tab list (`{ tabs, current }`), on load and change |
105105
| `navigate` | host page → iframe | show a view (`{ tabId, navTarget }`); the SPA routes client-side |
106-
| `navigated` | iframe → host page | the SPA navigated internally; the viewer highlights the dock |
106+
| `navigated` | iframe → host page | the SPA navigated internally; the hub UI provider highlights the dock |
107107

108108
It materializes a [client-only dock](#client-only-docks) per tab (id `<frameId>:<tabId>`) sharing the anchor's `frameId` and a `navTarget`, independent of [`groupId`](/guide/hub#grouping-dock-entries).
109109

110-
### The viewer's part
110+
### The hub UI provider's part
111111

112-
A viewer keeps one iframe alive per `frameId` (shown/hidden); on mount, it sets the element on the anchor's `docks.getStateById(anchorId)` state (`domElements.iframe`) and emits `dom:iframe:mounted`. See the "Tabbed Tool" in [`examples/hub-vite`](https://github.com/devframes/devframe/tree/main/examples/hub-vite) / [`hub-next`](https://github.com/devframes/devframe/tree/main/examples/hub-next).
112+
A hub UI provider keeps one iframe alive per `frameId` (shown/hidden); on mount, it sets the element on the anchor's `docks.getStateById(anchorId)` state (`domElements.iframe`) and emits `dom:iframe:mounted`. See the "Tabbed Tool" in [`examples/hub-vite`](https://github.com/devframes/devframe/tree/main/examples/hub-vite) / [`hub-next`](https://github.com/devframes/devframe/tree/main/examples/hub-next).

‎docs/content/1.guide/19.hub-initiate.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ The advertised path is hub-base-absolute (`/__devframes/__ws`). Dev-reevaluated
3939
| `__connection.json` | meta for the shared RPC socket |
4040
| `__ws` | WebSocket upgrade route |
4141
| `__index.json` | machine-readable index: mounted devframes, endpoints |
42-
| `__client-imports.js` | dock client-script import map for viewers |
42+
| `__client-imports.js` | dock client-script import map for hub UI providers |
4343
| `__mcp` | aggregate MCP endpoint over the tool registry (opt-in `mcp`) |
4444

4545
Devframe ids become URL segments, validated: reserved names throw `DF8000`, non-route-safe `DF8004`.
@@ -57,7 +57,7 @@ interface DevframeHubUi {
5757
}
5858
```
5959

60-
`@devframes/hub-ui`'s `createUi()` is the reference (viewer + floating dock); its `setup(ctx)` publishes config to `ctx.staticConfig.ui` (`ConnectionMeta.configs.ui`):
60+
`@devframes/hub-ui`'s `createUi()` is the reference (standalone `viewer` SPA + floating dock); its `setup(ctx)` publishes config to `ctx.staticConfig.ui` (`ConnectionMeta.configs.ui`):
6161

6262
- **`branding`** — rebrand the UI (logo, name, primary color).
6363
- **`dockPreferences`** — dock-rail: `categoryOrder`, floating-dock `maxVisibleItems`, first-run `defaultMode` (`'float'`/`'edge'`) and `defaultPosition`.
@@ -80,7 +80,7 @@ initHub({
8080
})
8181
```
8282

83-
A renderer registered at boot (`createDevframeClientHost({ renderers })`) overrides the manifest; an uncovered type shows the viewer's missing-renderer fallback.
83+
A renderer registered at boot (`createDevframeClientHost({ renderers })`) overrides the manifest; an uncovered type shows the hub UI provider's missing-renderer fallback.
8484

8585
Registrations are validated fail-fast: one module per type (`DF8108`), an existing bundle (`DF8109`), a route-safe type name (`DF8110`).
8686

0 commit comments

Comments
 (0)