Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ Monorepo (`pnpm` workspaces + `turbo`). ESM TypeScript; bundled with `tsdown`. P
| `packages/ui` | `@vitejs/devtools-ui` | Shared UI components, composables, and UnoCSS preset (`presetDevToolsUI`). Private, not published. |
| `packages/rolldown` | `@vitejs/devtools-rolldown` | Nuxt UI for Rolldown build data. Hub-mounted via `Plugin.devtools.setup`. Serves at `/__devtools-rolldown/`. |
| `packages/vite` | `@vitejs/devtools-vite` | Nuxt UI for Vite DevTools (WIP). Hub-mounted via `Plugin.devtools.setup`. Serves at `/__devtools-vite/`. |
| `packages/self-inspect` | `@vitejs/devtools-self-inspect` | Meta-introspection — DevTools for the DevTools. Hub-mounted via `Plugin.devtools.setup`. Serves at `/__devtools-self-inspect/`. |
| `packages/webext` | — | Browser extension scaffolding (ancillary). |

Meta-introspection ("DevTools for the DevTools") is provided by the official upstream `@devframes/plugin-inspect`, mounted as a built-in via `createPluginFromDevframe` (replaces the former `packages/self-inspect`).

Other top-level directories:
- `docs/` — VitePress docs; guides in `docs/guide/`
- `skills/` — Agent skill files generated from docs via [Agent Skills](https://agentskills.io/home). Structured references (RPC patterns, dock types, shared state, project structure) for AI agent context.
Expand All @@ -35,10 +36,9 @@ flowchart TD
hub --> devframe
kit --> hub
core --> kit
core --> rolldown & vite & self-inspect
core --> rolldown & vite
rolldown --> kit & ui
vite --> kit & ui
self-inspect --> kit
webext --> core
```

Expand All @@ -51,13 +51,14 @@ flowchart TD
## Architecture

- **Devframe context** (external — see [devfra.me](https://devfra.me)): `createHostContext` returns a `DevframeNodeContext` carrying `rpc`, `views` (HTTP file-serving via `hostStatic`), `diagnostics`, `agent`, plus `cwd`/`workspaceRoot`/`mode`/`host`. No docks, no terminals, no json-render.
- **Hub context** (external `@devframes/hub/node`): `createHubContext` wraps `createHostContext` and attaches the four hub hosts — `docks`, `terminals`, `messages`, `commands` — plus the `createJsonRenderer` factory. Wires the `'devframe:docks'` / `'devframe:commands'` shared-state sync and seeds the built-in `~terminals` / `~messages` / `~settings` docks. Also ships `mountDevframe(ctx, def)` — the framework-neutral primitive that registers any `DevframeDefinition` as a dock.
- **Hub context** (external `@devframes/hub/node`): `createHubContext` wraps `createHostContext` and attaches the four hub hosts — `docks`, `terminals`, `messages`, `commands` — plus the `createJsonRenderer` factory. Wires the `'devframe:docks'` / `'devframe:commands'` shared-state sync and seeds the built-in `~terminals` / `~messages` / `~settings` docks (each gateable via `CreateHubContextOptions.builtinDocks`; core disables `~terminals`/`~messages` in favour of the official plugins). Also ships `mountDevframe(ctx, def)` — the framework-neutral primitive that registers any `DevframeDefinition` as a dock.
- **Kit context** (`packages/kit/src/node/context.ts`): `createKitContext` wraps `createHubContext` and surfaces Vite-specific `viteConfig`/`viteServer` slots when mounted inside Vite DevTools. `KitNodeContext` extends `DevframeHubContext` so all the hub hosts come along for free.
- **Bridge** (`packages/kit/src/node/create-plugin-from-devframe.ts`): `createPluginFromDevframe(d, opts?)` returns `PluginWithDevTools`; in its `setup`, delegates to `mountDevframe(ctx, d, opts)` to mount the SPA, register the auto-derived iframe dock entry, and run `d.setup(ctx)`, then runs `opts.setup?.(ctx)` for kit-only extensions.
- **Vite DevTools entry** (`packages/core/src/node/context.ts`): `createDevToolsContext` calls `createKitContext`, registers Vite-specific commands (`vite:open-in-editor`, `vite:open-in-finder`), then scans Vite plugins for `.devtools.setup` hooks (which now receive the kit-augmented context).
- **Client context**: webcomponents/Nuxt UI state (`packages/core/src/client/webcomponents/state/*`) — dock entries, panels, RPC client. Two modes: `embedded` (overlay in host app) and `standalone` (independent page).
- **WS server** (`packages/core/src/node/ws.ts`): RPC via `devframe/rpc/transports/ws-server`. Auth skipped in build mode or when `devtools.clientAuth` is `false`.
- **Hub-mounted Nuxt UI plugins** (rolldown, vite, self-inspect): each implements `Plugin.devtools.setup`, receives a `KitNodeContext`, registers RPC functions, hosts a static Nuxt SPA, and registers its dock entry.
- **Hub-mounted Nuxt UI plugins** (rolldown, vite): each implements `Plugin.devtools.setup`, receives a `KitNodeContext`, registers RPC functions, hosts a static Nuxt SPA, and registers its dock entry.
- **Built-in devframe plugins** (`@devframes/plugin-inspect` today; `@devframes/plugin-terminals` / `@devframes/plugin-messages`): official portable `DevframeDefinition`s mounted as built-ins by `DevTools()` via kit's `createPluginFromDevframe` (gated by `builtinDevTools`).

## Development

Expand All @@ -78,7 +79,7 @@ pnpm -C docs run docs # docs dev server
- Use workspace aliases from `alias.ts`.
- RPC functions must use `defineRpcFunction` from kit; always namespace IDs (`my-plugin:fn-name`).
- Shared state via `devframe/utils/shared-state`; keep values serializable.
- Nuxt UI base paths: `/__devtools-rolldown/`, `/__devtools-vite/`, `/__devtools-self-inspect/`.
- Nuxt UI base paths: `/__devtools-rolldown/`, `/__devtools-vite/`.
- Shared UI components/preset in `packages/ui`; use `presetDevToolsUI` from `@vitejs/devtools-ui/unocss`.
- Currently focused on Rolldown build-mode analysis; dev-mode support is deferred.

Expand Down
6 changes: 0 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,6 @@ Typed RPC wrapper over `birpc` with WebSocket presets.

---

### `packages/self-inspect` - `@vitejs/devtools-self-inspect`

Meta-introspection — DevTools for the DevTools itself.

---

### `packages/webext` - `@vitejs/devtools-webext`

Browser extension (planned for future dev mode). **Not accepting contributions currently.**
Expand Down
1 change: 0 additions & 1 deletion alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const alias = {
'@vitejs/devtools-kit/utils/shared-state': r('kit/src/utils/shared-state.ts'),
'@vitejs/devtools-kit': r('kit/src/index.ts'),
'@vitejs/devtools-rolldown': r('rolldown/src/index.ts'),
'@vitejs/devtools-self-inspect': r('self-inspect/src/index.ts'),
'@vitejs/devtools/internal': r('core/src/internal.ts'),
'@vitejs/devtools/client/inject': r('core/src/client/inject/index.ts'),
'@vitejs/devtools/client/webcomponents': r('core/src/client/webcomponents/index.ts'),
Expand Down
38 changes: 15 additions & 23 deletions docs/errors/DTK0013.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,43 @@ outline: deep

## Cause

This error is thrown by the RPC resolver in `createWsServer()` when an untrusted WebSocket client attempts to call a non-anonymous RPC method. Methods whose names start with `devframe:anonymous:` are exempt from authentication and can be called by any client; all other methods require the client to be trusted.
This error is thrown by the RPC resolver in `createWsServer()` when an untrusted WebSocket client attempts to call a protected RPC method. Any method whose name starts with `anonymous:` is exempt and callable before trust — that's the auth handshake (`anonymous:devframe:auth` and `anonymous:devframe:auth:exchange`). Every other method requires the client to be trusted.

A client becomes trusted through one of these mechanisms:

1. **Client auth is disabled** (build mode, `clientAuth: false`, or `VITE_DEVTOOLS_DISABLE_CLIENT_AUTH=true`) -- all clients are auto-trusted.
2. **Auth token in storage** -- the client provides a `devframe_auth_token` query parameter that matches a token stored in `node_modules/.vite/devtools/auth.json`.
3. **Static auth tokens** -- the token matches one of the tokens listed in `devtools.clientAuthTokens` in your Vite config.
1. **Client auth is disabled** (build mode, `clientAuth: false`, or `VITE_DEVTOOLS_DISABLE_CLIENT_AUTH=true`) all clients are auto-trusted.
2. **One-time code exchange** — an untrusted browser is shown a one-time code in the terminal, along with a `?devframe_otp=` magic link. Entering the code (or opening the link) exchanges it via `anonymous:devframe:auth:exchange` for a node-issued bearer token; the browser persists that token and re-presents it (`anonymous:devframe:auth`) on reconnect.
3. **Static auth tokens** the token matches one listed in `devtools.clientAuthTokens` in your Vite config.

If none of these conditions are met, the client is untrusted and any call to a non-anonymous method triggers this error.
If none of these conditions are met, the client is untrusted and any call to a protected method triggers this error. A trusted browser can also hand its access back from **Settings → Advanced → Revoke Access**, which revokes its token and drops it to untrusted.

## Example

A client connecting without a valid auth token:
An untrusted browser calling a protected method:

```ts
// Client-side: connecting without authentication
const ws = new WebSocket('ws://localhost:7812')
// This client is untrusted

// Calling a protected method triggers DTK0013
await rpc.invoke('my-plugin:get-data')
// The browser hasn't completed the auth handshake yet — it's untrusted.
await rpc.call('my-plugin:get-data')
// Error: Unauthorized access to method "my-plugin:get-data" from client [abc123]
```

## Fix

Provide a valid authentication token when connecting:
Authorize the browser. When an untrusted client connects, the dev-server terminal prints a one-time code and a magic link:

```ts
// Client-side: connecting with a valid auth token
const ws = new WebSocket(
'ws://localhost:7812?devframe_auth_token=your-token-here'
)
```
- **Enter the code** in the DevTools authorization prompt, or
- **Open the magic link** (`<origin>/?devframe_otp=<code>`) — the client reads the code, exchanges it for a bearer token, and persists it for future reconnects.

Or configure static trusted tokens in your Vite config:
For automated setups (CI, shared machines), configure static trusted tokens instead — a client presenting one via the `devframe_auth_token` connection parameter is trusted without the interactive step:

```ts
import devtools from '@vitejs/devtools'
import { DevTools } from '@vitejs/devtools'
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
plugins: [
devtools(),
DevTools(),
],
devtools: {
enabled: true,
Expand All @@ -67,4 +59,4 @@ If you are developing locally and want to skip authentication entirely, see [DTK

## Source

- [`packages/core/src/node/ws.ts`](https://github.com/vitejs/devtools/blob/main/packages/core/src/node/ws.ts) — the WebSocket RPC resolver in `createWsServer()` throws `DTK0013` when an untrusted client invokes a method whose name is not prefixed with `devframe:anonymous:`.
- [`packages/core/src/node/ws.ts`](https://github.com/vitejs/devtools/blob/main/packages/core/src/node/ws.ts) — the WebSocket RPC resolver in `createWsServer()` throws `DTK0013` when an untrusted client invokes a method that isn't `anonymous:`-prefixed (devframe's `isAnonymousRpcMethod`).
20 changes: 2 additions & 18 deletions docs/kit/devtools-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,25 +204,9 @@ export default function myAnalyzerPlugin(): Plugin {
}
```

## Debugging with Self Inspect
## Debugging with the inspector

`@vitejs/devtools-self-inspect` adds a "Self Inspect" panel to DevTools that shows registered RPC functions, dock entries, client scripts, and DevTools-enabled plugins — handy when verifying that everything you registered actually shows up:

```bash
pnpm add -D @vitejs/devtools-self-inspect
```

```ts [vite.config.ts]
import { DevToolsSelfInspect } from '@vitejs/devtools-self-inspect'

export default defineConfig({
plugins: [
DevTools(),
DevToolsSelfInspect(),
// ...your plugins
],
})
```
Vite DevTools ships the official `@devframes/plugin-inspect` inspector as a built-in panel, enabled by default with `builtinDevTools`. It shows registered RPC functions, dock entries, client scripts, and DevTools-enabled plugins — handy when verifying that everything you registered actually shows up. Open the "Inspect" dock; no extra install needed.

## Next steps

Expand Down
2 changes: 1 addition & 1 deletion docs/kit/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Kit owns the hub-level surface — the things that only matter once multiple int
| **[Dock System](./dock-system)** | The unified dock — iframe / action / custom / launcher / json-render entries — with categories, when-clauses, and remote dock support. |
| **[Commands](./commands)** | The shared command palette: keybindings, children, when-gating across every integration. |
| **[Messages](./messages)** | Cross-tool toast notifications and the unified messages dock. |
| **[Terminals](./terminals)** | Aggregate terminal output from any integration into one xterm.js view. |
| **[Terminals](./terminals)** | Aggregate terminal output from any integration into one Terminals panel. |
| **[RPC](./rpc)** | Type-safe bidirectional RPC backed by Devframe's birpc + valibot. |
| **[Shared State](./shared-state)** | Patch-synced state that bridges server ↔ client across every integration. |
| **Isomorphic Views** | Deploy your UI as embedded panels, browser extensions, or standalone webpages. |
Expand Down
6 changes: 1 addition & 5 deletions docs/kit/messages.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Messages & Notifications

The Messages system lets plugins emit structured message entries from both the server (Node.js) and client (browser) contexts. Entries appear in the **Messages** panel in the DevTools dock and can optionally surface as toast notifications. For *coded* errors and warnings with stable codes and docs URLs, use [Structured Diagnostics](./diagnostics) (`ctx.diagnostics`) instead.
The Messages system lets plugins emit structured message entries from both the server (Node.js) and client (browser) contexts. Entries appear in the **Messages** panel (the official [`@devframes/plugin-messages`](https://devfra.me), mounted as a built-in) and can optionally surface as toast notifications. For *coded* errors and warnings with stable codes and docs URLs, use [Structured Diagnostics](./diagnostics) (`ctx.diagnostics`) instead.

## Use cases

Expand Down Expand Up @@ -165,10 +165,6 @@ Capacity tops out at 1000 entries; the oldest are dropped automatically when the

The [A11y Checker example](/kit/examples#a11y-checker) is a plugin that uses messages to report accessibility violations with severity levels, element positions, and WCAG labels.

## Dock badge

The Messages dock icon shows a badge with the total message count and hides itself when there are no messages.

## Events

The host emits events for observers of the message stream:
Expand Down
2 changes: 1 addition & 1 deletion docs/kit/remote-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ sequenceDiagram

User->>Core: configureServer
Core->>Core: register dock (remote: true) → allocate token
Core->>Core: createWsServer → wsEndpoint=ws://localhost:7812
Core->>Core: createWsServer → wsEndpoint=ws://localhost:5173/__devtools/__ws
User->>Core: open dock
Core->>Hosted: iframe src + connection descriptor
Hosted->>Core: WS connect (?devframe_auth_token=...)
Expand Down
4 changes: 2 additions & 2 deletions docs/kit/terminals.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ outline: deep

# Terminals & Subprocesses

DevTools Kit's terminal host lets a plugin spawn and manage child processes. Output streams in real time to an xterm.js panel inside DevTools.
DevTools Kit's terminal host lets a plugin spawn and manage child processes. Sessions are aggregated by the hub and surfaced in the Terminals panel (the official [`@devframes/plugin-terminals`](https://devfra.me), mounted as a built-in), which streams their output in real time.

## Starting a child process

Expand Down Expand Up @@ -158,4 +158,4 @@ for (const session of ctx.terminals.sessions.values()) {
}
```

`ctx.terminals.sessions` is a live `Map<string, DevToolsTerminalSession>` — useful for diagnostics, testing, and custom terminal UIs that mirror the built-in panel.
`ctx.terminals.sessions` is a live `Map<string, DevToolsTerminalSession>` — useful for diagnostics, testing, and custom terminal UIs that mirror the Terminals panel.
10 changes: 4 additions & 6 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
},
"dependencies": {
"@devframes/hub": "catalog:deps",
"@devframes/plugin-inspect": "catalog:deps",
"@devframes/plugin-messages": "catalog:deps",
"@devframes/plugin-terminals": "catalog:deps",
"@vitejs/devtools-kit": "workspace:*",
"@vitejs/devtools-rolldown": "workspace:*",
"birpc": "catalog:deps",
Expand All @@ -67,15 +70,12 @@
"nostics": "catalog:deps",
"obug": "catalog:deps",
"pathe": "catalog:deps",
"vue": "catalog:deps",
"ws": "catalog:deps"
"vue": "catalog:deps"
},
"devDependencies": {
"@clack/prompts": "catalog:inlined",
"@vitejs/devtools-rolldown": "workspace:*",
"@vitejs/plugin-vue": "catalog:build",
"@xterm/addon-fit": "catalog:frontend",
"@xterm/xterm": "catalog:frontend",
"dompurify": "catalog:frontend",
"fuse.js": "catalog:frontend",
"human-id": "catalog:inlined",
Expand All @@ -96,8 +96,6 @@
"@json-render/vue": "0.13.0",
"@vueuse/core": "14.3.0",
"@vueuse/shared": "14.3.0",
"@xterm/addon-fit": "0.11.0",
"@xterm/xterm": "6.0.0",
"dompurify": "3.4.3",
"fast-string-truncated-width": "3.0.3",
"fast-string-width": "3.0.2",
Expand Down
Loading
Loading