From c32c72e3dd7b328432f613e891382377bfef46d7 Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Thu, 27 Aug 2026 12:15:47 +0000 Subject: [PATCH] docs: split guide lookup tables into grouped reference pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the Divio documentation system: guide pages teach with prose and code examples; lookup tables (fields, options, enums, statuses, routes) move to three new grouped reference pages — Node-Side API, Browser-Side API, and Hub API. Each guide keeps a prose summary of the essentials plus a link to its reference section; comparison and decision tables stay in the guides as explanation. Codify the split in AGENTS.md. --- AGENTS.md | 9 ++ docs/content/1.guide/10.standalone-cli.md | 8 +- docs/content/1.guide/11.client.md | 30 +--- docs/content/1.guide/12.in-page-channel.md | 11 +- docs/content/1.guide/14.security.md | 19 +-- docs/content/1.guide/15.agent-native.md | 6 +- docs/content/1.guide/16.hub.md | 54 +------ docs/content/1.guide/17.client-context.md | 35 +---- docs/content/1.guide/18.hub-initiate.md | 11 +- docs/content/1.guide/2.devframe-definition.md | 38 +---- .../1.guide/22.build-your-own-hub-ui.md | 17 +- docs/content/1.guide/3.rpc.md | 15 +- docs/content/1.guide/5.streaming.md | 7 +- docs/content/1.guide/6.client-assets.md | 9 +- docs/content/1.guide/9.diagnostics.md | 9 +- docs/content/8.references/4.node-api.md | 147 ++++++++++++++++++ docs/content/8.references/5.browser-api.md | 59 +++++++ docs/content/8.references/6.hub-api.md | 145 +++++++++++++++++ docs/content/8.references/index.md | 7 +- 19 files changed, 400 insertions(+), 236 deletions(-) create mode 100644 docs/content/8.references/4.node-api.md create mode 100644 docs/content/8.references/5.browser-api.md create mode 100644 docs/content/8.references/6.hub-api.md diff --git a/AGENTS.md b/AGENTS.md index dc98f9b3..bb802995 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -211,9 +211,18 @@ Callouts (`> [!NOTE]`, `> [!TIP]`, `> [!INFO]`, `::: tip`, etc.) interrupt the r Trim filler intros, redundant cross-links (one link per page is enough - sidebars handle navigation), and code samples that demonstrate more than the point being made. Lead each page with one sentence that says what the reader can build with this. Strip out promises about future work, marketing language ("powerful", "seamless"), and exposition that the surrounding code already conveys. +### 4. Guides teach, references list + +The docs separate learning material from lookup material, following the [Divio documentation system](https://docs.divio.com/documentation-system/): + +- **Guide pages (`docs/content/1.guide/`) are learning-oriented** - prose, code examples, and explanation. A lookup table (definition fields, options, enums, statuses, event names, route tables) belongs on a references page, with the guide keeping a one-or-two-sentence prose summary of the essentials plus a link to the reference section. Comparison and decision tables ("X vs Y", trade-off matrices) are explanation and stay in the guides; navigational link tables stay on `index.md` pages. +- **The references section (`docs/content/8.references/`) holds the lookup tables**, grouped: [Node-Side API](docs/content/8.references/4.node-api.md), [Browser-Side API](docs/content/8.references/5.browser-api.md), and [Hub API](docs/content/8.references/6.hub-api.md), alongside the terms, when-clauses, and events pages. Each reference section opens with one line naming what the table lists and linking the guide page that teaches it. A new lookup table goes into the matching reference page (and the references `index.md`), not into a guide. +- **The adapters, frameworks, helpers, and plugins sections are per-package reference pages** - each page is the reference for its own adapter/kit/package, so its options and RPC tables stay in place. + ### What goes where - Critical security / data-loss hazard → `[!WARNING]` callout. - Experimental API / stability caveat → `[!WARNING]` callout at the top of the page. - Bad-practice contrast → inline `// ✗ Bad` / `// ✓ Good` comments inside code blocks. +- Lookup table for a guide topic → the matching `docs/content/8.references/` page; the guide keeps a prose summary + link. - Anything else worth saying → prose. diff --git a/docs/content/1.guide/10.standalone-cli.md b/docs/content/1.guide/10.standalone-cli.md index 053c41b7..bd8f8a96 100644 --- a/docs/content/1.guide/10.standalone-cli.md +++ b/docs/content/1.guide/10.standalone-cli.md @@ -279,13 +279,7 @@ version.on('updated', () => fetchPayload().then(setData)) ## Use your own CLI framework -Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps, against one `DevframeDefinition`: - -| Building block | Entry | -|----------------|-------| -| `createDevServer(def, opts?)` | `devframe/adapters/dev` | -| `createBuild(def, opts?)` | `devframe/adapters/build` | -| `createMcpServer(def, opts?)` | `devframe/adapters/mcp` | +Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps against one `DevframeDefinition`: `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`) — see the [CLI adapter](/adapters/cac#use-your-own-cli-framework). ```ts [src/cli.ts] import process from 'node:process' diff --git a/docs/content/1.guide/11.client.md b/docs/content/1.guide/11.client.md index b3cf9f9a..18f79200 100644 --- a/docs/content/1.guide/11.client.md +++ b/docs/content/1.guide/11.client.md @@ -57,16 +57,7 @@ await registerDevframeViewerOrigin(connection) ### Options -| Option | Description | -|--------|-------------| -| `connection` | Connection prepared by `setupDevframeConnection()`. | -| `baseURL` | Mount path to probe for `__connection.json` (array = fallback). Default `'./'` (relative to `document.baseURI`); use an absolute path (`'/__devframe/'`) from outside the SPA. | -| `authToken` | Override the auth token (default: a locally-persisted id). | -| `cacheOptions` | `true` for default caching, or an options object. | -| `callTimeout` | Ms before a pending `rpc.call` rejects with a `'timeout'` `DevframeConnectionError`; `0`/omit = wait forever. | -| `wsOptions` | Transport overrides — `onConnected` / `onError` / `onDisconnected` hooks, socket URL. | -| `rpcOptions` | Forwarded to `birpc`. | -| `connectionMeta` | Descriptor that skips the `__connection.json` fetch. | +`baseURL` points at the mount path to probe for `__connection.json` (default `'./'`, relative to `document.baseURI`); `connection` adopts one prepared by `setupDevframeConnection()`. The rest cover auth (`authToken`), [caching](#caching) (`cacheOptions`), timeouts (`callTimeout`), transport hooks (`wsOptions`), `birpc` passthrough (`rpcOptions`), and discovery override (`connectionMeta`) — every option is in the [Browser-Side API reference](/references/browser-api#connectdevframe-options). ## Modes @@ -256,14 +247,7 @@ const displayUrl = stripRemoteConnectionFromUrl(viewerUrl) ## Events -Emitted over `rpc.events`: - -| Event | Fires when | -|-------|------------| -| `rpc:is-trusted:updated` | Trust granted, denied, or revoked. Carries the new `isTrusted` boolean. | -| `connection:status` | The [connection status](#handling-connection-and-auth-errors) changes. Carries `(status, previous)`. | -| `connection:error` | A connection-level failure — socket error or trust refused. Carries the `Error`. | -| `rpc:error` | An `rpc.call` rejects, from the node side or a down connection. Carries `(error, method)`. | +Four events arrive over `rpc.events`: `rpc:is-trusted:updated` when trust is granted, denied, or revoked; `connection:status` when the [connection status](#handling-connection-and-auth-errors) changes; `connection:error` on a connection-level failure; and `rpc:error` when an `rpc.call` rejects. Payloads are in the [Browser-Side API reference](/references/browser-api#rpc-client-events). ```ts rpc.events.on('rpc:is-trusted:updated', (isTrusted) => { @@ -280,15 +264,7 @@ rpc.events.on('rpc:is-trusted:updated', (isTrusted) => { ### Connection status -`rpc.status` collapses transport and trust into one value; `rpc.connectionError` holds the last connection-level `Error` (`null` when healthy): - -| Status | Meaning | -|--------|---------| -| `connecting` | Establishing socket / handshake. Calls queue until open. | -| `connected` | Socket open and trusted; calls are served. | -| `unauthorized` | Socket open, trust refused. Prompt for [authentication](#authenticating-with-a-one-time-code). | -| `disconnected` | Socket closed (dropped mid-session or never opened). | -| `error` | Fatal — the socket errored or connection meta couldn't load. | +`rpc.status` collapses transport and trust into one value; `rpc.connectionError` holds the last connection-level `Error` (`null` when healthy). It moves through `connecting` (calls queue until open), `connected` (calls are served), `unauthorized` (socket open, trust refused — prompt for [authentication](#authenticating-with-a-one-time-code)), `disconnected`, and `error`; each value's meaning is in the [Browser-Side API reference](/references/browser-api#connection-statuses). A `static` backend has no live socket, so `rpc.status` stays `connected`. diff --git a/docs/content/1.guide/12.in-page-channel.md b/docs/content/1.guide/12.in-page-channel.md index bf2ca5f9..0f43b138 100644 --- a/docs/content/1.guide/12.in-page-channel.md +++ b/docs/content/1.guide/12.in-page-channel.md @@ -123,16 +123,7 @@ Without an `initialValue`, a panel's `get` resolves once the first replay arrive ## Errors and fallbacks -Every failure mode is a coded `InPageChannelError` (`error.code`) with a message that explains itself: - -| Code | When | What to do | -|------|------|------------| -| `timeout` | A call outlived `callTimeoutMs` (default 15s), or `whenConnected(ms)` expired | The message carries the endpoint status — `connecting` usually means the page script isn't loaded in this context | -| `closed` | The endpoint was closed with calls pending | Expected during teardown | -| `not-serializable` | A `jsonSerializable: true` payload contained a non-JSON value | The message names the offending path (e.g. `its arguments[0].nodes[2]` is a Map) | -| `not-cloneable` | The port refused to clone a payload (`DataCloneError`) | Strip functions/DOM nodes/reactivity proxies — or declare `jsonSerializable: true` for the precise error above | -| `invalid-args` | Incoming arguments failed their Standard-Schema validation | The message lists the schema issues | -| `state-uninitialized` | The page script read a shared state before providing its `initialValue` | Initialize on first access | +Every failure mode is a coded `InPageChannelError` (`error.code`) with a message that explains itself: `timeout` (a call or `whenConnected(ms)` outlived its deadline), `closed` (endpoint torn down with calls pending), `not-serializable` / `not-cloneable` (a payload the port can't carry — the message names the offending path), `invalid-args` (Standard-Schema validation failed), and `state-uninitialized` (a shared state read before its `initialValue`). Causes and fixes per code are in the [Browser-Side API reference](/references/browser-api#in-page-channel-error-codes). The panel endpoint's connection lifecycle is explicit, so a panel renders a useful fallback instead of hanging: diff --git a/docs/content/1.guide/14.security.md b/docs/content/1.guide/14.security.md index a3f0d335..e953731d 100644 --- a/docs/content/1.guide/14.security.md +++ b/docs/content/1.guide/14.security.md @@ -51,22 +51,9 @@ Pass `clientAuthTokens` for CI/shared machines to skip the prompt, or a custom ` ### Auth methods -| RPC method | Direction | Shape | -|------------|-----------|-------| -| `anonymous:devframe:auth` | client → server | `{ authToken, ua, origin }` → `{ isTrusted }` — re-authenticate a stored token | -| `anonymous:devframe:auth:exchange` | client → server | `{ code, ua, origin }` → `{ authToken \| null }` — exchange a code for a token | -| `devframe:auth:revoke` | client → server | self-revoke the caller's own token | -| `devframe:auth:revoked` | server → client | event — token revoked | - -Node primitives (`devframe/node/auth`): - -| Function | Role | -|----------|------| -| `getTempAuthCode()` / `refreshTempAuthCode()` | read / rotate the one-time code | -| `exchangeTempAuthCode(code, session, { ua, origin }, storage)` | verify a code, mint + store the token, trust the session, return it (or `null`) | -| `verifyAuthToken(token, session, storage)` | trust a session presenting a known token | -| `buildOtpAuthUrl(origin, code?)` | build a magic-link URL embedding the code | -| `revokeAuthToken(context, storage, token)` | delete a token and disconnect sessions using it | +The two `anonymous:`-prefixed handshake methods re-authenticate a stored token (`anonymous:devframe:auth`) and exchange a one-time code for a token (`anonymous:devframe:auth:exchange`); `devframe:auth:revoke` self-revokes, and the `devframe:auth:revoked` event drops affected RPC clients to untrusted. Wire shapes are in the [Node-Side API reference](/references/node-api#auth-methods). + +Node primitives in `devframe/node/auth` — `getTempAuthCode` / `refreshTempAuthCode`, `exchangeTempAuthCode`, `verifyAuthToken`, `buildOtpAuthUrl`, and `revokeAuthToken` — implement the same flow for a host framework wiring its own gate; signatures are in the [reference](/references/node-api#node-auth-primitives). RPC client methods (`devframe/client`): `requestTrustWithCode(code)`, `requestTrustWithToken(token)`, and `ensureTrusted(timeout?)` / `isTrusted` (the trust gate). diff --git a/docs/content/1.guide/15.agent-native.md b/docs/content/1.guide/15.agent-native.md index c10cae2d..d6363336 100644 --- a/docs/content/1.guide/15.agent-native.md +++ b/docs/content/1.guide/15.agent-native.md @@ -183,8 +183,4 @@ Prefer coded diagnostics anywhere agent-reachable: agents act on `fix` and follo ## CLI -| Command | Description | -|---------|-------------| -| ` mcp` | Start the MCP server on `stdio`. | -| ` dev --mcp` | Serve the agent-consumable API on `/__mcp`. | -| `devframe connect` | Discover running devframes and proxy their tools — see [MCP adapter](/adapters/mcp#discovery-devframe-connect). | +` mcp` starts the MCP server on `stdio`; ` dev --mcp` serves the agent-consumable API on `/__mcp`; `devframe connect` discovers running devframes and proxies their tools ([MCP adapter](/adapters/mcp#discovery-devframe-connect)). The command table is in the [Node-Side API reference](/references/node-api#mcp-cli-commands). diff --git a/docs/content/1.guide/16.hub.md b/docs/content/1.guide/16.hub.md index bd04fa69..2bd175e9 100644 --- a/docs/content/1.guide/16.hub.md +++ b/docs/content/1.guide/16.hub.md @@ -13,14 +13,7 @@ _Orchestrating multiple devtools (from [A Playground](https://github.com/devfram ## What the hub adds -`DevframeHubContext` adds four subsystems to `DevframeNodeContext`: - -| Subsystem | API | Purpose | -|---|---|---| -| `ctx.docks` | `register / update / values / activate` | Dock entries (iframes, launchers, custom-render) and groups; `activate(dockId, params?)` sets the active dock ([Cross-iframe dock activation](#cross-iframe-dock-activation)). | -| `ctx.terminals` | `register / startChildProcess` | Aggregate terminal sessions, streaming output ([Terminals](/plugins/terminals#hub-aggregation)). | -| `ctx.messages` | `add / update / remove / clear` | Server-side toast/notification queue (FIFO, capped at 1000). | -| `ctx.commands` | `register / execute / list` | Hierarchical command palette with keybindings and `when` clauses. | +`DevframeHubContext` adds four subsystems to `DevframeNodeContext`: `ctx.docks` registers dock entries and groups and [activates docks](#cross-iframe-dock-activation); `ctx.terminals` aggregates terminal sessions with streaming output ([Terminals](/plugins/terminals#hub-aggregation)); `ctx.messages` is the server-side toast/notification queue; `ctx.commands` is the hierarchical command palette with keybindings and `when` clauses. Each subsystem's API is in the [Hub API reference](/references/hub-api#hub-subsystems). Data-driven UI panels are an opt-in [JSON-Render](/guide/json-render) package (a `json-render` dock type). @@ -69,13 +62,7 @@ It mirrors into the `devframe:docks:active` shared-state slot; the [terminals do ## Process-control launchers -A `type: 'launcher'` dock entry is a one-click action tile. Three optional `launcher` fields make it a live process controller: - -| Field | Purpose | -|---|---| -| `command` | Bound command id; out-of-process hub UI providers dispatch via `hub:commands:execute` (register a handler via `ctx.commands`). | -| `terminalSessionId` | Tracked session id; a "view in terminal" action calls `hub:docks:activate` with the terminals dock id and `{ sessionId }`. | -| `digest` | Latest progress line, shown inline; patch via `docks.update()`. | +A `type: 'launcher'` dock entry is a one-click action tile. Three optional `launcher` fields make it a live process controller: `command` binds a command id dispatched via `hub:commands:execute`, `terminalSessionId` links a tracked session for a "view in terminal" action, and `digest` shows the latest progress line inline ([Hub API reference](/references/hub-api#launcher-fields)). `onLaunch` lets a same-process host framework invoke directly; provide `command`, `onLaunch`, or both. @@ -173,14 +160,7 @@ export default { skipTrailingSlashRedirect: true } ### Duplicate devframes -When a devframe shares an already-mounted `id`, `duplicationStrategy` decides: - -| Strategy | Behavior | -|---|---| -| `'warn'` (default) | Keep the first, drop the later, emit `DF8105`. | -| `'silent'` | Drop the later one without warning. | -| `'throw'` | Throw `DF8105`. | -| `'duplicate'` | Every instance coexists under a disambiguated dock id (`my-tool`, `my-tool-2`, …). | +When a devframe shares an already-mounted `id`, `duplicationStrategy` decides: `'warn'` (the default) keeps the first and drops the later with [`DF8105`](/errors/DF8105), `'silent'` drops it quietly, `'throw'` raises, and `'duplicate'` lets every instance coexist under disambiguated dock ids ([Hub API reference](/references/hub-api#duplication-strategies)). ```ts defineDevframe({ @@ -222,35 +202,13 @@ Group and members stay independent top-level entries in `devframe:docks`. Activa #### Known categories -`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default buckets: - -| Category | Weight | Typical use | -|---|---|---| -| `framework` | `-100` | Framework internals. | -| `default` | `0` | Uncategorized. | -| `app` | `100` | App tools. | -| `ui` | `150` | Components, styling. | -| `data` | `250` | State, storage, queries. | -| `web` | `300` | Network, platform, a11y. | -| `performance` | `350` | Profiling, metrics. | -| `advanced` | `400` | Power-user tools. | -| `docs` | `500` | Documentation. | -| `~builtin` | `1000` | Built-in views; always last. | +`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default buckets, running from `framework` (weight `-100`) through `default`, `app`, `ui`, `data`, `web`, `performance`, `advanced`, and `docs` to `~builtin` (always last). The weight table is in the [Hub API reference](/references/hub-api#dock-categories). Framework kits can interleave category ids or override weights; an unknown category sorts as `0`. -## The protocol — what the hub UI provider sees - -A hub UI provider imports no hub classes; it reads these shared-state keys and RPC methods: +## The hub UI protocol -| Channel | Type | What it carries | -|---|---|---| -| `devframe:docks` shared state | `DevframeDockEntry[]` | Every registered dock entry. | -| `devframe:commands` shared state | `DevframeServerCommandEntry[]` | Serializable command list (handlers stripped). | -| `devframe:user-settings` shared state | `DevframeDocksUserSettings` | Persisted project-scope hub settings. | -| `devframe:docks:active` shared state | `DevframeDocksActiveState` | Most recent [dock activation](#cross-iframe-dock-activation) request. | -| `hub:commands:execute` RPC | `(id, ...args) => unknown` | Server-side command dispatch. | -| `hub:docks:activate` RPC | `({ dockId, params? }) => void` | Switch the active dock. | +A hub UI provider imports no hub classes; it renders from four shared-state slots — `devframe:docks` (every registered dock entry), `devframe:commands` (the serializable command list), `devframe:user-settings` (persisted hub settings), and `devframe:docks:active` (the most recent [dock activation](#cross-iframe-dock-activation) request) — and dispatches through two RPC methods, `hub:commands:execute` and `hub:docks:activate`. Types and payloads are in the [Hub API reference](/references/hub-api#hub-ui-protocol). Broadcast notifications (`devframe:docks:activate`, `devframe:terminals:updated`, `devframe:messages:updated`) arrive via `rpc.client.register(...)`; the client runtime registers `devframe:docks:activate` for you ([Events Reference](/references/events)). diff --git a/docs/content/1.guide/17.client-context.md b/docs/content/1.guide/17.client-context.md index be8ac3e8..4bc5910f 100644 --- a/docs/content/1.guide/17.client-context.md +++ b/docs/content/1.guide/17.client-context.md @@ -24,28 +24,13 @@ const { context, dispose } = await createDevframeClientRuntime({ rpc }) ### Options -| Option | Description | -|--------|-------------| -| `rpc` | An already-connected `DevframeRpcClient`; when omitted, created via `connectDevframe(connect)`. | -| `connect` | Forwarded to `connectDevframe` when `rpc` is omitted (e.g. `baseURL`). | -| `clientType` | `'standalone'` (default) — owns the page; `'embedded'` — inside a user app alongside a panel. | -| `loadClientScripts` | Import and run dock client scripts (default `true`). | -| `renderers` | Dock renderers registered at boot, keyed by dock `type`; local wins over the hub's [renderer manifest](/guide/hub-initiate#renderer-modules). | +Pass an already-connected `rpc` (or `connect` options for `connectDevframe`), the page's `clientType` (`'standalone'` by default, `'embedded'` inside a user app), `loadClientScripts: false` to skip dock client scripts, and boot-time `renderers` (which win over the hub's [renderer manifest](/guide/hub-initiate#renderer-modules)) — see the [Hub API reference](/references/hub-api#client-runtime-options). A second boot replaces the context and warns; `dispose()` tears down listeners and unpublishes it. ## The client context -| Property | Description | -|----------|-------------| -| `rpc` | The [RPC client](/guide/client) — server/client functions, shared state. | -| `clientType` | `'embedded'` (inside the user app) or `'standalone'` (independent hub page). | -| `docks` | `entries`, `selected`, `groupedEntries`, `switchEntry()`, `toggleEntry()`, `getStateById()`, `register()` / `update()` for [client-only docks](#client-only-docks). | -| `panel` | Dock panel state: position, size, drag/resize. | -| `commands` | Command palette: `register()`, `execute()`, `getKeybindings()`. | -| `renderers` | Dock-renderer registry — `register()`, `get()`, `has()`, `mount(entry, container)`. Routes a dock `type` to a renderer (local boot or the hub's [manifest](/guide/hub-initiate#renderer-modules); local wins). `mount()` resolves a `status`: `mounted` (with `dispose`), `missing-renderer`, or `load-error` (with `error`). | -| `when` | The [when-clause](/references/when-clauses) context. | -| `connection` | Live [connection status](/guide/client#handling-connection-and-auth-errors) — `status`, `error`, `events`. | +The context carries the [RPC client](/guide/client) (`rpc`) and the page's `clientType`, plus six hub facets: `docks` (entries, selection, [client-only registration](#client-only-docks)), `panel` (dock panel state), `commands` (the command palette), `renderers` (the dock-renderer registry), `when` (the [when-clause](/references/when-clauses) context), and `connection` (live [connection status](/guide/client#handling-connection-and-auth-errors)). Every property is in the [Hub API reference](/references/hub-api#client-context-properties). ### Accessing the context @@ -59,13 +44,7 @@ A client-only dock can also carry `type: 'json-render'` with an inline [JSON-ren ## Dock client scripts -A client script is a `ClientScriptEntry` — `{ importFrom, importName? }` (`importName` defaults `'default'`); the field varies by entry kind: - -| Entry kind | Field | Runs | -|---|---|---| -| `action` | `action` | when the dock button is activated | -| `custom-render` | `renderer` | to render the entry's panel | -| `iframe` | `clientScript` (optional) | alongside the iframe panel, inside the host page | +A client script is a `ClientScriptEntry` — `{ importFrom, importName? }` (`importName` defaults `'default'`). The field varies by entry kind: an `action` entry's `action` runs when the dock button is activated, a `custom-render` entry's `renderer` renders its panel, and an `iframe` entry's optional `clientScript` runs alongside the iframe panel inside the host page ([Hub API reference](/references/hub-api#dock-client-script-fields)). The exported function (`DockClientScriptContext`) receives the client context and two dock-scoped extras: @@ -99,13 +78,7 @@ Dock iframes are their own documents: the panel calls `connectDevframe()`, disco ## Shared-iframe soft navigation -A tool with many internal views (Nuxt DevTools' tabs) can surface each as a hub dock sharing **one** live iframe — the **anchor** owns a `frameId` and opts in via `ctx.install(…, { dock: { frameId, subTabs: { protocol: 'postmessage' } } })`. On mount, the client runtime attaches a **frame-nav adapter** speaking an origin-locked `postMessage` protocol on `devframe:frame-nav`. - -| Message | Direction | Meaning | -|---|---|---| -| `ready` / `manifest` | iframe → host page | tab list (`{ tabs, current }`), on load and change | -| `navigate` | host page → iframe | show a view (`{ tabId, navTarget }`); the SPA routes client-side | -| `navigated` | iframe → host page | the SPA navigated internally; the hub UI provider highlights the dock | +A tool with many internal views (Nuxt DevTools' tabs) can surface each as a hub dock sharing **one** live iframe — the **anchor** owns a `frameId` and opts in via `ctx.install(…, { dock: { frameId, subTabs: { protocol: 'postmessage' } } })`. On mount, the client runtime attaches a **frame-nav adapter** speaking an origin-locked `postMessage` protocol on `devframe:frame-nav`: the iframe reports its tab list (`ready` / `manifest`), the host page requests a view (`navigate`), and the iframe reports internal navigation back (`navigated`). Message shapes are in the [Hub API reference](/references/hub-api#frame-nav-messages). It materializes a [client-only dock](#client-only-docks) per tab (id `:`) sharing the anchor's `frameId` and a `navTarget`, independent of [`groupId`](/guide/hub#grouping-dock-entries). diff --git a/docs/content/1.guide/18.hub-initiate.md b/docs/content/1.guide/18.hub-initiate.md index c8685810..55c786cd 100644 --- a/docs/content/1.guide/18.hub-initiate.md +++ b/docs/content/1.guide/18.hub-initiate.md @@ -33,16 +33,7 @@ The advertised path is hub-base-absolute (`/__devframes/__ws`). Dev-reevaluated ## The namespace -| Path | Serves | -| --- | --- | -| `/` | the `ui.viewer` SPA, or index document when headless | -| `/` | each devframe's SPA + own `__connection.json` → shared socket | -| `embedded.js` | the `ui.embedded` bootstrap (`404` if none) | -| `__connection.json` | meta for the shared RPC socket | -| `__ws` | WebSocket upgrade route | -| `__index.json` | machine-readable index: mounted devframes, endpoints | -| `__client-imports.js` | dock client-script import map for hub UI providers | -| `__mcp` | aggregate MCP endpoint over the tool registry (opt-in `mcp`) | +The namespace serves the hub UI at `/` (the `ui.viewer` SPA, or an index document when headless) and each devframe's SPA at `/` with its own `__connection.json` pointing at the shared socket. Hub-level endpoints sit alongside: `embedded.js` (the `ui.embedded` bootstrap), `__connection.json`, `__ws`, `__index.json`, `__client-imports.js`, and the opt-in `__mcp`. The route table is in the [Hub API reference](/references/hub-api#hub-namespace-routes). Devframe ids become URL segments, validated: reserved names throw `DF8000`, non-route-safe `DF8004`. diff --git a/docs/content/1.guide/2.devframe-definition.md b/docs/content/1.guide/2.devframe-definition.md index f9b60cd6..3316e1e1 100644 --- a/docs/content/1.guide/2.devframe-definition.md +++ b/docs/content/1.guide/2.devframe-definition.md @@ -39,24 +39,7 @@ export default defineDevframe({ ## Definition fields -| Field | Type | Description | -|-------|------|-------------| -| `id` | `string` | **Required.** Unique namespaced id (kebab-case); prefixes RPC/dock/MCP-tool names. | -| `name` | `string` | **Required.** Display name (dock, agent manifests). | -| `version` | `string` | **Required.** Semver; shown in hub UIs, diagnostics. | -| `packageName` | `string` | **Required.** npm package (`@scope/my-tool`). | -| `importMetaUrl` | `string` | **Recommended.** Pass `import.meta.url` — the deps resolution base: default `resolveFrom` for [remote assets](/guide/client-assets) and declared [services](/guide/services#wire-services). | -| `homepage` | `string` | **Required.** Homepage/docs URL. | -| `description` | `string` | **Required.** One-line summary. | -| `icon` | `string \| { light, dark }` | Optional Iconify name or URL; light/dark pairs. | -| `basePath` | `string` | Optional mount-path override. Default `/` standalone (`cli`/`build`), `/__/` hosted (`vite`/`embedded`). | -| `duplicationStrategy` | `'warn' \| 'silent' \| 'throw' \| 'duplicate'` | Hub reaction when another devframe shares this `id`. Default `'warn'`. See [Hub](/guide/hub); standalone adapters ignore it. | -| `capabilities` | `{ dev?, build? }` | Per-runtime feature flags. `boolean` = whole runtime; object = individual features. | -| `services` | `DevframeServiceInput[]` | Wire services consumed — descriptors (`{ package, version?, required?, options? }`) imported against the devframe's own deps, or ready definitions. See [Cross-Devframe Services](/guide/services#wire-services). | -| `clientAssets` | `string \| RemoteAssets` | Built SPA served as the UI — local dist dir or [remote assets](/guide/client-assets). Read by every UI-serving adapter (`dev`, `build`, `vite`, `next`, hub). | -| `rpc` | `{ snapshot?: (string \| { method, inputs })[] }` | RPC config. `rpc.snapshot` opts an RPC this devframe doesn't own into the static dump. Bare method id bakes the no-arg call; `{ method, inputs }` bakes one record per argument-tuple (`inputs` = tuples or async `(ctx) => tuples`). First tuple = fallback. | -| `setup` | `(ctx, info?) => void \| Promise` | **Required.** Server-side entry point, run in every runtime. Optional 2nd arg carries runtime metadata — notably parsed CLI `flags` under `createCac`. | -| `cli` | `DevframeCliOptions` | CLI adapter defaults. See [CLI options](#cli-options). | +`id`, `name`, `version`, `packageName`, `homepage`, `description`, and `setup` are required; pass `importMetaUrl: import.meta.url` so [remote assets](/guide/client-assets) and declared [services](/guide/services#wire-services) resolve against the devframe's own dependencies. The remaining fields cover display (`icon`), mounting (`basePath`, `duplicationStrategy`, `capabilities`), what the devframe consumes and serves (`services`, `clientAssets`, `rpc.snapshot`), and [CLI defaults](#cli-options) (`cli`). Every field is listed in the [Node-Side API reference](/references/node-api#definition-fields). ### Sourcing metadata from `package.json` @@ -184,13 +167,7 @@ ctx.staticConfig['my-plugin'] = { featureFlag: true } ### Storage scopes -`ctx.host.getStorageDir(scope)` places persisted state in three classes: - -| Scope | Placement | For | -|-------|-----------|-----| -| `workspace` | committable, `/.devframe/` | team-shared: saved presets, config | -| `project` | per-checkout, `/node_modules/./devframe/` | caches, personal settings | -| `global` | per-user, `~/./devframe/` | auth tokens, machine-wide prefs | +`ctx.host.getStorageDir(scope)` places persisted state in three classes: `workspace` is committable and team-shared (saved presets, config), `project` is per-checkout (caches, personal settings), and `global` is per-user (auth tokens, machine-wide prefs). Placements are in the [Node-Side API reference](/references/node-api#storage-scopes). `ctx.scope(id)` returns a namespace-scoped view ([Scoped Context](/guide/scoped-context)) auto-prefixing every RPC id, shared-state key, and streaming channel, plus a persisted `settings` store (`project`/`global` scopes use the matching storage classes). @@ -225,16 +202,7 @@ defineDevframe({ }) ``` -| Field | Type | Description | -|-------|------|-------------| -| `command` | `string` | Binary name in `--help`. Default: the `id`. | -| `port` | `number` | Preferred dev-server port. | -| `portRange` | `[number, number]` | Port scan range (`get-port-please`). | -| `random` | `boolean` | Prefer a random open port. | -| `host` | `string` | Default bind host. | -| `open` | `boolean \| string` | `true` = origin, string = a path, `false` = off (`--open`/`--no-open`). With `auth`, embeds the OTP. | -| `auth` | `boolean` | Disable WS trust flow when localhost-only, single-user. Default `true`. | -| `configure` | `(cli: CAC) => void` | Contribute flags/commands before `createCac`'s `configureCli`. | +Beyond the fields shown, `random` prefers a random open port and `auth: false` disables the WS trust flow for localhost-only, single-user tools. Every field is listed in the [Node-Side API reference](/references/node-api#cli-options). ## Multiple runtimes, one definition diff --git a/docs/content/1.guide/22.build-your-own-hub-ui.md b/docs/content/1.guide/22.build-your-own-hub-ui.md index a121d50d..a1a10f61 100644 --- a/docs/content/1.guide/22.build-your-own-hub-ui.md +++ b/docs/content/1.guide/22.build-your-own-hub-ui.md @@ -37,16 +37,13 @@ and loads dock client scripts. Honor: ### Dock entry types Render the built-in variants of the open dock union -(`DevframeDockEntryRegistry`, `@devframes/hub/types`): - -| Type | The hub UI provider renders | -|---|---| -| `iframe` | the entry's `url` in a kept-alive iframe (per `frameId` when shared); honor `subTabs` soft nav | -| `action` | a dock-rail button; activating runs its client script | -| `custom-render` | a container its client script mounts into | -| `launcher` | a launch call-to-action reflecting `launcher.status` | -| `group` | one dock-rail button collapsing its member entries | -| `~builtin` | your native views (settings, feeds) for reserved ids | +(`DevframeDockEntryRegistry`, `@devframes/hub/types`): `iframe` (the entry's +`url` in a kept-alive iframe, honoring `subTabs` soft nav), `action` (a +dock-rail button running its client script), `custom-render` (a container its +client script mounts into), `launcher` (a launch call-to-action reflecting +`launcher.status`), `group` (one dock-rail button collapsing its members), and +`~builtin` (your native views for reserved ids). What to render per type is in +the [Hub API reference](/references/hub-api#dock-entry-types). Honor `when` / `visibility`, `category` grouping (order from `DEFAULT_CATEGORIES_ORDER`, `@devframes/hub/constants`), and the diff --git a/docs/content/1.guide/3.rpc.md b/docs/content/1.guide/3.rpc.md index daa1270d..0765de9d 100644 --- a/docs/content/1.guide/3.rpc.md +++ b/docs/content/1.guide/3.rpc.md @@ -49,12 +49,7 @@ Scope with your devframe id, then a kebab-case action: `my-tool:get-modules`. ### Function types -| Type | Description | Cached | Static Dump | -|------|-------------|--------|-------------| -| `query` | Read operation that can change over time. | Opt-in via `cacheable` | Manual (declare `dump`) | -| `static` | Data that never changes for a given input. | Indefinitely | Automatic | -| `action` | Mutation with side effects. | Never | Never | -| `event` | Fire-and-forget; no response. | Never | Never | +A function's `type` sets its caching and [static-dump](#static-dumps) behavior: `query` for reads that change over time (caching opt-in via `cacheable`, dumping via an explicit `dump`), `static` for data fixed per input (cached indefinitely, dumped automatically), `action` for mutations, and `event` for fire-and-forget notifications. The full matrix is in the [Node-Side API reference](/references/node-api#rpc-function-types). ### Handler arguments @@ -84,13 +79,7 @@ defineDevframe({ }) ``` -| Option | Type | Description | -|--------|------|-------------| -| `method` | browser-side RPC name | Browser-side function to call. | -| `args` | any[] | Arguments for the browser-side function. | -| `optional` | `boolean` | Don't throw if no RPC client is listening. | -| `event` | `boolean` | Fire-and-forget. | -| `filter` | `(client) => boolean` | Skip specific RPC clients. | +Beyond `method` and `args`, `optional` skips throwing when no RPC client is listening, `event` makes the broadcast fire-and-forget, and `filter` skips specific RPC clients — see the [Node-Side API reference](/references/node-api#broadcast-options). ## Streaming diff --git a/docs/content/1.guide/5.streaming.md b/docs/content/1.guide/5.streaming.md index 53a26b68..6876c0d4 100644 --- a/docs/content/1.guide/5.streaming.md +++ b/docs/content/1.guide/5.streaming.md @@ -120,12 +120,7 @@ reader.cancel() // sends cancel upstream; the node-side stream.signal flips ## Lifecycle and cancellation -| Event | Node side | Browser side | -|-------|--------|--------| -| `stream.close()` / `stream.error(err)` | broadcasts `end` | `for await` resolves or throws | -| `reader.cancel()` | aborts `stream.signal` on **last**-subscriber cancel | `for await` ends | -| WS disconnects | aborts `stream.signal` on **last**-subscriber drop | reader survives, resubscribes on re-trust | -| `chat` panel closes | cancels upstream | — | +`stream.close()` / `stream.error(err)` broadcast `end`, resolving (or throwing inside) the browser-side `for await`. Cancellation flows upstream: `reader.cancel()` — or the **last** subscriber's WS dropping — aborts `stream.signal`; a disconnected reader survives and resubscribes on re-trust. The event-by-event matrix is in the [Node-Side API reference](/references/node-api#streaming-lifecycle). ## Browser-to-node uploads diff --git a/docs/content/1.guide/6.client-assets.md b/docs/content/1.guide/6.client-assets.md index 92887636..6107159d 100644 --- a/docs/content/1.guide/6.client-assets.md +++ b/docs/content/1.guide/6.client-assets.md @@ -98,14 +98,7 @@ Per request, resolution tries in order: ### Options -| Field | Purpose | -|-------|---------| -| `package` | npm package with the built assets. | -| `version` | Exact version, usually your `pkg.version`. | -| `resolveFrom` | Local-path resolution base. Defaults to `importMetaUrl`; `null` skips to cache + CDN. | -| `path` | Subpath the assets live under (default `dist`). | -| `provider` | `'jsdelivr'` (default), `'unpkg'`, or a custom provider (internal mirror). | -| `offline` | `true` serves only from local install or cache, never network. | +`package` and `version` (exact) name the published assets; `resolveFrom`, `path`, `provider`, and `offline` tune resolution — every field is in the [Node-Side API reference](/references/node-api#remote-assets-options). An invalid npm name or non-exact version throws [`DF0065`](/errors/DF0065). diff --git a/docs/content/1.guide/9.diagnostics.md b/docs/content/1.guide/9.diagnostics.md index 75752560..666c167b 100644 --- a/docs/content/1.guide/9.diagnostics.md +++ b/docs/content/1.guide/9.diagnostics.md @@ -64,14 +64,7 @@ export function MyPlugin(): PluginWithDevTools { Codes are a 4-letter prefix + 4-digit number (e.g. `MYP0001`); pick one distinctive enough to avoid collisions. -Prefixes in use: - -| Prefix | Owner | -|--------|-------| -| `DF` | `devframe` | -| `DTK` | `@vitejs/devtools` (Vite-specific) | -| `RDDT` | `@vitejs/devtools-rolldown` | -| `VDT` | `@vitejs/devtools-vite` (reserved) | +`DF` belongs to `devframe` itself; the `@vitejs/devtools` packages own `DTK`, `RDDT`, and `VDT`. The prefixes in use are listed in the [Node-Side API reference](/references/node-api#diagnostic-code-prefixes). A definition takes a `why` (message) and optional `fix` (resolution), string or function; `docsBase` auto-attaches the URL to each diagnostic. diff --git a/docs/content/8.references/4.node-api.md b/docs/content/8.references/4.node-api.md new file mode 100644 index 00000000..09fcd82a --- /dev/null +++ b/docs/content/8.references/4.node-api.md @@ -0,0 +1,147 @@ +--- +title: 'Node-Side API' +navigation: + icon: i-lucide-server-cog +description: 'Lookup tables for the node side: DevframeDefinition fields, CLI options, storage scopes, RPC function types, broadcast options, streaming lifecycle, remote assets, diagnostics prefixes, and the auth surface.' +--- + +Lookup tables for a devframe's node side. Each section links the guide page that teaches the concept. + +## Definition fields + +The fields of a `DevframeDefinition` — [Devframe Definition](/guide/devframe-definition). + +| Field | Type | Description | +|-------|------|-------------| +| `id` | `string` | **Required.** Unique namespaced id (kebab-case); prefixes RPC/dock/MCP-tool names. | +| `name` | `string` | **Required.** Display name (dock, agent manifests). | +| `version` | `string` | **Required.** Semver; shown in hub UIs, diagnostics. | +| `packageName` | `string` | **Required.** npm package (`@scope/my-tool`). | +| `importMetaUrl` | `string` | **Recommended.** Pass `import.meta.url` — the deps resolution base: default `resolveFrom` for [remote assets](/guide/client-assets) and declared [services](/guide/services#wire-services). | +| `homepage` | `string` | **Required.** Homepage/docs URL. | +| `description` | `string` | **Required.** One-line summary. | +| `icon` | `string \| { light, dark }` | Optional Iconify name or URL; light/dark pairs. | +| `basePath` | `string` | Optional mount-path override. Default `/` standalone (`cli`/`build`), `/__/` hosted (`vite`/`embedded`). | +| `duplicationStrategy` | `'warn' \| 'silent' \| 'throw' \| 'duplicate'` | Hub reaction when another devframe shares this `id`. Default `'warn'`. See [Duplication strategies](/references/hub-api#duplication-strategies); standalone adapters ignore it. | +| `capabilities` | `{ dev?, build? }` | Per-runtime feature flags. `boolean` = whole runtime; object = individual features. | +| `services` | `DevframeServiceInput[]` | Wire services consumed — descriptors (`{ package, version?, required?, options? }`) imported against the devframe's own deps, or ready definitions. See [Cross-Devframe Services](/guide/services#wire-services). | +| `clientAssets` | `string \| RemoteAssets` | Built SPA served as the UI — local dist dir or [remote assets](/guide/client-assets). Read by every UI-serving adapter (`dev`, `build`, `vite`, `next`, hub). | +| `rpc` | `{ snapshot?: (string \| { method, inputs })[] }` | RPC config. `rpc.snapshot` opts an RPC this devframe doesn't own into the static dump. Bare method id bakes the no-arg call; `{ method, inputs }` bakes one record per argument-tuple (`inputs` = tuples or async `(ctx) => tuples`). First tuple = fallback. | +| `setup` | `(ctx, info?) => void \| Promise` | **Required.** Server-side entry point, run in every runtime. Optional 2nd arg carries runtime metadata — notably parsed CLI `flags` under `createCac`. | +| `cli` | `DevframeCliOptions` | CLI adapter defaults. See [CLI options](#cli-options). | + +## CLI options + +The `cli` field's `DevframeCliOptions` — [CLI options](/guide/devframe-definition#cli-options). + +| Field | Type | Description | +|-------|------|-------------| +| `command` | `string` | Binary name in `--help`. Default: the `id`. | +| `port` | `number` | Preferred dev-server port. | +| `portRange` | `[number, number]` | Port scan range (`get-port-please`). | +| `random` | `boolean` | Prefer a random open port. | +| `host` | `string` | Default bind host. | +| `open` | `boolean \| string` | `true` = origin, string = a path, `false` = off (`--open`/`--no-open`). With `auth`, embeds the OTP. | +| `auth` | `boolean` | Disable WS trust flow when localhost-only, single-user. Default `true`. | +| `configure` | `(cli: CAC) => void` | Contribute flags/commands before `createCac`'s `configureCli`. | + +## Storage scopes + +The three classes `ctx.host.getStorageDir(scope)` places persisted state in — [Storage scopes](/guide/devframe-definition#storage-scopes). + +| Scope | Placement | For | +|-------|-----------|-----| +| `workspace` | committable, `/.devframe/` | team-shared: saved presets, config | +| `project` | per-checkout, `/node_modules/./devframe/` | caches, personal settings | +| `global` | per-user, `~/./devframe/` | auth tokens, machine-wide prefs | + +## RPC function types + +The `type` field of `defineRpcFunction` — [RPC](/guide/rpc). + +| Type | Description | Cached | Static Dump | +|------|-------------|--------|-------------| +| `query` | Read operation that can change over time. | Opt-in via `cacheable` | Manual (declare `dump`) | +| `static` | Data that never changes for a given input. | Indefinitely | Automatic | +| `action` | Mutation with side effects. | Never | Never | +| `event` | Fire-and-forget; no response. | Never | Never | + +## Broadcast options + +The options of `rpc.broadcast` — [Broadcasting](/guide/rpc#broadcasting). + +| Option | Type | Description | +|--------|------|-------------| +| `method` | browser-side RPC name | Browser-side function to call. | +| `args` | any[] | Arguments for the browser-side function. | +| `optional` | `boolean` | Don't throw if no RPC client is listening. | +| `event` | `boolean` | Fire-and-forget. | +| `filter` | `(client) => boolean` | Skip specific RPC clients. | + +## Streaming lifecycle + +How each lifecycle event lands on both sides of a streaming channel — [Streaming](/guide/streaming#lifecycle-and-cancellation). + +| Event | Node side | Browser side | +|-------|--------|--------| +| `stream.close()` / `stream.error(err)` | broadcasts `end` | `for await` resolves or throws | +| `reader.cancel()` | aborts `stream.signal` on **last**-subscriber cancel | `for await` ends | +| WS disconnects | aborts `stream.signal` on **last**-subscriber drop | reader survives, resubscribes on re-trust | +| `chat` panel closes | cancels upstream | — | + +## Remote assets options + +The fields of a `RemoteAssets` source for `clientAssets` and `hostStatic` — [Remote assets](/guide/client-assets#remote-assets). + +| Field | Purpose | +|-------|---------| +| `package` | npm package with the built assets. | +| `version` | Exact version, usually your `pkg.version`. | +| `resolveFrom` | Local-path resolution base. Defaults to `importMetaUrl`; `null` skips to cache + CDN. | +| `path` | Subpath the assets live under (default `dist`). | +| `provider` | `'jsdelivr'` (default), `'unpkg'`, or a custom provider (internal mirror). | +| `offline` | `true` serves only from local install or cache, never network. | + +## Diagnostic code prefixes + +Prefixes in use across the ecosystem — [Structured Diagnostics](/guide/diagnostics#code-conventions). + +| Prefix | Owner | +|--------|-------| +| `DF` | `devframe` | +| `DTK` | `@vitejs/devtools` (Vite-specific) | +| `RDDT` | `@vitejs/devtools-rolldown` | +| `VDT` | `@vitejs/devtools-vite` (reserved) | + +## Auth methods + +The wire-level RPC methods of the trust handshake — [Security](/guide/security#authentication-flow). + +| RPC method | Direction | Shape | +|------------|-----------|-------| +| `anonymous:devframe:auth` | client → server | `{ authToken, ua, origin }` → `{ isTrusted }` — re-authenticate a stored token | +| `anonymous:devframe:auth:exchange` | client → server | `{ code, ua, origin }` → `{ authToken \| null }` — exchange a code for a token | +| `devframe:auth:revoke` | client → server | self-revoke the caller's own token | +| `devframe:auth:revoked` | server → client | event — token revoked | + +## Node auth primitives + +The building blocks in `devframe/node/auth` — [Security](/guide/security#the-ready-made-layer). + +| Function | Role | +|----------|------| +| `getTempAuthCode()` / `refreshTempAuthCode()` | read / rotate the one-time code | +| `exchangeTempAuthCode(code, session, { ua, origin }, storage)` | verify a code, mint + store the token, trust the session, return it (or `null`) | +| `verifyAuthToken(token, session, storage)` | trust a session presenting a known token | +| `buildOtpAuthUrl(origin, code?)` | build a magic-link URL embedding the code | +| `revokeAuthToken(context, storage, token)` | delete a token and disconnect sessions using it | + +## MCP CLI commands + +The agent-facing CLI surface — [Agent-Native Devframe](/guide/agent-native). + +| Command | Description | +|---------|-------------| +| ` mcp` | Start the MCP server on `stdio`. | +| ` dev --mcp` | Serve the agent-consumable API on `/__mcp`. | +| `devframe connect` | Discover running devframes and proxy their tools — see [MCP adapter](/adapters/mcp#discovery-devframe-connect). | diff --git a/docs/content/8.references/5.browser-api.md b/docs/content/8.references/5.browser-api.md new file mode 100644 index 00000000..044be5b1 --- /dev/null +++ b/docs/content/8.references/5.browser-api.md @@ -0,0 +1,59 @@ +--- +title: 'Browser-Side API' +navigation: + icon: i-lucide-globe +description: 'Lookup tables for the browser side: connectDevframe options, RPC client events, connection statuses, and in-page channel error codes.' +--- + +Lookup tables for a devframe's browser side. Each section links the guide page that teaches the concept. + +## connectDevframe options + +The options of `connectDevframe()` / `getDevframeRpcClient()` — [Client](/guide/client). + +| Option | Description | +|--------|-------------| +| `connection` | Connection prepared by `setupDevframeConnection()`. | +| `baseURL` | Mount path to probe for `__connection.json` (array = fallback). Default `'./'` (relative to `document.baseURI`); use an absolute path (`'/__devframe/'`) from outside the SPA. | +| `authToken` | Override the auth token (default: a locally-persisted id). | +| `cacheOptions` | `true` for default caching, or an options object. | +| `callTimeout` | Ms before a pending `rpc.call` rejects with a `'timeout'` `DevframeConnectionError`; `0`/omit = wait forever. | +| `wsOptions` | Transport overrides — `onConnected` / `onError` / `onDisconnected` hooks, socket URL. | +| `rpcOptions` | Forwarded to `birpc`. | +| `connectionMeta` | Descriptor that skips the `__connection.json` fetch. | + +## RPC client events + +Emitted over `rpc.events` — [Events](/guide/client#events). + +| Event | Fires when | +|-------|------------| +| `rpc:is-trusted:updated` | Trust granted, denied, or revoked. Carries the new `isTrusted` boolean. | +| `connection:status` | The [connection status](#connection-statuses) changes. Carries `(status, previous)`. | +| `connection:error` | A connection-level failure — socket error or trust refused. Carries the `Error`. | +| `rpc:error` | An `rpc.call` rejects, from the node side or a down connection. Carries `(error, method)`. | + +## Connection statuses + +The values of `rpc.status` — [Handling connection and auth errors](/guide/client#handling-connection-and-auth-errors). + +| Status | Meaning | +|--------|---------| +| `connecting` | Establishing socket / handshake. Calls queue until open. | +| `connected` | Socket open and trusted; calls are served. | +| `unauthorized` | Socket open, trust refused. Prompt for [authentication](/guide/client#authenticating-with-a-one-time-code). | +| `disconnected` | Socket closed (dropped mid-session or never opened). | +| `error` | Fatal — the socket errored or connection meta couldn't load. | + +## In-page channel error codes + +The `error.code` values of `InPageChannelError` — [Errors and fallbacks](/guide/in-page-channel#errors-and-fallbacks). + +| Code | When | What to do | +|------|------|------------| +| `timeout` | A call outlived `callTimeoutMs` (default 15s), or `whenConnected(ms)` expired | The message carries the endpoint status — `connecting` usually means the page script isn't loaded in this context | +| `closed` | The endpoint was closed with calls pending | Expected during teardown | +| `not-serializable` | A `jsonSerializable: true` payload contained a non-JSON value | The message names the offending path (e.g. `its arguments[0].nodes[2]` is a Map) | +| `not-cloneable` | The port refused to clone a payload (`DataCloneError`) | Strip functions/DOM nodes/reactivity proxies — or declare `jsonSerializable: true` for the precise error above | +| `invalid-args` | Incoming arguments failed their Standard-Schema validation | The message lists the schema issues | +| `state-uninitialized` | The page script read a shared state before providing its `initialValue` | Initialize on first access | diff --git a/docs/content/8.references/6.hub-api.md b/docs/content/8.references/6.hub-api.md new file mode 100644 index 00000000..397c4941 --- /dev/null +++ b/docs/content/8.references/6.hub-api.md @@ -0,0 +1,145 @@ +--- +title: 'Hub API' +navigation: + icon: i-lucide-layout-dashboard +description: 'Lookup tables for the hub: subsystems, launcher fields, duplication strategies, dock categories, the hub UI protocol, the namespace routes, the client runtime, the client context, and dock entry types.' +--- + +Lookup tables for `@devframes/hub` — its node-side subsystems and its browser-side client runtime. Each section links the guide page that teaches the concept. + +## Hub subsystems + +What `DevframeHubContext` adds to `DevframeNodeContext` — [Hub](/guide/hub). + +| Subsystem | API | Purpose | +|---|---|---| +| `ctx.docks` | `register / update / values / activate` | Dock entries (iframes, launchers, custom-render) and groups; `activate(dockId, params?)` sets the active dock ([Cross-iframe dock activation](/guide/hub#cross-iframe-dock-activation)). | +| `ctx.terminals` | `register / startChildProcess` | Aggregate terminal sessions, streaming output ([Terminals](/plugins/terminals#hub-aggregation)). | +| `ctx.messages` | `add / update / remove / clear` | Server-side toast/notification queue (FIFO, capped at 1000). | +| `ctx.commands` | `register / execute / list` | Hierarchical command palette with keybindings and `when` clauses. | + +## Launcher fields + +The optional `launcher` fields that make a `type: 'launcher'` dock entry a live process controller — [Process-control launchers](/guide/hub#process-control-launchers). + +| Field | Purpose | +|---|---| +| `command` | Bound command id; out-of-process hub UI providers dispatch via `hub:commands:execute` (register a handler via `ctx.commands`). | +| `terminalSessionId` | Tracked session id; a "view in terminal" action calls `hub:docks:activate` with the terminals dock id and `{ sessionId }`. | +| `digest` | Latest progress line, shown inline; patch via `docks.update()`. | + +## Duplication strategies + +The `duplicationStrategy` values deciding what happens when a devframe shares an already-mounted `id` — [Duplicate devframes](/guide/hub#duplicate-devframes). + +| Strategy | Behavior | +|---|---| +| `'warn'` (default) | Keep the first, drop the later, emit `DF8105`. | +| `'silent'` | Drop the later one without warning. | +| `'throw'` | Throw `DF8105`. | +| `'duplicate'` | Every instance coexists under a disambiguated dock id (`my-tool`, `my-tool-2`, …). | + +## Dock categories + +`DEFAULT_CATEGORIES_ORDER` (from `@devframes/hub`, `/node`, `/client`, `/constants`) names the default dock-rail buckets — [The dual role of `category`](/guide/hub#the-dual-role-of-category). + +| Category | Weight | Typical use | +|---|---|---| +| `framework` | `-100` | Framework internals. | +| `default` | `0` | Uncategorized. | +| `app` | `100` | App tools. | +| `ui` | `150` | Components, styling. | +| `data` | `250` | State, storage, queries. | +| `web` | `300` | Network, platform, a11y. | +| `performance` | `350` | Profiling, metrics. | +| `advanced` | `400` | Power-user tools. | +| `docs` | `500` | Documentation. | +| `~builtin` | `1000` | Built-in views; always last. | + +## Hub UI protocol + +The shared-state keys and RPC methods a hub UI provider renders from — [The hub UI protocol](/guide/hub#the-hub-ui-protocol). + +| Channel | Type | What it carries | +|---|---|---| +| `devframe:docks` shared state | `DevframeDockEntry[]` | Every registered dock entry. | +| `devframe:commands` shared state | `DevframeServerCommandEntry[]` | Serializable command list (handlers stripped). | +| `devframe:user-settings` shared state | `DevframeDocksUserSettings` | Persisted project-scope hub settings. | +| `devframe:docks:active` shared state | `DevframeDocksActiveState` | Most recent [dock activation](/guide/hub#cross-iframe-dock-activation) request. | +| `hub:commands:execute` RPC | `(id, ...args) => unknown` | Server-side command dispatch. | +| `hub:docks:activate` RPC | `({ dockId, params? }) => void` | Switch the active dock. | + +## Hub namespace routes + +What `initHub()` serves under its `base` — [The namespace](/guide/hub-initiate#the-namespace). + +| Path | Serves | +| --- | --- | +| `/` | the `ui.viewer` SPA, or index document when headless | +| `/` | each devframe's SPA + own `__connection.json` → shared socket | +| `embedded.js` | the `ui.embedded` bootstrap (`404` if none) | +| `__connection.json` | meta for the shared RPC socket | +| `__ws` | WebSocket upgrade route | +| `__index.json` | machine-readable index: mounted devframes, endpoints | +| `__client-imports.js` | dock client-script import map for hub UI providers | +| `__mcp` | aggregate MCP endpoint over the tool registry (opt-in `mcp`) | + +## Client runtime options + +The options of `createDevframeClientRuntime()` — [The client runtime](/guide/client-context#the-client-runtime). + +| Option | Description | +|--------|-------------| +| `rpc` | An already-connected `DevframeRpcClient`; when omitted, created via `connectDevframe(connect)`. | +| `connect` | Forwarded to `connectDevframe` when `rpc` is omitted (e.g. `baseURL`). | +| `clientType` | `'standalone'` (default) — owns the page; `'embedded'` — inside a user app alongside a panel. | +| `loadClientScripts` | Import and run dock client scripts (default `true`). | +| `renderers` | Dock renderers registered at boot, keyed by dock `type`; local wins over the hub's [renderer manifest](/guide/hub-initiate#renderer-modules). | + +## Client context properties + +The properties of `DevframeClientContext` — [The client context](/guide/client-context#the-client-context). + +| Property | Description | +|----------|-------------| +| `rpc` | The [RPC client](/guide/client) — server/client functions, shared state. | +| `clientType` | `'embedded'` (inside the user app) or `'standalone'` (independent hub page). | +| `docks` | `entries`, `selected`, `groupedEntries`, `switchEntry()`, `toggleEntry()`, `getStateById()`, `register()` / `update()` for [client-only docks](/guide/client-context#client-only-docks). | +| `panel` | Dock panel state: position, size, drag/resize. | +| `commands` | Command palette: `register()`, `execute()`, `getKeybindings()`. | +| `renderers` | Dock-renderer registry — `register()`, `get()`, `has()`, `mount(entry, container)`. Routes a dock `type` to a renderer (local boot or the hub's [manifest](/guide/hub-initiate#renderer-modules); local wins). `mount()` resolves a `status`: `mounted` (with `dispose`), `missing-renderer`, or `load-error` (with `error`). | +| `when` | The [when-clause](/references/when-clauses) context. | +| `connection` | Live [connection status](/guide/client#handling-connection-and-auth-errors) — `status`, `error`, `events`. | + +## Dock client script fields + +Which `ClientScriptEntry` field carries an entry's client script, and when it runs — [Dock client scripts](/guide/client-context#dock-client-scripts). + +| Entry kind | Field | Runs | +|---|---|---| +| `action` | `action` | when the dock button is activated | +| `custom-render` | `renderer` | to render the entry's panel | +| `iframe` | `clientScript` (optional) | alongside the iframe panel, inside the host page | + +## Frame-nav messages + +The origin-locked `postMessage` protocol on `devframe:frame-nav` — [Shared-iframe soft navigation](/guide/client-context#shared-iframe-soft-navigation). + +| Message | Direction | Meaning | +|---|---|---| +| `ready` / `manifest` | iframe → host page | tab list (`{ tabs, current }`), on load and change | +| `navigate` | host page → iframe | show a view (`{ tabId, navTarget }`); the SPA routes client-side | +| `navigated` | iframe → host page | the SPA navigated internally; the hub UI provider highlights the dock | + +## Dock entry types + +The built-in variants of the open dock union (`DevframeDockEntryRegistry`, `@devframes/hub/types`) a hub UI provider renders — [Build Your Own Hub UI](/guide/build-your-own-hub-ui). + +| Type | The hub UI provider renders | +|---|---| +| `iframe` | the entry's `url` in a kept-alive iframe (per `frameId` when shared); honor `subTabs` soft nav | +| `action` | a dock-rail button; activating runs its client script | +| `custom-render` | a container its client script mounts into | +| `launcher` | a launch call-to-action reflecting `launcher.status` | +| `group` | one dock-rail button collapsing its member entries | +| `~builtin` | your native views (settings, feeds) for reserved ids | diff --git a/docs/content/8.references/index.md b/docs/content/8.references/index.md index f859056a..21e866a9 100644 --- a/docs/content/8.references/index.md +++ b/docs/content/8.references/index.md @@ -2,7 +2,7 @@ title: 'References' navigation: icon: i-lucide-book-marked -description: 'Lookup pages the guides link into: the canonical terms, the when-clause contexts, and every event name on the wire.' +description: 'Lookup pages the guides link into: the canonical terms, the when-clause contexts, every event name on the wire, and the API tables for the node side, the browser side, and the hub.' --- Lookup pages the guides link into: @@ -10,5 +10,8 @@ Lookup pages the guides link into: - [Terms](/references/terms) — the canonical vocabulary of these docs: one name per concept, with its anchoring API. - [When Clauses](/references/when-clauses) — the contexts and operators that gate docks, commands, and custom UI. - [Events Reference](/references/events) — every event, broadcast, shared-state key, and channel name, by direction and reach. +- [Node-Side API](/references/node-api) — `DevframeDefinition` fields, CLI options, storage scopes, RPC function types, broadcast options, streaming lifecycle, remote assets, diagnostics prefixes, and the auth surface. +- [Browser-Side API](/references/browser-api) — `connectDevframe` options, RPC client events, connection statuses, and in-page channel error codes. +- [Hub API](/references/hub-api) — hub subsystems, launcher fields, duplication strategies, dock categories, the hub UI protocol, the namespace routes, the client runtime, the client context, and dock entry types. -The [error reference](/errors) documents each `DF*` diagnostic code, and [migrations](/migrations) each version step. +The [error reference](/errors) documents each `DF*` diagnostic code, and [migrations](/migrations) each version step. The adapter, framework-kit, helper, and built-in-devframe pages each carry their own package's options and RPC tables.