Skip to main content
Version: 11.x

Class: ReconnectingWsTransport

Defined in: src/channel/transport/reconnectingWs.ts:42

A WsTransport that replaces its socket instead of dying with it.

The policy here is the one WebSocketChannel has shipped since 10.6.8, relocated rather than redesigned. In particular the split that makes reconnection safe is preserved exactly:

  • a request that was never put on the wire is queued and sent once the connection is back, which cannot duplicate anything because the node never saw it;
  • a request that was on the wire is rejected by the base class when the socket closes, and never replayed — only the caller knows whether resending it is safe.

Subscription restoration is not done here: the transport does not know what a subscription is. It exposes onReconnected, awaited after the new connection opens and before the queue is flushed, so a queued request cannot overtake the re-subscription it was queued behind.

This is the transport to build once at module scope and lend to everything that talks to the same node — one socket then serves them all, and it survives the drops a shared gateway imposes.

Example

const transport = new ReconnectingWsTransport({
nodeUrl: 'wss://your-starknet-node/rpc/v0_10',
});

const myProvider = new WebSocketProvider({ transport });
transport.on('statechange', () => console.log(transport.getState()));

Extends

Constructors

Constructor

new ReconnectingWsTransport(options): ReconnectingWsTransport

Defined in: src/channel/transport/reconnectingWs.ts:78

Parameters

options

ReconnectingWsTransportOptions

Returns

ReconnectingWsTransport

Overrides

WsTransport.constructor

Properties

nodeUrl

readonly nodeUrl: string

Defined in: src/channel/transport/ws.ts:90

The URL of the WebSocket RPC node.

Inherited from

WsTransport.nodeUrl


socket

socket: WebSocket

Defined in: src/channel/transport/ws.ts:98

The underlying socket. Owned by this transport — close it through close().

Not readonly because a subclass may replace it on a reconnection. This class never does: one WsTransport is one socket, which is what its own tests rely on.

Inherited from

WsTransport.socket


WsImplementation

protected readonly WsImplementation: WebSocketModule

Defined in: src/channel/transport/ws.ts:101

Kept so a subclass can build a replacement socket the same way this one was built.

Inherited from

WsTransport.WsImplementation

Accessors

queuesRequests

Get Signature

get queuesRequests(): boolean

Defined in: src/channel/transport/reconnectingWs.ts:95

Whether a request made right now would be held for a reconnection rather than sent.

Exposed so the WebSocketChannel façade can reproduce the refusal its send() used to raise: it refused only when nothing was going to pick the request up later.

Returns

boolean

Methods

onReconnected()

onReconnected(hook): () => void

Defined in: src/channel/transport/reconnectingWs.ts:105

Registers work to run after a reconnection opens, before the request queue is flushed.

Parameters

hook

() => Promise<void>

Returns

the unregister function.

() => void


onOpened()

protected onOpened(): void

Defined in: src/channel/transport/reconnectingWs.ts:112

What happens once a socket is open. Overridden by a reconnecting subclass, which also has a retry counter to reset and a queue to flush.

Returns

void

Overrides

WsTransport.onOpened


onClosed()

protected onClosed(): void

Defined in: src/channel/transport/reconnectingWs.ts:133

What happens once a socket is gone. This class stays closed; a reconnecting subclass starts an attempt instead.

Returns

void

Overrides

WsTransport.onClosed


onError()

protected onError(): void

Defined in: src/channel/transport/reconnectingWs.ts:146

What happens on a socket error. This class only logs; a reconnecting subclass treats it as a failed attempt, because a refused connection may produce an error with no close behind it.

Returns

void

Overrides

WsTransport.onError


request()

Call Signature

request(body): Promise<ResponseBody>

Defined in: src/channel/transport/reconnectingWs.ts:234

Sends the envelope, queueing it when the connection is down. See RpcTransport.request for the contract every transport honours.

A queued call is never left pending: it goes out when the socket comes back, and rejects with a WebSocketNotConnectedError if reconnection gives up or close is called. Note that requestTimeout only starts once the request is on the wire, so the reconnection settings — not requestTimeout — bound how long a queued call can wait.

Parameters
body

RequestBody

A request envelope, or an array of them for a batch.

Returns

Promise<ResponseBody>

The response envelope, or an array of them.

Overrides

WsTransport.request

Call Signature

request(body): Promise<ResponseBody[]>

Defined in: src/channel/transport/reconnectingWs.ts:235

Sends the envelope, queueing it when the connection is down. See RpcTransport.request for the contract every transport honours.

A queued call is never left pending: it goes out when the socket comes back, and rejects with a WebSocketNotConnectedError if reconnection gives up or close is called. Note that requestTimeout only starts once the request is on the wire, so the reconnection settings — not requestTimeout — bound how long a queued call can wait.

Parameters
body

RequestBody[]

A request envelope, or an array of them for a batch.

Returns

Promise<ResponseBody[]>

The response envelope, or an array of them.

Overrides

WsTransport.request


reconnect()

reconnect(): void

Defined in: src/channel/transport/reconnectingWs.ts:291

Manually opens a fresh connection, cancelling the effect of an earlier close().

Flagged as a reconnection so onOpened runs completeReconnection(): a manual reconnect owes the caller exactly what an automatic one delivers — subscriptions restored first, then the request queue flushed behind them. Without the flag the socket came back empty, which is the React StrictMode path: mount, cleanup close(), remount reconnect(), subscriptions silently lost.

Reporting 'reconnecting' rather than 'connecting' is the honest label, and it keeps queuesRequests true for the gap, so a request issued before the socket opens is queued instead of refused.

Returns

void


close()

close(code?, reason?): void

Defined in: src/channel/transport/reconnectingWs.ts:307

Closes the socket for good, and stops the automatic reconnection with it.

Any request still queued is rejected rather than left waiting for a connection that is no longer coming. Call reconnect to start over afterwards.

Parameters

code?

number

WebSocket close code sent to the node.

reason?

string

Human-readable close reason sent to the node.

Returns

void

Overrides

WsTransport.close


swapSocket()

protected swapSocket(next): void

Defined in: src/channel/transport/ws.ts:180

Adopts a replacement socket.

The readiness latch is discarded with the old socket: it records that that connection came up, and reusing it would let a request be written to a socket still handshaking.

Requests already on the wire are not settled here — handleClose has done that for the socket that went away, since nothing on a dead socket can still be answered.

Parameters

next

WebSocket

Returns

void

Inherited from

WsTransport.swapSocket


setState()

protected setState(next): void

Defined in: src/channel/transport/ws.ts:284

Parameters

next

WsTransportState

Returns

void

Inherited from

WsTransport.setState


getState()

getState(): WsTransportState

Defined in: src/channel/transport/ws.ts:295

The current connection state. The getSnapshot half of the useSyncExternalStore pair.

Returns

WsTransportState

Inherited from

WsTransport.getState


isConnected()

isConnected(): boolean

Defined in: src/channel/transport/ws.ts:300

Whether the socket is open right now.

Returns

boolean

Inherited from

WsTransport.isConnected


allocateRequestId()

allocateRequestId(): number

Defined in: src/channel/transport/ws.ts:312

Allocates the next wire id, starting at 0.

Exposed because a caller may write to the socket itself rather than through requestWebSocketChannel.send() is fire-and-forget and correlates nothing. Drawing from this same sequence is what stops such a write from colliding with a request this transport is tracking, which would hand one caller the other's reply.

Returns

number

Inherited from

WsTransport.allocateRequestId


on()

on<K>(event, listener): () => void

Defined in: src/channel/transport/ws.ts:327

Subscribes to one of the transport's two streams.

'statechange' fires on every connection state transition; 'notification' fires for every frame the node pushes on its own.

Type Parameters

K

K extends keyof WsTransportEvents

Parameters

event

K

listener

(payload) => void

Returns

the unsubscribe function, which is what useSyncExternalStore requires of its subscribe argument.

() => void

Inherited from

WsTransport.on


rejectPending()

protected rejectPending(reason): void

Defined in: src/channel/transport/ws.ts:482

Fails every request still on the wire.

Their only other exit is the requestTimeout timer, so without this the caller waits the whole timeout — 60s by default — for a reply that can no longer arrive, and that pending timer keeps the Node event loop alive for just as long.

Parameters

reason

string

Returns

void

Inherited from

WsTransport.rejectPending