Skip to content

feat(handler): add devframe/handler — initDevframe framework-agnostic middleware - #167

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

feat(handler): add devframe/handler — initDevframe framework-agnostic middleware#167
antfubot wants to merge 4 commits into
mainfrom
feat/handler-core

Conversation

@antfubot

@antfubot antfubot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Bottom of a 5-PR stack implementing the /__devframes/ standard-middleware plan (plans/devframes-standard-middleware.md, committed here).

Intent

Let any framework that can mount a catch-all route host a devframe: initDevframe(def) from devframe/initiate returns a live DevframeInstance whose .handler — a web-standard (request) => Promise<Response> — serves the SPA, __connection.json discovery, WebSocket RPC, the auth gate (on by default), and the optional MCP route. The instance also exposes a connect-style nodeMiddleware, Bun fetch-upgrade websocket hooks, ready, context, connectionMeta(), and close() — mirroring the content.handler mounting model (factory named for the instance, capabilities reached off it).

  • WebSocket binding by precedence: ws.port (explicit side-car) > server (shared upgrade at <base>__ws) > ws.url alone (no local transport) > Bun fetch-upgrade > eager auto side-car; ws.url always overrides the advertised endpoint (tunnel pattern). __connection.json reflects the active combination.
  • key option memoizes the instance on globalThis so dev-time module re-evaluation (Next/Nitro/SvelteKit HMR) can't leak side-car servers (DF0053 on option changes; DF0054 for connectionMeta() before ready).
  • Auth banner origin derives lazily from the first request.
  • Internals: transport-agnostic createContextRpcServer + reusable createWsRpcPeerHooks extracted from startHttpAndWs (no behavior change; carries the new onPeerDisconnect hook) so Node and Bun transports share one wiring.

Breaking changes

  • WS route unified on __ws (was __devframe_ws) across every adapter — matches upstream Vite DevTools' /__devtools/__ws.
  • Removed unused constants DEVFRAME_MOUNT_PATH, DEVFRAME_MOUNT_PATH_NO_TRAILING_SLASH, DEVFRAME_DIRNAME.

Stack

  1. feat/handler-core (this PR)
  2. feat/handler-adapters — createDevServer / viteDevBridge / @devframes/next rebuilt on the instance
  3. feat/hub-handler — headless @devframes/hub/initiate (initHub) with the ui slot
  4. feat/hub-ui — @devframes/hub-ui webcomponents port + createUi()
  5. feat/handler-examples-docs — examples + framework guides + Bun smoke test

Created with the help of an agent.

@netlify

netlify Bot commented Aug 6, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 4231c95
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a73e9d2a79f0900087692d2
😎 Deploy Preview https://deploy-preview-167--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.

…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.
@antfubot
antfubot force-pushed the feat/handler-core branch from 236ae62 to 1b8b4e4 Compare August 6, 2026 01:46
@antfubot antfubot changed the title feat(handler): add devframe/handler — framework-agnostic web-standard middleware feat(handler): add devframe/handler — initDevframe framework-agnostic middleware Aug 6, 2026
…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)
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.

1 participant