Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,38 @@ jobs:
lint: pnpm run lint && pnpm run knip
build-for-lint: true

# The RPC transport binds a native WebSocket on Bun/Deno (crossws's
# Bun/Deno adapters over `Bun.serve` / `Deno.serve`) and falls back to SSE
# for a shared foreign `node:http` server. This runs the cross-runtime smoke
# test under each runtime so that binding can't regress (issue #317).
runtime:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
runtime: [bun, deno]
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- name: Set up Bun
if: matrix.runtime == 'bun'
uses: oven-sh/setup-bun@v2
- name: Set up Deno
if: matrix.runtime == 'deno'
uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- run: pnpm install --frozen-lockfile
- name: Build devframe
run: pnpm --filter devframe run build
- name: Run the ${{ matrix.runtime }} RPC transport smoke test
run: pnpm run test:runtime:${{ matrix.runtime }}

e2e:
runs-on: ubuntu-latest
timeout-minutes: 15
Expand Down
32 changes: 32 additions & 0 deletions docs/content/6.errors/DF0075.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: 'DF0075: No RPC Transport On This Runtime'
description: 'On Bun/Deno a shared server needs crossws Node adapter and SSE is disabled, so no RPC transport is advertised.'
---

## Message

> On {runtime} the shared server's WebSocket upgrade needs crossws's Node adapter, which refuses to run off Node — and SSE is disabled, so this instance advertises no RPC transport at all.

## Cause

Sharing a host's `node:http` server (the `server` tier) drives the WebSocket upgrade through crossws's Node adapter, which runs only on Node. On Bun and Deno the socket falls back to the SSE endpoint — but here `sse: false` turned that endpoint off too, so the instance has no way for a client to reach its RPC surface.

## Example

```ts
import { initHub } from '@devframes/hub/initiate'

// Running on Bun/Deno, sharing the host's node:http server:
const hub = initHub({
server: viteHttpServer,
sse: false, // ✗ removes the only transport left on Bun/Deno
})
```

## Fix

Keep the SSE endpoint enabled (drop `sse: false`) so clients connect over it on Bun/Deno, or move the socket to a side-car — `ws: { sidecar: true }` binds the native WebSocket adapter (`Bun.serve` / `Deno.serve`) on its own port, where a real WebSocket works.

## Source

- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell warns this when a shared-server WebSocket binding falls back on Bun/Deno and the SSE endpoint is disabled, for both `initDevframe` and `initHub`.
30 changes: 30 additions & 0 deletions docs/content/6.errors/DF0076.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: 'DF0076: WebSocket Upgrade Unsupported On This Runtime'
description: 'attach / handleUpgrade drive a raw node:http upgrade into crossws Node adapter, which refuses to run on Bun/Deno.'
---

## Message

> `attach` / `handleUpgrade` drive a raw `node:http` upgrade into crossws's Node adapter, which refuses to run on {runtime}.

## Cause

`attach(server)` and `handleUpgrade(req, socket, head)` hand a raw `node:http` upgrade socket to crossws's Node adapter. That adapter runs only on Node — Bun and Deno expose WebSockets as `fetch` upgrades through `Bun.serve` / `Deno.serve` instead, so there is no `node:http` upgrade socket for the adapter to take over.

## Example

```ts
import { initHub } from '@devframes/hub/initiate'

// Running on Bun/Deno:
const hub = initHub({ base: '/__devframes/' })
hub.attach(myNodeHttpServer) // ✗ throws DF0076 on Bun/Deno
```

## Fix

On Bun/Deno, serve the advertised `__ws` route from `Bun.serve` / `Deno.serve` and complete the upgrade with `attachBunWsTransport` / `attachDenoWsTransport` (see the `hub-deno-minimal` example), or connect over the SSE endpoint instead — it rides the instance's ordinary HTTP surface and needs no upgrade wiring. A side-car (`ws: { sidecar: true }`) also binds the native WebSocket adapter for you on its own port.

## Source

- [`packages/devframe/src/node/instance-shell.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/instance-shell.ts) — the shared instance shell throws this from `attach` / `handleUpgrade` on Bun/Deno, for both `initDevframe` and `initHub`.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"test": "pnpm run build && vitest",
"test:e2e": "pnpm run build && playwright test",
"test:e2e:ui": "pnpm run build && playwright test --ui",
"test:runtime": "tsx packages/devframe/test/runtime-smoke.ts",
"test:runtime:bun": "bun packages/devframe/test/runtime-smoke.ts",
"test:runtime:deno": "deno run -A --node-modules-dir=manual packages/devframe/test/runtime-smoke.ts",
"test:ecosystem": "tsx scripts/ecosystem-ci.ts",
"release": "bumpp -r",
"typecheck": "pnpm run verify:typecheck-coverage && turbo run typecheck",
Expand Down
10 changes: 10 additions & 0 deletions packages/devframe/src/node/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,15 @@ export const diagnostics = defineDiagnostics({
`\`rpc.snapshot\` names "${p.method}", but no RPC function is registered under that id — nothing to bake into the static build.`,
fix: 'Check the method id, and ensure the service/plugin that registers it is installed (e.g. declared in `services`) before the build collects the dump.',
},
DF0075: {
why: (p: { runtime: string }) =>
`On ${p.runtime} the shared server's WebSocket upgrade needs crossws's Node adapter, which refuses to run off Node — and SSE is disabled, so this instance advertises no RPC transport at all.`,
fix: 'Keep the SSE endpoint enabled (drop `sse: false`) so clients connect over it on Bun/Deno, or move the socket to a side-car (`ws: { sidecar: true }`) which binds the native WebSocket adapter on its own port.',
},
DF0076: {
why: (p: { runtime: string }) =>
`\`attach\` / \`handleUpgrade\` drive a raw \`node:http\` upgrade into crossws's Node adapter, which refuses to run on ${p.runtime}.`,
fix: 'On Bun/Deno, serve the advertised `__ws` route from `Bun.serve` / `Deno.serve` with `attachBunWsTransport` / `attachDenoWsTransport` (see the hub-deno-minimal example), or connect over the SSE endpoint instead.',
},
},
})
Loading
Loading