feat(examples,docs): migrate reference hubs to initHub; Nitro & Hono examples, Bun smoke, framework guides - #172
Open
antfubot wants to merge 8 commits into
Open
feat(examples,docs): migrate reference hubs to initHub; Nitro & Hono examples, Bun smoke, framework guides#172antfubot wants to merge 8 commits into
antfubot wants to merge 8 commits into
Conversation
…er hooks createContextRpcServer owns everything about serving RPC that is independent of how peers connect (auth wiring, session resolver, auto-trust shim); createWsRpcPeerHooks shapes the per-peer lifecycle for any crossws adapter. startHttpAndWs behavior is unchanged — it now composes the two, so other transports (fetch-upgrade runtimes) can reuse the same wiring.
… middleware createHandler(def) serves a devframe's whole surface — SPA, __connection.json discovery, WebSocket RPC, auth gate (on by default), and the optional MCP route — through one fetch handler mountable on any framework's catch-all route, plus a connect-style nodeMiddleware and Bun fetch-upgrade websocket hooks. WebSocket binding resolves by precedence: ws.port (explicit side-car) > server (shared upgrade at <base>__ws) > ws.url alone (no local transport; external server owns it) > Bun fetch-upgrade > eager auto side-car. ws.url always overrides the advertised endpoint (the tunnel pattern: bind locally, advertise the relay). A key option memoizes the handler on globalThis so HMR module re-evaluation can't leak side-cars (DF0053 on option changes; DF0054 for connectionMeta before ready). BREAKING CHANGE: the WS route unifies on `__ws` (was `__devframe_ws`) across every adapter, and the unused DEVFRAME_MOUNT_PATH / DEVFRAME_DIRNAME constants are removed.
…ing a DevframeInstance The factory is named for the instance it initiates (define → init pairing with defineDevframe), reached from the devframe/initiate subpath, and the web-standard request handler is a property — initDevframe(def).handler — matching the content.handler mounting model, so future capabilities extend the instance object instead of overloading a handler-named factory. - subpath: devframe/handler → devframe/initiate (src/adapters/initiate.ts) - createHandler → initDevframe; CreateHandlerOptions → InitDevframeOptions - DevframeHandler → DevframeInstance; fetch → handler - diagnostics/docs updated (DF0053/DF0054 wording)
…frames/next on initDevframe
One wiring underneath every serving path: the adapters become thin
assemblies over the devframe/initiate instance.
- createDevServer = initDevframe + a node listener (listen-first so the
shared WS tier reports the real port; DF0052 rejection preserved;
registry/openBrowser/onReady unchanged; ws/rpcGroup/connectionMeta
surfaced from the instance transport)
- viteDevBridge bridge mode = instance.nodeMiddleware on Vite's stack;
the WS upgrade now shares Vite's own http server at <base>__ws (zero
extra ports; pinned devMiddleware.port keeps the explicit side-car)
and MCP moves onto the Vite origin at <base>__mcp
- @devframes/next reduces to memoization + defaults sugar (key-memoized
instance; MCP same-origin through the catch-all route)
- initDevframe grows the host-integration options the adapters need:
app, distDir: false, origin getter, getStorageDir,
destroyUnmatchedUpgrades, onPeerConnect/onPeerDisconnect passthrough
- resolveDevServerPort / resolveMcpConnectionMeta move to adapters/_shared
(re-exported from adapters/dev unchanged)
BREAKING CHANGE: viteDevBridge and @devframes/next advertise same-origin
relative endpoints now — websocket { path: '__ws' } on the host origin
(or { port, path: '__ws' } for a pinned side-car) and mcp
{ path: '__mcp' } — instead of side-car-port absolute paths.
…hind one handler initHub() serves the whole multi-devframe devtools surface through one web-standard handler under a single namespace (default /__devframes/): every mounted devframe shares one hub context (merged RPC registry, shared state, docks/terminals/messages/commands), one WebSocket transport, and one hub Auth; frames serve at <base><id>/ with per-frame discovery pointing at the shared socket. - reserved layout: __connection.json, __ws, __index.json, __client-imports.js, __mcp (aggregate over the shared registry), embedded.js; frame ids validated against it (DF8000) - DevframeHubUi slot (pure data): ui.viewer owns the namespace root, ui.embedded serves the floating bootstrap at embedded.js — omitted, the hub stays fully headless and the root serves the index document - assembly modes: declarative devframes list (+ configure(ctx)) or a pre-built context (DF8002 when both); key memoization against dev-reload leaks (DF8001) - devframe: the Bun WS tier is promoted to the public devframe/rpc/transports/ws-bun subpath, createContextRpcServer is exported from devframe/node, and adapters/mcp exports mountMcpHttp — the primitives initHub composes - mountDevframe now mounts a frame's connection meta before its SPA statics so route-ordered hosts (h3) resolve the exact meta route ahead of the static catch-all
…b's ui slot A port of Vite DevTools' web components onto @devframes/hub, prebuilt into two entries the hub serves through DevframeHubUi: - embedded.js — the floating DockEmbedded bootstrap (single self- contained ES module; always visible by design — visibility policy belongs to whoever authors an embedded entry) - a standalone viewer SPA (vanilla shell mounting DockStandalone, relative asset paths, served at the hub base) createUi() returns the slot object pointing at the built artifacts. The components (dock shell, panels, command palette, messages/toasts, views, json-render catalog) are Vue custom elements with shadow-root styles compiled ahead of time from the shared devframe design system (@antfu/design sage-green preset); imports are rewired from @vitejs/devtools-kit onto @devframes/hub's client runtime, the view-mode machinery is removed, and branding/element names/storage keys move to the devframes namespace. Storybook follows the repo's shared vue3-vite setup. Co-developed with Vite DevTools — the components descend from vitejs/devtools (MIT).
… & Hono examples, Bun smoke, framework guides Both reference hosts now assemble through one initHub() call while keeping their hand-built viewer UIs as protocol demos: the Vite example shares Vite's own http server for the WS upgrade at /__devframes/__ws (zero extra ports) and the Next example collapses its encoded catch-all routes into a single app/%5F_devframes/[[...path]]/route.ts delegating to hub.handler. New minimal examples prove the middleware story end to end: - examples/nitro-devframe-hub — Nitro v3, one middleware delegation, devframe packages kept external so import.meta.url asset resolution survives bundling - examples/hono-devframe-hub — one runtime-agnostic app file served by @hono/node-server on Node and Bun.serve on Bun (fetch-upgrade tier); scripts/smoke-bun.ts exercises fetch + WS RPC + embedded.js on Bun initHub grows what the migrations needed: devframes entries with dock overrides, rpcDeclarations passthrough, a route-safe id guard (DF8004), a bind-retry for the auto side-car, and a buffered embedded.js body that survives dev-worker proxies. Docs: adapters/initiate (mount snippets for Vite/Nitro/Hono/Next/Nuxt/ SvelteKit, WS binding precedence, auth posture) and guide/hub-initiate (the namespace, the ui slot, single hub Auth, singular-vs-hub table).
atinux
reviewed
Aug 6, 2026
Comment on lines
+41
to
+51
| ```ts [Nitro] | ||
| // middleware/devtools.ts | ||
| import { defineHandler } from 'h3' | ||
| import { devtools } from '../devtools' | ||
|
|
||
| export default defineHandler((event) => { | ||
| const { pathname } = new URL(event.req.url) | ||
| if (pathname === '/__my-tool' || pathname.startsWith('/__my-tool/')) | ||
| return devtools.handler(event.req) | ||
| }) | ||
| ``` |
There was a problem hiding this comment.
Another solution is to create a server route, see: https://content.comark.dev/integrations/nitro#mount-the-handler
Suggested change
| ```ts [Nitro] | |
| // middleware/devtools.ts | |
| import { defineHandler } from 'h3' | |
| import { devtools } from '../devtools' | |
| export default defineHandler((event) => { | |
| const { pathname } = new URL(event.req.url) | |
| if (pathname === '/__my-tool' || pathname.startsWith('/__my-tool/')) | |
| return devtools.handler(event.req) | |
| }) | |
| ``` | |
| ```ts [Nitro] | |
| // routes/__my-tool/[...path].ts | |
| import { defineHandler } from 'nitro' | |
| import { devtools } from '../../devtools' | |
| export default defineHandler((event) => devtools.handler(event.req)) |
(not tested)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Top of the
/__devframes/standard-middleware stack (on #170). Seeplans/devframes-standard-middleware.md.Intent
Prove the whole stack end to end and document it:
examples/vite-devframe-hubandexamples/next-devframe-hubassemble through oneinitHub()call while keeping their hand-built viewer UIs as protocol demos. Vite shares its own http server for the WS upgrade at/__devframes/__ws(zero extra ports); Next collapses its encoded catch-all routes into oneapp/%5F_devframes/[[...path]]/route.tsdelegating tohub.handler.ui: createUi():nitro-devframe-hub(Nitro v3, one middleware delegation, devframe packages externalized soimport.meta.urlasset resolution survives bundling) andhono-devframe-hub(one runtime-agnostic app file —@hono/node-serveron Node,Bun.serve({ fetch, websocket })on Bun's fetch-upgrade tier).bun scripts/smoke-bun.tsboots the Hono hub underBun.serveand verifies discovery, a frame SPA,embedded.js, and a WS RPC round-trip over a same-origin upgrade — no side-car anywhere. Verified locally:adapters/initiate(mount snippets for Vite / Nitro / Hono / Next.js / Nuxt / SvelteKit, WS binding precedence, auth posture) andguide/hub-initiate(the namespace, theuislot, the single hub Auth, the singular-vs-hub table).devframesentries with dock overrides,rpcDeclarationspassthrough, route-safe id guard (DF8004), bind-retry for the auto side-car, bufferedembedded.jsbody that survives dev-worker proxies.Stack
Created with the help of an agent.