Skip to content

Commit c0dfc1f

Browse files
authored
refactor!: remove never-implemented SPA adapter remnants and other dead code (#234)
1 parent c5bce49 commit c0dfc1f

64 files changed

Lines changed: 165 additions & 315 deletions

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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
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/spa/embedded outputs) without caring how it'll be displayed. A devframe app 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 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 app runs standalone (CLI, static deploy, embedded SPA) just as well as it mounts inside a hub.
66

77
**`@devframes/hub`** is the framework-neutral hub layer that sits on top of devframe and provides the multi-integration orchestration (docks, terminals, messages, commands). It does not ship UI - implementers (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 plugin like the a11y inspector runs code inside the page being inspected. See `examples/hub-vite/` for a working ~120-line Vite host demonstrating the protocol end to end.
88

@@ -79,8 +79,8 @@ These reinforce devframe's positioning as "the container for one devtool integra
7979

8080
- **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.
8181
- **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.
82-
- **Mount path depends on adapter context.** Given `id: 'foo'`, the default mount path is `/__foo/` for *hosted* adapters (`vite`, `embedded`) and `/` for *standalone* adapters (`cli`, `spa`, `build`). Authors override via `DevframeDefinition.basePath`. Don't hardcode mount paths in adapter code paths that may run standalone.
83-
- **SPAs own their basePath at runtime.** Build SPAs with relative asset paths (`vite.base: './'`); discover the effective base in the browser from the executing script's location / `document.baseURI`. `createBuild` / `createSpa` copy SPA output verbatim - no HTML rewriting, no build-time `--base` injection. The client (`connectDevframe`) resolves `.connection.json` relative to the runtime base automatically.
82+
- **Mount path depends on adapter context.** Given `id: 'foo'`, the default mount path is `/__foo/` for *hosted* adapters (`vite`, `embedded`) and `/` for *standalone* adapters (`cli`, `build`). Authors override via `DevframeDefinition.basePath`. Don't hardcode mount paths in adapter code paths that may run standalone.
83+
- **SPAs own their basePath at runtime.** Build SPAs with relative asset paths (`vite.base: './'`); discover the effective base in the browser from the executing script's location / `document.baseURI`. `createBuild` copies SPA output verbatim - no HTML rewriting, no build-time `--base` injection. The client (`connectDevframe`) resolves `.connection.json` relative to the runtime base automatically.
8484
- **CLI flags compose from both sides.** The `cac` instance backing `createCac` is exposed both to the `DevframeDefinition` (`cli.configure(cli)`) - for capabilities contributed by the tool itself - and to the `createCac` caller - for flags added at the final assembly stage. Parsed flag values are forwarded to `setup(ctx, { flags })`. Never hardcode domain-specific flags into `createCac`.
8585

8686
### Hub example parity

‎docs/adapters/build.md‎

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,22 @@ Produces a self-contained static deploy of a devframe:
1010
2. Runs `setup(ctx)` with `mode: 'build'`.
1111
3. Collects RPC dumps for every `'static'` function and any `'query'` function with `dump.inputs` / `snapshot: true`.
1212
4. Writes `<outDir>/__connection.json` (`{ backend: 'static' }`) and sharded dump files under `<outDir>/__rpc-dump/` — both at the SPA root so the deployed client discovers them via relative paths from `document.baseURI`.
13-
5. When `def.spa` is set, also writes `<outDir>/spa-loader.json` describing how the SPA hydrates its data.
1413

1514
```ts
1615
import { createBuild } from 'devframe/adapters/build'
1716
import devframe from './devframe'
1817

1918
await createBuild(devframe, {
2019
outDir: 'dist-static',
21-
base: '/',
2220
})
2321
```
2422

2523
| Option | Default | Description |
2624
|--------|---------|-------------|
2725
| `outDir` | `dist-static` | Output directory. Cleared on each build. |
28-
| `base` | `/` | Absolute URL base the output is served from. |
2926
| `distDir` | `def.cli?.distDir` | Override the SPA dist directory. |
27+
| `pretty` | `false` | Pretty-print dump JSON (larger on disk). |
3028

3129
The resulting directory hosts on any static web server (`serve`, nginx, GitHub Pages, …). The client auto-detects `static` mode by resolving `./__connection.json` against `document.baseURI` and runs in read-only form.
3230

3331
`createBuild` copies the SPA verbatim, so deploying under a custom URL base just means building the SPA with relative asset paths (`vite.base: './'`) — the client discovers the effective base at runtime.
34-
35-
When `def.spa` is set on the definition, `createBuild` also writes `spa-loader.json` next to `index.html` describing how the deployed SPA sources its data:
36-
37-
- `'none'` — use the baked RPC dump only (read-only static view).
38-
- `'query'` — hydrate from URL search params.
39-
- `'upload'` — accept a drag-and-drop file.
40-
41-
Deployed SPAs that use `setupBrowser` ship their own client entry that registers the handlers.

‎docs/adapters/cac.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ outline: deep
44

55
# CLI (cac)
66

7-
The cac adapter wraps a `DevframeDefinition` in a [`cac`](https://github.com/cacjs/cac)-powered command-line interface. From one entry it spins up an `h3` dev server with WebSocket RPC, builds static snapshots, builds SPA bundles, or starts an MCP server.
7+
The cac adapter wraps a `DevframeDefinition` in a [`cac`](https://github.com/cacjs/cac)-powered command-line interface. From one entry it spins up an `h3` dev server with WebSocket RPC, builds static snapshots, or starts an MCP server.
88

99
`cac` is an optional peer dependency, pulled in only through this adapter — install it alongside `devframe` to opt into `createCac`:
1010

@@ -68,7 +68,7 @@ defineDevframe({
6868
id: 'my-devframe',
6969
cli: {
7070
command: 'my-devframe', // binary name; default: the id
71-
distDir: './client/dist', // required for dev/build/spa
71+
distDir: './client/dist', // required for dev/build
7272
port: 7777, // preferred port
7373
portRange: [7777, 9000], // passed through to get-port-please
7474
random: false, // passed through to get-port-please

‎docs/adapters/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ A devframe's SPA basePath depends on which adapter is running it:
2525

2626
| Adapter kind | Default basePath | Reason |
2727
|--------------|------------------|--------|
28-
| `cli`, `spa`, `build` (standalone) | `/` | The devframe owns the origin. |
28+
| `cli`, `build` (standalone) | `/` | The devframe owns the origin. |
2929
| `vite`, `embedded` (hosted) | `/__<id>/` | The devframe shares the origin with a host app and namespaces itself. |
3030

3131
Override either side explicitly with `DevframeDefinition.basePath`:

‎docs/errors/DF0058.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
outline: deep
3+
---
4+
5+
# DF0058: Dev Server Disabled By The Definition
6+
7+
## Message
8+
9+
> "`{id}`" declares `capabilities.dev: false` — it does not support a live dev server (its value is a static export only).
10+
11+
## Cause
12+
13+
`createDevServer` runs unconditionally when called directly, but a definition can opt out of the live dev server via `capabilities.dev: false` — for a devframe whose value is inherently static (e.g. a report generator with nothing to serve live), a dev server would only ever produce an empty or misleading surface. This diagnostic covers a caller invoking `createDevServer()` directly.
14+
15+
## Example
16+
17+
```ts
18+
// ✗ Bad — starts a dev server for a devframe that opted out of it
19+
await createDevServer(reportDevframe) // throws DF0058
20+
21+
// ✓ Good — run it anyway when you know what you're doing
22+
await createDevServer(reportDevframe, { force: true })
23+
```
24+
25+
## Fix
26+
27+
- Pass `{ force: true }` to `createDevServer()` to run it anyway.
28+
- Otherwise, drop `capabilities.dev: false` on the definition if a live dev server should be supported after all.
29+
30+
## Source
31+
32+
- [`packages/devframe/src/adapters/dev.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/dev.ts)`createDevServer()` throws this when `capabilities.dev` is `false` and `force` isn't set.

‎docs/examples/built-with.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ Real-world devframes:
1212

1313
End-to-end examples in this repo, exercising the full adapter surface:
1414

15-
- [**files-inspector**](https://github.com/devframes/devframe/tree/main/examples/files-inspector) — lists files in cwd via RPC; exercises CLI dev/build/spa surfaces.
15+
- [**files-inspector**](https://github.com/devframes/devframe/tree/main/examples/files-inspector) — lists files in cwd via RPC; exercises CLI dev/build surfaces.
1616
- [**streaming-chat**](https://github.com/devframes/devframe/tree/main/examples/streaming-chat) — streams synthetic chat tokens from server to client via `ctx.rpc.streaming`.
1717
- [**next-runtime-snapshot**](https://github.com/devframes/devframe/tree/main/examples/next-runtime-snapshot) — Next.js App Router SPA over RPC, surfacing the host Node runtime (system info, memory, env).

‎docs/examples/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ End-to-end examples that exercise the full adapter surface, each a runnable app
88

99
| Example | UI framework | What it shows |
1010
|---------|--------------|---------------|
11-
| [files-inspector](./files-inspector) | Preact | Lists files in the cwd via RPC; exercises the CLI dev / build / spa surfaces. |
11+
| [files-inspector](./files-inspector) | Preact | Lists files in the cwd via RPC; exercises the CLI dev / build surfaces. |
1212
| [json-render](./json-render) | Vue | A server-authored JSON-render view rendered by `@devframes/json-render-ui`, with live state and an action bridge. |
1313
| [streaming-chat](./streaming-chat) | Preact | Streams synthetic chat tokens server → client, with history kept in shared state. |
1414
| [next-runtime-snapshot](./next-runtime-snapshot) | React (Next.js) | A Next.js App Router SPA over RPC, surfacing the host Node runtime. |

‎docs/frameworks/nuxt.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ my-tool/
113113
└── public/ # Nuxt build output, pointed at by cli.distDir
114114
```
115115

116-
In dev (`nuxt dev`) the bridge is live. In production (`<your-cli> build` then `<your-cli> spa`) the SPA loads the static dump.
116+
In dev (`nuxt dev`) the bridge is live. In production (`<your-cli> build`) the SPA loads the static dump.
117117

118118
## How it works
119119

‎docs/guide/devframe-definition.md‎

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,11 @@ export default defineDevframe({
4848
| `homepage` | `string` | **Required.** Project homepage or documentation URL. |
4949
| `description` | `string` | **Required.** One-line summary of what the tool does. |
5050
| `icon` | `string \| { light, dark }` | Optional Iconify name or URL; supports light/dark pairs. |
51-
| `basePath` | `string` | Optional mount path override. Defaults depend on the adapter: `/` for standalone (`cli` / `spa` / `build`), `/.<id>/` for hosted (`vite` / `embedded`). |
51+
| `basePath` | `string` | Optional mount path override. Defaults depend on the adapter: `/` for standalone (`cli` / `build`), `/.<id>/` for hosted (`vite` / `embedded`). |
5252
| `duplicationStrategy` | `'warn' \| 'silent' \| 'throw' \| 'duplicate'` | How a hub reacts when another devframe sharing this `id` is mounted onto the same hub. Defaults to `'warn'`. See [Hub](./hub). Hub adapters consult it; standalone adapters ignore it. |
53-
| `capabilities` | `{ dev?, build?, spa? }` | Per-runtime feature flags. A `boolean` applies to the runtime as a whole; an object enables individual features. |
53+
| `capabilities` | `{ dev?, build? }` | Per-runtime feature flags. A `boolean` applies to the runtime as a whole; an object enables individual features. |
5454
| `setup` | `(ctx, info?) => void \| Promise<void>` | **Required.** Server-side entry point. Runs in every runtime. The optional second argument carries runtime metadata — most notably the parsed CLI `flags` when running under `createCac`. |
55-
| `setupBrowser` | `(ctx) => void \| Promise<void>` | Browser-only entry used by the SPA adapter. |
5655
| `cli` | `DevframeCliOptions` | Defaults for the CLI adapter. See [CLI options](#cli-options) below. |
57-
| `spa` | `DevframeSpaOptions` | Defaults for the SPA adapter (`base`, `loader`). |
5856

5957
### Sourcing metadata from `package.json`
6058

@@ -171,23 +169,6 @@ Each devframe-level host has a dedicated page:
171169
- [Agent-Native](./agent-native)`ctx.agent`
172170
- [Cross-Plugin Services](./services)`ctx.services`
173171

174-
## Browser setup
175-
176-
The SPA adapter supports a `setupBrowser(ctx)` hook that runs inside the deployed client bundle. Use it for tools that perform their own in-browser work — parsing a dropped file, calling public APIs from the client, etc.
177-
178-
```ts
179-
defineDevframe({
180-
id: 'my-devframe',
181-
name: 'My Devframe',
182-
setup(ctx) { /* server-side */ },
183-
setupBrowser(ctx) {
184-
// `ctx.rpc` is the write-disabled static client in SPA mode.
185-
},
186-
})
187-
```
188-
189-
Deployed SPAs that use `setupBrowser` ship their own client entry that registers the handlers.
190-
191172
## CLI options
192173

193174
`cli` configures the CLI adapter's defaults and plugs additional flags/commands into the CAC instance:
@@ -198,7 +179,7 @@ defineDevframe({
198179
name: 'My Devframe',
199180
cli: {
200181
command: 'my-devframe', // binary name; default: the `id`
201-
distDir: './client/dist', // required for dev / build / spa
182+
distDir: './client/dist', // required for dev / build
202183
port: 9876, // preferred port; default: 9999
203184
portRange: [9876, 10000], // forwarded to get-port-please
204185
random: false, // forwarded to get-port-please
@@ -220,7 +201,7 @@ defineDevframe({
220201
| Field | Type | Description |
221202
|-------|------|-------------|
222203
| `command` | `string` | Binary name surfaced in `--help`. Default: the definition's `id`. |
223-
| `distDir` | `string` | SPA dist directory. **Required** for `dev` / `build` / `spa`. |
204+
| `distDir` | `string` | SPA dist directory. **Required** for `dev` / `build`. |
224205
| `port` | `number` | Preferred port for the dev server. |
225206
| `portRange` | `[number, number]` | Port scan range, passed through to `get-port-please`. |
226207
| `random` | `boolean` | Prefer a random open port. |
@@ -231,18 +212,6 @@ defineDevframe({
231212

232213
`setup(ctx, info)` receives `info.flags` populated from both devframe's built-in flags and any you declared via `configure` — saves duplicating flag parsing.
233214

234-
## SPA options
235-
236-
```ts
237-
defineDevframe({
238-
id: 'my-devframe',
239-
spa: {
240-
base: '/',
241-
loader: 'query', // 'query' | 'upload' | 'none'
242-
},
243-
})
244-
```
245-
246215
See [Adapters](/adapters/) for how each adapter consumes these.
247216

248217
## Multiple runtimes, one definition

‎docs/guide/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Devframe keeps its surface focused on one tool, so the same definition stays por
1515
- **One tool per definition.** A devframe describes a single integration. Deploy it through any adapter; host-level features that only matter when several tools share a UI (palettes, cross-tool toasts, unified terminals) come from whichever host you mount into — Vite DevTools is one example.
1616
- **Headless.** Hook into `onReady`, `cli.configure`, and friends to print your own startup banners and styling — Devframe stays out of the way.
1717
- **App-owned file watching.** Wire your own watcher (chokidar, fs.watch, …) and signal change via `ctx.rpc.sharedState.set(...)` or event-typed RPCs.
18-
- **Context-aware mount paths.** Standalone adapters (`cli`, `spa`, `build`) serve at `/` by default; hosted adapters (`vite`, `embedded`) serve at `/.<id>/`. Override via `DevframeDefinition.basePath`.
18+
- **Context-aware mount paths.** Standalone adapters (`cli`, `build`) serve at `/` by default; hosted adapters (`vite`, `embedded`) serve at `/.<id>/`. Override via `DevframeDefinition.basePath`.
1919
- **SPAs own their base at runtime.** Build with relative asset paths (`vite.base: './'`); `connectDevframe` discovers the effective base from the executing script's location.
2020
- **CLI flags compose.** The `cac` instance is exposed to both the devframe (`cli.configure`) and the caller of `createCac`, so capability flags and app flags merge cleanly.
2121

0 commit comments

Comments
 (0)