# Versioned envelopes with an explicitly owned connection

> Documentation for Redweb 0.16.1. Install that exact version when following these examples.

Negotiate a finite protocol version before upgrade, then share stable envelopes and error codes between server and client.

This pattern demonstrates one API area. Application-specific names, credentials, assets, and policies may need to be supplied. Complete starter recipes include all required application files.

```js
import { SocketRoute } from 'redweb'

class ProtocolRoute extends SocketRoute {
  constructor() {
    super({
      path: '/match',
      handlers: [MoveHandler],
      protocol: {
        versions: ['2', '1'],
        binary: {
          maxBytes: 64 * 1024,
          encode: (state) => codec.encode(state),
          decode: (bytes) => codec.decode(bytes),
        },
      },
    })
  }
}

// Browser entry (bundle separately from server code)
import { ProtocolClient, ERROR_CODES } from 'redweb/client'
const socket = new WebSocket(
  'wss://game.example/match?redwebVersion=2'
)
const client = new ProtocolClient(socket, '2')

socket.addEventListener('message', (event) => {
  try {
    const message = client.parse(event)
    if (message.error?.code === ERROR_CODES.RATE_LIMITED) backOff()
  } catch (error) {
    console.error('Invalid server envelope', error)
  }
})

socket.addEventListener('open', () => {
  client.send('move', { x: 4, y: 2 }, { sequence: 17 })
})
```

## Notes and boundaries

- Browsers negotiate with redwebVersion in the query.
- requestId correlates; sequence expresses application ordering.
- Neither field promises durability or exactly-once delivery.
- ProtocolClient is the low-level envelope helper, not redweb-client. For generated server-TSX UI, bind typed handlers instead of writing this browser module.
