# websocket

> The websocket identity: WebSocket frames over an HTTP upgrade. Every directive and what is required.

`websocket` speaks WebSocket frames over an HTTP upgrade. The session persists across steps, so a solution can stage the upgrade in one step and fire frames in the next. The target is a base URL. The runtime computes the masked text frame, so a dynamic payload needs no hand-computed frame lengths.

## Write it in English

A websocket step reads as sentences: `send "<text>"`, `receive <n> bytes`, `receive until "<hex>"`, `timeout <n> seconds`, `close the connection`, and `expect ...`. The payload is sent as text (never hex-encoded).

## The directives

### send

`send "<text>"` is the text payload, sent as a masked WebSocket text frame. Variables are filled in as text. The `send hex` form does not apply here; the payload is sent as-is.

### receive

`receive <n> bytes` reads at most that many.

### receive until

`receive until "<hex>"` stops the read once this hex marker appears.

### timeout

`timeout <n> seconds` bounds the wait. Example: `timeout 5 seconds`.

### close

`close the connection` ends the session after this step.

### capture

`capture` pulls a value out of the received hex for later steps, and it reads as English. The `value after` shape captures the run of hex after a hex marker and hex-decodes it:

```text
websocket negotiate
  send "..."
  capture the value after "6f703a6f747270633a" as port_id
```

Later steps reference `{port_id}`. The regex form is still available: the pattern runs over the hex and group 1 is hex-decoded before storing (`capture port: "(....)"`).

### ws-text framing

The step's `send "<text>"` is treated as a UTF-8 text payload and wrapped into a masked WebSocket text frame with the length computed by the engine, so you never hand-compute frame lengths.

## Example

```text
websocket ws-rpc
  # send a JSON-RPC request over the open WebSocket
  send "{\"jsonrpc\":\"2.0\",\"id\":{port}}"
  receive 65536 bytes
  expect "..." in the response
```