Skip to content

feat(examples,docs): migrate reference hubs to initHub; Nitro & Hono examples, Bun smoke, framework guides - #172

Open
antfubot wants to merge 4 commits into
mainfrom
feat/handler-examples-docs
Open

feat(examples,docs): migrate reference hubs to initHub; Nitro & Hono examples, Bun smoke, framework guides#172
antfubot wants to merge 4 commits into
mainfrom
feat/handler-examples-docs

Conversation

@antfubot

@antfubot antfubot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Top of the /__devframes/ standard-middleware stack. See plans/devframes-standard-middleware.md.

Intent

Prove the middleware story across frameworks and make the mount ergonomics explicit.

initDevframe / initHub: base is required and exposed

Both factories now take a required base (the mount path is explicit at the call site — pass DEVFRAMES_HUB_BASE for the hub's /__devframes/) and echo the normalized value back as instance.base, so route guards and middleware reference it instead of repeating the magic string. Breaking: base is no longer optional.

Examples: renamed + a minimal family

  • Reference hosts (hand-built viewers): hub-vite, hub-next.
  • Minimal family — one initHub({ ui: createUi() }) handler mounted on the framework, the whole integration in the config/route file: hub-vite-minimal, hub-next-minimal, hub-nitro-minimal, hub-hono-minimal, hub-rsbuild-minimal.
  • Per @atinux's review, the Nitro example uses a catch-all server route (+ index route for the namespace root) rather than middleware; the Rsbuild example lazy-inits the hub inside server.setup so importing the config is side-effect free.
  • Breaking: example package names changed (vite-devframe-hubhub-vite, etc.).

Fixes found by dogfooding

  • hub-ui: Vite's lib build was inlining the embedded/standalone entry's own source as a data:video/mp2t URL (the new URL('...', import.meta.url) asset pattern), so the dock resolved its base from a data URL and connection discovery failed. Reading import.meta.url through a variable sidesteps it.
  • .gitignore now covers .next / .nitro / .output so knip (which respects gitignore) doesn't scan framework build output.

Verified

All five minimal examples boot and serve /, /__devframes/, __connection.json, __index.json, embedded.js, and a frame SPA (200s); bun scripts/smoke-bun.ts exercises the Bun fetch-upgrade tier end to end. Full gauntlet green: build, typecheck (incl. verify-typecheck-coverage), 1084 tests, lint, knip.

Created with the help of an agent.

Comment thread docs/adapters/initiate.md
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)
})
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Base automatically changed from feat/hub-ui to main August 6, 2026 10:23
… & 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 catch-all route (+ an
  index route for the namespace root), 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).
@antfubot
antfubot force-pushed the feat/handler-examples-docs branch from f60ca01 to 90930f8 Compare August 6, 2026 10:39
@netlify

netlify Bot commented Aug 6, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 493307b
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a752fbfbb8b2d00083c6fb1
😎 Deploy Preview https://deploy-preview-172--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@devframes devframes deleted a comment from antfubot Aug 6, 2026
…inline the module

Vite's lib build recognizes the literal `new URL('...', import.meta.url)`
asset pattern and was inlining the embedded/standalone entry's own source
as a `data:video/mp2t` URL — so at runtime the dock resolved its hub base
from that data URL instead of the served script URL, and connection-meta
discovery failed. Assigning import.meta.url to a variable first sidesteps
the pattern matcher; the base stays the real runtime URL.
Both initDevframe and initHub now take a required `base` option (the
mount path is explicit at the call site — pass DEVFRAMES_HUB_BASE for the
hub's conventional /__devframes/) and echo the normalized value back as
`instance.base`, so route guards and middleware reference it instead of
repeating the magic string.

BREAKING CHANGE: `base` is no longer optional on initDevframe/initHub.
…the hub-*-minimal family

The two reference hosts become hub-vite and hub-next; the middleware
demos become hub-nitro-minimal and hub-hono-minimal, joined by new
hub-vite-minimal, hub-next-minimal, and hub-rsbuild-minimal — each a
single initHub({ ui: createUi() }) handler mounted on its framework
(the whole minimal integration is the config/route file). The Nitro one
now uses a catch-all server route (+ index route) per @atinux's review;
the Rsbuild one lazy-inits the hub inside server.setup so importing the
config is side-effect free.

Also: .gitignore now covers .next/.nitro/.output so knip (which respects
gitignore) doesn't scan Next/Nitro build output; playwright/vitest/turbo/
knip/verify-typecheck-coverage/scripts/AGENTS/docs and the sidebar are
repointed at the new names, and docs gain a page per minimal example.

BREAKING CHANGE: example package names changed (vite-devframe-hub ->
hub-vite, next-devframe-hub -> hub-next, nitro/hono-devframe-hub ->
hub-nitro-minimal/hub-hono-minimal).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants