feat(web): grow real node halves in connection and hmr
connection binds the web transport: it injects httpServer + apiProxy and registers toFetchHandler(ctx.apiProxy) under the /api prefix (the node:http to fetch bridge moves in from the webserver, keeping the res-close disconnect detection and drain/close backpressure waits). hmr owns dev reload: a stat-poll watch per graph row driven by clientModuleHost.onGraphChanged, rebuilt(id) on content change, and the /plugins/events SSE route (GET/HEAD guarded); frame types are single-sourced in events.ts shared by both halves.
This commit is contained in:
@@ -1,10 +1,36 @@
|
||||
/**
|
||||
* Connection plugin, node half. The package IS a dshClient plugin: the wire
|
||||
* consumer layer lives in its client half in full (src/client/ — contract:
|
||||
* api-contracts v3 section 3, inventory §3.2); consumers import the /client
|
||||
* subpath. The empty apply exists so the plugin appears in the host Loader
|
||||
* (lifecycle governance + dshClient discovery).
|
||||
* Connection plugin, node half: the host end of the web transport. Registers
|
||||
* the /api prefix route on the web server and bridges node:http requests to
|
||||
* the transport-agnostic fetch-shaped api handler. The wire consumer layer
|
||||
* lives in the client half (src/client/ — contract: api-contracts v3
|
||||
* section 3); consumers import the /client subpath.
|
||||
*/
|
||||
import type { Context } from 'cordis'
|
||||
// Type-only route import; it also carries the httpServer Context merge.
|
||||
import type { WebRoute } from '@deepseek-ai/dsh-host-webserver'
|
||||
import { toFetchHandler } from '@deepseek-ai/dsh-host-apiproxy'
|
||||
import { API_PATH } from './api-path.ts'
|
||||
import { bridge } from './http-bridge.ts'
|
||||
|
||||
/** Host plugin body — no host-side behavior for the connection plugin. */
|
||||
export function apply(_ctx: unknown): void {}
|
||||
export { API_PATH } from './api-path.ts'
|
||||
|
||||
/** Cordis plugin name. */
|
||||
export const name = 'client-connection'
|
||||
|
||||
/** Required services: the route registry and the api gateway. */
|
||||
export const inject = ['httpServer', 'apiProxy']
|
||||
|
||||
/**
|
||||
* Mount the /api transport: wrap the api gateway into a fetch handler and
|
||||
* serve it under the /api prefix.
|
||||
* @param ctx - host plugin context carrying httpServer and apiProxy.
|
||||
*/
|
||||
export function apply(ctx: Context): void {
|
||||
const apiHandler = toFetchHandler(ctx.apiProxy)
|
||||
const route: WebRoute = {
|
||||
kind: 'prefix',
|
||||
path: API_PATH,
|
||||
handler: (req, res) => bridge(req, res, apiHandler),
|
||||
}
|
||||
ctx.effect(() => ctx.httpServer.register(route), 'client-connection: /api route')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user