Skip to content

feat: expose WebSocket serverOptions for crossws adapter #3925

@productdevbook

Description

@productdevbook

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions