feat: expose WebSocket serverOptions for crossws adapter
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 11.2k
- Forks
- 899
- Avg merge
- 2d 24m
- Merged PRs (30d)
- 40
Description
Problem
When using WebSocket with the graphql-ws protocol (for GraphQL subscriptions), browsers reject the connection with:
WebSocket connection failed: Error during WebSocket handshake:
Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
This happens because crossws's node adapter has handleProtocols: () => false hardcoded:
// crossws/dist/adapters/node.mjs
const wss = options.wss || new _WebSocketServer({
noServer: true,
handleProtocols: () => false, // ← Problem
...options.serverOptions // ← Solution exists but not exposed
});
The ws library uses handleProtocols to negotiate WebSocket subprotocols. When it returns false, browsers reject the handshake even if we manually add Sec-WebSocket-Protocol header in the upgrade hook.
Current Workaround
Adding the header manually in the upgrade hook works for Node.js clients but not for browsers:
defineWebSocketHandler({
upgrade(request) {
const protocol = request.headers.get('sec-websocket-protocol')
if (protocol?.includes('graphql-transport-ws')) {
return {
headers: { 'Sec-WebSocket-Protocol': 'graphql-transport-ws' }
}
}
}
})
Proposed Solution
Expose serverOptions in Nitro's WebSocket configuration so users can customize the crossws adapter:
// nitro.config.ts
export default defineNitroConfig({
features: {
websocket: true
},
websocket: {
serverOptions: {
handleProtocols: (protocols) => {
if (protocols.has('graphql-transport-ws')) {
return 'graphql-transport-ws'
}
return false
}
}
}
})
Or at minimum, allow passing serverOptions to the crossws adapter in the runtime presets.
Use Case
This is needed for GraphQL subscriptions over WebSocket using the graphql-ws protocol, which is the standard for:
- GraphQL Yoga
- Apollo Server
- Any GraphQL server implementing the graphql-ws spec
Environment
- Nitro: 3.0.1-alpha.1
- crossws: 0.4.1
- Node.js: 24.x
Related
- crossws adapter code: https://github.com/unjs/crossws/blob/main/src/adapters/node.ts
- graphql-ws protocol: https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the websocket configuration from nitro.config.ts into the runtime presets and the crossws adapter at src/adapters/node.ts. Verify how serverOptions can reach the adapter, then check the GraphQL subprotocol handshake; done means users can configure handleProtocols without the manual upgrade-hook workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, typescript
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100