Skip to content

Commit 5dc9b97

Browse files
authored
refactor!: replace startHttpAndWs and mountDevframe with initHub/initDevframe and ctx.install (#192)
1 parent 3dc6b3e commit 5dc9b97

78 files changed

Lines changed: 904 additions & 1087 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/adapters/initiate.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Fetch handlers hand over `Request`s, so the RPC socket needs a binding of its ow
116116
3. **`ws: { sidecar: true }`** — a side-car server on a free port, for hosts whose handlers never see upgrades (Next.js route handlers, Nitro, Rsbuild).
117117
4. **The host's own upgrades** — with none of the above, the socket waits for the host to hand upgrade events over: `devtools.attach(server)` routes a server's `upgrade` events (returning a detach function), and `devtools.handleUpgrade(req, socket, head)` completes a single one from a listener you already own. This is the tier for hosts whose server exists only after the instance does, and it builds the transport lazily — an instance nobody attaches costs nothing.
118118

119-
`ws.url` controls the *advertisement* instead: the browser dials it verbatim. On its own it means an external server owns the transport and its auth (wire the instance's `context` into that server with `startHttpAndWs`); alongside a local binding it overrides only what is advertised — the tunnel pattern, where a relay forwards to the socket bound here.
119+
`ws.url` controls the *advertisement* instead: the browser dials it verbatim. On its own it means an external server owns the transport and its auth (wire the instance's `context` into that server by composing `createContextRpcServer` with a WS transport); alongside a local binding it overrides only what is advertised — the tunnel pattern, where a relay forwards to the socket bound here.
120120

121121
Whichever combination is active, `__connection.json` describes it and the browser client follows. Asking a configured instance to also take over host upgrades reports `DF0055` (a local binding already owns the socket) or `DF0056` (`ws.url` handed it to someone else).
122122

‎docs/errors/DF0007.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ outline: deep
1010
1111
## Cause
1212

13-
`getCurrentRpcSession()` was called outside the RPC dispatch context. Usually indicates the RPC server hasn't been composed with `startHttpAndWs` or the caller is running before the async context is established.
13+
`getCurrentRpcSession()` was called outside the RPC dispatch context. Usually indicates the RPC server hasn't been composed with the context transport binding (`createContextRpcServer`) or the caller is running before the async context is established.
1414

1515
## Fix
1616

‎docs/errors/DF0036.md‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@ outline: deep
1010
1111
## Cause
1212

13-
`startHttpAndWs` was configured with an `authorize` gate (either directly, or via a [`DevframeAuthHandler`](../guide/security) passed as `auth`) and the calling session hasn't satisfied it — the call is neither to an `anonymous:`-prefixed method (see `isAnonymousRpcMethod`) nor made by a trusted session.
13+
The RPC server was configured with an `authorize` gate (either directly, or via a [`DevframeAuthHandler`](../guide/security) passed as `auth`) and the calling session hasn't satisfied it — the call is neither to an `anonymous:`-prefixed method (see `isAnonymousRpcMethod`) nor made by a trusted session.
1414

1515
## Example
1616

1717
```ts
18-
import { startHttpAndWs } from 'devframe/node'
19-
import { createInteractiveAuth } from 'devframe/recipes/interactive-auth'
18+
import { createDevServer } from 'devframe/adapters/dev'
2019

21-
const auth = createInteractiveAuth(ctx)
22-
23-
await startHttpAndWs({ context: ctx, port: 9999, auth })
20+
// `auth` defaults to devframe's interactive gate; `initDevframe` / `initHub`
21+
// gate hosted instances the same way through their own `auth` option.
22+
await createDevServer(def)
2423

2524
// A browser that hasn't completed the handshake yet can still reach the
2625
// handshake methods themselves…
@@ -38,4 +37,4 @@ await client.call('some-plugin:do-something') // ✗ throws DF0036
3837

3938
## Source
4039

41-
- [`packages/devframe/src/node/server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/server.ts)`startHttpAndWs`'s resolver throws this when `authorize`/`auth.authorize` rejects a call.
40+
- [`packages/devframe/src/node/rpc-core.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/rpc-core.ts)`createContextRpcServer`'s resolver throws this when `authorize`/`auth.authorize` rejects a call.

‎docs/errors/DF0052.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ outline: deep
1010
1111
## Cause
1212

13-
`startHttpAndWs` tried to bind the HTTP server it owns to `host:port` and the underlying `listen()` call failed — most commonly `EADDRINUSE` (another process, often a previous devframe instance, is already bound to that port) or `EACCES` (insufficient permissions, typically a privileged port). The WS RPC transport is torn down before this error surfaces, so nothing is leaked.
13+
The instance's side-car / shared-server transport binding tried to bind the HTTP server it owns to `host:port` and the underlying `listen()` call failed — most commonly `EADDRINUSE` (another process, often a previous devframe instance, is already bound to that port) or `EACCES` (insufficient permissions, typically a privileged port). The WS RPC transport is torn down before this error surfaces, so nothing is leaked.
1414

1515
## Example
1616

1717
```ts
1818
// A previous instance is still bound to 4096:
19-
// await startHttpAndWs({ context, host: 'localhost', port: 4096 }) → DF0052
19+
// await createDevServer(def, { host: 'localhost', port: 4096 }) → DF0052
2020
```
2121

2222
## Fix
@@ -26,4 +26,4 @@ outline: deep
2626

2727
## Source
2828

29-
- [`packages/devframe/src/node/server.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/server.ts)`startHttpAndWs()` throws this when its owned HTTP server's `listen()` fails.
29+
- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts)the instance shell's HTTP+WS binding throws this when its owned HTTP server's `listen()` fails.

‎docs/errors/DF0056.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const tunnelled = initDevframe(def, {
3232

3333
## Fix
3434

35-
Drop `ws.url` to have the instance serve the socket, or pair it with `server` / `ws.port` / `ws.sidecar` for the tunnel pattern — a local binding that the advertised relay forwards to. To serve RPC from a server you wire yourself, run `startHttpAndWs({ context, server, path })` against the instance's `context` and keep `ws.url` pointed at it.
35+
Drop `ws.url` to have the instance serve the socket, or pair it with `server` / `ws.port` / `ws.sidecar` for the tunnel pattern — a local binding that the advertised relay forwards to. To serve RPC from a server you wire yourself, compose `createContextRpcServer` (`devframe/internal`) with a WS transport (`devframe/rpc/transports/ws-server`) against the instance's `context` and keep `ws.url` pointed at it.
3636

3737
## Source
3838

‎docs/errors/DF8002.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ initHub({ base: '/__devframes/', devframes: [git] })
2323

2424
// ✓ Good — bring your own context:
2525
const ctx = await createHubContext({ host: myHost, cwd })
26-
await mountDevframe(ctx, git)
26+
await ctx.install(git)
2727
initHub({ base: '/__devframes/', context: ctx })
2828
```
2929

‎docs/errors/DF8105.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ outline: deep
1010
1111
## Cause
1212

13-
`mountDevframe(ctx, def)` was called with a devframe whose `id` already belongs to another devframe mounted on the same hub. Devframes are deduplicated by `id`, and the definition's `duplicationStrategy` is `'warn'` (the default) or `'throw'`.
13+
`ctx.install(def)` was called with a devframe whose `id` already belongs to another devframe mounted on the same hub. Devframes are deduplicated by `id`, and the definition's `duplicationStrategy` is `'warn'` (the default) or `'throw'`.
1414

1515
## Fix
1616

@@ -21,8 +21,8 @@ Set `duplicationStrategy` on the definition to choose how duplicates are handled
2121
- `'throw'` — surface duplicates as a thrown error.
2222
- `'duplicate'` — let every instance coexist under a disambiguated dock id (`my-tool`, `my-tool-2`, …).
2323

24-
Otherwise, remove the redundant `mountDevframe` call so each devframe is mounted once.
24+
Otherwise, remove the redundant `ctx.install` call (or the duplicate `devframes` entry) so each devframe is mounted once.
2525

2626
## Source
2727

28-
- [`packages/hub/src/node/mount-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/mount-devframe.ts)`mountDevframe()` emits this when a devframe sharing an already-mounted `id` is mounted and the strategy is not `'duplicate'`.
28+
- [`packages/hub/src/node/install-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/install-devframe.ts)`ctx.install()` emits this when a devframe sharing an already-mounted `id` is installed and the strategy is not `'duplicate'`.

‎docs/errors/DF8106.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ outline: deep
1010
1111
## Cause
1212

13-
A mounted devframe's SPA loads in an iframe at its own base (e.g. `/__terminals/`) and calls `connectDevframe()`, which fetches `./__connection.json` relative to that base to discover the RPC/WebSocket endpoint. `mountDevframe` serves that file at each base by calling the host's `mountConnectionMeta(base)` alongside `mountStatic`.
13+
A mounted devframe's SPA loads in an iframe at its own base (e.g. `/__terminals/`) and calls `connectDevframe()`, which fetches `./__connection.json` relative to that base to discover the RPC/WebSocket endpoint. `ctx.install` serves that file at each base by calling the host's `mountConnectionMeta(base)` alongside `mountStatic`.
1414

1515
This diagnostic is reported when a devframe with a servable `cli.distDir` is mounted on a `DevframeHost` that does not implement `mountConnectionMeta`. The SPA's `./__connection.json` fetch then falls through to the host's HTML fallback, so the SPA cannot discover the endpoint and its panel stays empty or stuck loading — previously a silent failure.
1616

@@ -35,4 +35,4 @@ A static-snapshot host that bakes `__connection.json` into its served files can
3535

3636
## Source
3737

38-
- [`packages/hub/src/node/mount-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/mount-devframe.ts)`mountDevframe()` emits this when a devframe with a servable `distDir` is mounted on a host lacking `mountConnectionMeta`.
38+
- [`packages/hub/src/node/install-devframe.ts`](https://github.com/devframes/devframe/blob/main/packages/hub/src/node/install-devframe.ts)`ctx.install()` emits this when a devframe with a servable `distDir` is installed on a host lacking `mountConnectionMeta`.

‎docs/guide/client-context.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ A script that fails to import is logged and retried on the next dock update.
139139
Build the script as a single self-contained ES module — it loads outside any chunk graph or import map. Attach it when mounting the devframe:
140140

141141
```ts
142-
await mountDevframe(ctx, myDevframe, {
142+
await ctx.install(myDevframe, {
143143
dock: { clientScript: { importFrom: `/@fs/${myAgentBundlePath}` } },
144144
})
145145
```
@@ -152,14 +152,14 @@ The [a11y inspector](/plugins/a11y)'s in-page agent is the canonical client scri
152152

153153
## Iframe panels
154154

155-
Dock iframes are their own documents, so they connect themselves instead of reading the host page's context: the panel SPA calls `connectDevframe()`, which discovers `./__connection.json` relative to its own base — `mountDevframe` serves the hub's connection meta under every dock base for exactly this. The client script (host page) and the iframe panel then share the server through RPC and shared state, or a same-origin `BroadcastChannel` when the loop must survive static builds.
155+
Dock iframes are their own documents, so they connect themselves instead of reading the host page's context: the panel SPA calls `connectDevframe()`, which discovers `./__connection.json` relative to its own base — `ctx.install` serves the hub's connection meta under every dock base for exactly this. The client script (host page) and the iframe panel then share the server through RPC and shared state, or a same-origin `BroadcastChannel` when the loop must survive static builds.
156156

157157
## Shared-iframe soft navigation
158158

159159
A tool with many internal views — Nuxt DevTools' tabs, say — can surface each view as its own hub dock while they all share **one** live iframe, switching between them with client-side (soft) navigation instead of reloading. One iframe dock is the **anchor**: it owns a `frameId` and opts in with `subTabs`.
160160

161161
```ts
162-
await mountDevframe(ctx, nuxtDevtools, {
162+
await ctx.install(nuxtDevtools, {
163163
dock: { frameId: 'nuxt-devtools', subTabs: { protocol: 'postmessage' } },
164164
})
165165
```

‎docs/guide/hub-initiate.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ A devframe's SPA and RPC client code are byte-identical in both cases — that i
8282

8383
## Bring your own context
8484

85-
Hosts that assemble `createHubContext` + `mountDevframe` themselves (with their own `DevframeHost` serving the frames) pass the finished context instead of a `devframes` list:
85+
Hosts that assemble `createHubContext` + `ctx.install` themselves (with their own `DevframeHost` serving the frames) pass the finished context instead of a `devframes` list:
8686

8787
```ts
8888
const hub = initHub({ base: DEVFRAMES_HUB_BASE, context: ctx })

0 commit comments

Comments
 (0)