Skip to content

feat(server): wire Server.listen() through native HttpApi listener (kill-switch) - #25595

Closed
kitlangton wants to merge 2 commits into
devfrom
kit/server-listen-native
Closed

feat(server): wire Server.listen() through native HttpApi listener (kill-switch)#25595
kitlangton wants to merge 2 commits into
devfrom
kit/server-listen-native

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

Summary

  • When the effect-httpapi backend is selected, Server.listen() now delegates to HttpApiListener.listen() (native Bun.serve + inline WS upgrades) instead of routing through the Hono runtime adapter (Hono.fetch + createBunWebSocket).
  • The Hono backend path is unchanged.
  • New env var OPENCODE_HTTPAPI_LEGACY_LISTENER forces the effect-httpapi backend back through the Hono adapter as an escape hatch.

Why now

This is step 6a of the Hono deletion arc. Stacks on top of:

Together those got the native listener to functional parity with the Hono path. This PR finally gives it production traffic — on dev / beta / local install channels where OPENCODE_EXPERIMENTAL_HTTPAPI already defaults on. prod / latest channels still go through the Hono path until the rollout is complete.

Kill switch

OPENCODE_HTTPAPI_LEGACY_LISTENER=1

When set, the effect-httpapi backend goes back through adapter.create(app).runtime.listen() (i.e. Hono is wrapping the HttpApi handler again). Has no effect when the Hono backend is already selected. The flag is documented in flag.ts next to OPENCODE_EXPERIMENTAL_HTTPAPI.

What's NOT in this PR

  • Removing any Hono code. The Hono backend, middlewares, and routes are untouched. That's step 6b.
  • Node adapter for the native listener. Bun-only for now; BunHttpServer.layer is the only path that gives us Bun.serve's path-based WS upgrade hook.
  • Touching the --hono debug flag for Server.openapi() (kept for spec diffability).

Behavior diff for the native path

ConcernHono adapter pathNative listener path
HTTP routingHono → HttpApi via webHandlerHttpApi webHandler directly
WS upgrade (PTY)createBunWebSocketBun.serve#fetchserver.upgrade(...)
WS upgrade (workspace proxy)WorkspaceRouterMiddlewareServerProxy.websocketresolveWorkspaceProxy → inline bridge in httpapi-listener.ts
mDNS publishunchangedunchanged
Server.url module exportunchangedunchanged
listen({ port: 0 }) fallbackBun adapter handlesstart(4096) ?? start(0) (matches existing behavior)
Telemetryopencode.server.backend onlyadds opencode.server.listener=bun-native

Test plan

  • bun run typecheck clean (13/13)
  • bun run test test/server/ — 172 pass / 0 fail / 2 todo (covers the new httpapi-listener.test.ts workspace-proxy + PTY paths from feat(httpapi-listener): workspace-proxy WS forwarding #25594)
  • Manual: run opencode serve on a dev channel and exercise the SDK end-to-end
  • Manual: set OPENCODE_HTTPAPI_LEGACY_LISTENER=1 and confirm the Hono adapter path comes back (look for opencode.server.listener absent from the structured log)

Bridge workspace-proxy WebSocket upgrades inside the Bun.serve listener so
the Hono path's WorkspaceRouterMiddleware → ServerProxy.websocket flow has
a native equivalent. The HttpApi handler still owns HTTP; the listener now
also resolves the workspace target inline (?workspace=… or session lookup),
upgrades the client connection, and bridges it to a remote WebSocket with
queueing, subprotocol forwarding, and close-code propagation.
This unblocks flipping Server.listen() over to the new listener but does
not flip it — the Hono path remains canonical. Bun-only; node:http + ws
adapter is a follow-up (TODO inline).
…ill-switch)
When the effect-httpapi backend is selected, Server.listen() now delegates
to HttpApiListener.listen() — a native Bun.serve listener with inline
WebSocket upgrade handling — instead of routing through the Hono runtime
adapter (Hono.fetch + createBunWebSocket).
The Hono backend path is unchanged, and a kill-switch env var
(OPENCODE_HTTPAPI_LEGACY_LISTENER) forces the effect-httpapi backend back
through the Hono adapter as an escape hatch if the native listener
regresses for a user.
This unblocks the Hono deletion arc by giving the native listener real
production traffic on dev/beta/local channels (where
OPENCODE_EXPERIMENTAL_HTTPAPI defaults on) while leaving prod/latest
channels on the Hono path.
@kitlangton

Copy link
Copy Markdown
ContributorAuthor

Closing — redundant. The effect-httpapi backend already has full WS + proxy support via HttpApiProxy.websocket + workspace-routing middleware. The real fix is to swap adapter.createFetch for Effect's BunHttpServer.layer in Server.listen()'s effect-httpapi path. Replacement PR coming.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@kitlangton