Skip to content

Commit 58d7c12

Browse files
committed
fix: green up hub-hono-minimal typecheck and rewrite the 0.9 migration guide
The `unit-test / lint` CI job runs `pnpm typecheck`; `hub-hono-minimal` had a latent, cache-masked failure (unresolved `Bun` global in the Bun entry and a hono `ServerType` vs `node:http` `Server` mismatch). Type the Bun entry's slice locally instead of pulling `@types/bun`, and narrow the hono server cast. Revise `docs/guide/migration-0.9.md` end to end so it describes the final 0.9 surface: `startHttpAndWs` and `mountDevframe` are now documented as removed (in favor of `createDevServer`/`initDevframe`/`initHub` and `ctx.install`), the new opt-in `register` flag is covered, and the internals-move table reflects `StartedServer` (not `startHttpAndWs`) relocating to `devframe/internal`.
1 parent 3b9c175 commit 58d7c12

3 files changed

Lines changed: 79 additions & 3 deletions

File tree

‎docs/guide/migration-0.9.md‎

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,63 @@ The low-level primitives shared between `devframe` and its first-party integrati
145145
| Moved | From | To |
146146
|---|---|---|
147147
| `createH3DevframeHost` (+ `CreateH3DevframeHostOptions`) | `devframe/node` | `devframe/internal` |
148-
| `startHttpAndWs` (+ `StartedServer`, `StartHttpAndWsOptions`) | `devframe/node` | `devframe/internal` |
149148
| `createContextRpcServer` (+ `ContextRpcServer`, `CreateContextRpcServerOptions`) | `devframe/node` | `devframe/internal` |
149+
| `StartedServer` (the `createDevServer` return handle) | `devframe/node` | `devframe/internal` |
150150
| `DevframeAgentHost` (class) | `devframe/node` | `devframe/internal` |
151151
| `coerceAgentPositionalArgs` (+ `AgentArgsFallback`) | `devframe/node` | `devframe/internal` |
152152
| `registerDevframeInstance` / `listLiveDevframeInstances` (+ `DevframeInstanceRecord`, `DevframeInstanceRegistration`) | `devframe/node` | `devframe/internal` |
153153
| `normalizeHttpServerUrl` | `devframe/node` | `devframe/internal` |
154154

155-
A host that stands up its own server composes from `devframe/internal` — `createH3DevframeHost` for the node `DevframeHost`, `createContextRpcServer` + `devframe/rpc/transports/*` to bind a transport — plus `devframe/node`'s `createHostContext` and `devframe/node/hub-internals`. This is the path `@devframes/hub`'s `initHub` takes (in later releases `startHttpAndWs` was removed in favor of `initDevframe` / `initHub`). A custom host advertises itself with `registerDevframeInstance`, and a devtool enumerates running instances with `listLiveDevframeInstances`. Application code should prefer the adapters and `devframe/initiate`.
155+
A host that stands up its own server composes from `devframe/internal` — `createH3DevframeHost` for the node `DevframeHost`, `createContextRpcServer` + `devframe/rpc/transports/*` to bind a transport — plus `devframe/node`'s `createHostContext` and `devframe/node/hub-internals`. This is the path `@devframes/hub`'s `initHub` takes. A custom host advertises itself with `registerDevframeInstance` (or the new `register` flag, below), and a devtool enumerates running instances with `listLiveDevframeInstances`. Application code should prefer the adapters and `devframe/initiate`.
156+
157+
## `startHttpAndWs` is removed
158+
159+
The low-level "listen on a port + attach the WS transport" primitive is gone. `createDevServer`, `initDevframe`, and `initHub` own that binding internally now, resolving the transport from their own `server` / `ws` options — so the common paths never touch it. `StartHttpAndWsOptions` is removed with it; `StartedServer` stays (it is still `createDevServer`'s return handle, re-exported from `devframe/internal`).
160+
161+
| 0.8.x | 0.9 |
162+
|---|---|
163+
| `startHttpAndWs({ context, port, ... })` for a standalone tool | `createDevServer(def, { port, ... })` |
164+
| `startHttpAndWs(...)` inside a framework host | `initDevframe(def, { base, ... })` / `initHub({ base, ... })` |
165+
166+
A host that genuinely binds its own transport — a bare RPC socket, or a server it wires itself — composes the two public primitives `startHttpAndWs` used underneath: `createContextRpcServer` (`devframe/internal`) for the session/auth wiring, and a transport from `devframe/rpc/transports/*`.
167+
168+
```ts
169+
// 0.9 — bind the RPC socket onto a server you own
170+
import { createServer } from 'node:http'
171+
import { createContextRpcServer } from 'devframe/internal'
172+
import { attachWsRpcTransport } from 'devframe/rpc/transports/ws-server'
173+
174+
const httpServer = createServer()
175+
const { rpcGroup, onConnected, onDisconnected } = createContextRpcServer({ context, auth: false })
176+
attachWsRpcTransport(rpcGroup, { server: httpServer, onConnected, onDisconnected })
177+
httpServer.listen(port)
178+
```
179+
180+
## `@devframes/hub`'s `mountDevframe` is removed — use `ctx.install`
181+
182+
The free `mountDevframe(ctx, def, options)` function is replaced by an `install` method on the hub context. `MountDevframeOptions` is renamed `InstallDevframeOptions`. `initHub`'s declarative `devframes` list runs the same install path under the hood, so most hosts never call it directly.
183+
184+
| 0.8.x | 0.9 |
185+
|---|---|
186+
| `import { mountDevframe } from '@devframes/hub/node'` | removed — call `ctx.install` |
187+
| `await mountDevframe(ctx, def, opts)` | `await ctx.install(def, opts)` |
188+
| `MountDevframeOptions` | `InstallDevframeOptions` (from `@devframes/hub/node`) |
189+
190+
```ts
191+
// 0.8.x
192+
import { createHubContext, mountDevframe } from '@devframes/hub/node'
193+
194+
const ctx = await createHubContext({ host, cwd, mode: 'dev' })
195+
await mountDevframe(ctx, myDevframe)
196+
```
197+
198+
```ts
199+
// 0.9
200+
import { createHubContext } from '@devframes/hub/node'
201+
202+
const ctx = await createHubContext({ host, cwd, mode: 'dev' })
203+
await ctx.install(myDevframe)
204+
```
156205

157206
## `@devframes/hub` category order lives only on `/constants`
158207

@@ -185,6 +234,16 @@ const detach = hub.attach(serve({ fetch: app.fetch, port: 3000 }))
185234

186235
Calling `attach` / `handleUpgrade` on an instance that already owns a transport reports [`DF0055`](/errors/DF0055), and on the advertise-only `ws.url` tier [`DF0056`](/errors/DF0056).
187236

237+
## `initDevframe` / `initHub` can register themselves
238+
239+
An in-process host used to call `registerDevframeInstance` by hand to appear in the global instance registry (`~/.devframe/instances/`, read by `devframe connect` and the inspect plugin's Instances tab). Both factories now take an opt-in `register` flag that does it for them: a dynamic import that writes the record once the public origin resolves and removes it on `close()`. `createDevServer` registers this way automatically.
240+
241+
| 0.8.x | 0.9 |
242+
|---|---|
243+
| manual `registerDevframeInstance({ pid, port, origin, … })` + `unregister()` on every close path | `initHub({ base, register: true })` / `initDevframe(def, { base, register: true })` |
244+
245+
Pass an object to override individual record fields — `register: { id, name, rootDir }`. `registerDevframeInstance` / `listLiveDevframeInstances` remain on `devframe/internal` for hosts that drive the registry directly.
246+
188247
## The `key` option is removed; memoize on `globalThis`
189248

190249
`initDevframe` and `initHub` no longer memoize instances under a `key` (and the `DF0053` / `DF8001` replacement diagnostics are gone with it). A host that re-evaluates its modules in dev owns the memo, which makes the lifecycle visible at the call site:
@@ -227,3 +286,5 @@ Bun.serve({
227286
```
228287

229288
`examples/hub-hono-minimal` ships this wiring in [`src/bun.ts`](https://github.com/devframes/devframe/blob/main/examples/hub-hono-minimal/src/bun.ts), next to the Node entry's `hub.attach(server)`.
289+
</content>
290+
</invoke>

‎examples/hub-hono-minimal/src/bun.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ import { createContextRpcServer } from 'devframe/internal'
33
import { attachBunWsTransport } from 'devframe/rpc/transports/ws-bun'
44
import { app, hub } from './app'
55

6+
// `Bun` is a global on the Bun runtime only; this is the Bun entry. Declare the
7+
// slice this file uses so `tsc` (Node types only, no `@types/bun`) can check it
8+
// — typing the `fetch` callback's params here is also what keeps them from
9+
// being implicitly `any`.
10+
declare const Bun: {
11+
serve: (options: {
12+
port: number
13+
fetch: (request: Request, server: unknown) => Response | Promise<Response>
14+
websocket: unknown
15+
}) => { readonly port: number, stop: (closeActiveConnections?: boolean) => void }
16+
}
17+
618
/**
719
* The Bun entry. Bun serves HTTP through the same `app.fetch` as Node, but
820
* WebSockets arrive as fetch upgrades rather than `node:http` `upgrade`

‎examples/hub-hono-minimal/src/server.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Server } from 'node:http'
12
import process from 'node:process'
23
import { serve } from '@hono/node-server'
34
import { app, hub } from './app'
@@ -10,7 +11,9 @@ import { app, hub } from './app'
1011
// for one instead with `ws: { sidecar: true }`.
1112
const port = Number(process.env.PORT ?? 5179)
1213

13-
const server = serve({ fetch: app.fetch, port, hostname: '0.0.0.0' })
14+
// `serve()` returns `ServerType` (its http/http2 union); the default is a
15+
// plain `node:http` server, which is what `hub.attach` routes upgrades on.
16+
const server = serve({ fetch: app.fetch, port, hostname: '0.0.0.0' }) as unknown as Server
1417
const detach = hub.attach(server)
1518

1619
process.on('SIGINT', () => {

0 commit comments

Comments
 (0)