No description
  • TypeScript 54.9%
  • JavaScript 43.6%
  • Shell 1.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-22 15:30:33 -04:00
.github/workflows build: remove dependabot config 2026-06-02 19:39:56 -04:00
scripts Move WebSocket server code to separate file test/websocket-server.js 2025-10-08 01:54:02 +00:00
src Update dependencies 2024-10-14 13:04:20 +00:00
test Move WebSocket server code to separate file test/websocket-server.js 2025-10-08 01:54:02 +00:00
.gitignore Ignore vitest screenshots 2025-10-07 22:08:12 -04:00
.npmrc build: adopt supply chain defaults 2026-06-02 16:36:39 -04:00
CODE_OF_CONDUCT.md Extract StableSocket module 2020-07-10 17:22:39 -06:00
CODEOWNERS Create CODEOWNERS 2023-08-16 13:43:51 -04:00
CONTRIBUTING.md Extract StableSocket module 2020-07-10 17:22:39 -06:00
LICENSE Extract StableSocket module 2020-07-10 17:22:39 -06:00
package-lock.json audit fix 2026-06-22 15:29:17 -04:00
package.json audit fix 2026-06-22 15:29:17 -04:00
README.md Update README.md 2020-07-26 00:35:34 -07:00
rollup.config.js Update assert syntax 2024-10-14 17:09:26 +00:00
SECURITY.md Extract StableSocket module 2020-07-10 17:22:39 -06:00
tsconfig.json Update dependencies 2024-10-14 13:04:20 +00:00
vitest.config.ts build: upgrade node 26 toolchain 2026-06-02 16:38:32 -04:00

StableSocket

A web socket that reconnects.

Installation

$ npm install @github/stable-socket

Usage

import {StableSocket} from '@github/stable-socket'

const delegate = {
  socketDidOpen(socket: Socket) {
    // Socket is ready to write.
    socket.send('Hello')
  },
  socketDidClose(socket: Socket, code?: number, reason?: string) {
    // Socket closed and will retry the connection.
  },
  socketDidFinish(socket: Socket) {
    // Socket closed for good and will not retry.
  },
  socketDidReceiveMessage(socket: Socket, message: string) {
    // Socket read data from the connection.
  },
  socketShouldRetry(socket: Socket, code: number): boolean {
    // Socket reconnects unless server returns the policy violation code.
    return code !== 1008
  }
}

const policy = {
  timeout: 4000,
  attempts: Infinity,
  maxDelay: 60000
}

const url = 'wss://live.example.com'
const socket = new StableSocket(url , delegate, policy)
socket.open()

BufferedSocket

Writing to a StableSocket while it is in the opening or closed states discards the message data. Use a BufferedSocket to buffer writes to be sent when it opens.

import {BufferedSocket, StableSocket} from '@github/stable-socket'
const socket = new BufferedSocket(new StableSocket(url, delegate, policy))
socket.open()
socket.send('hello') // Will be sent when the socket is open.

Asynchronous connections

StableSocket and BufferedSocket are abstractions over a WebSocket that maintain an internal state machine, managing reconnects and preventing writes to closed sockets. However, sometimes we need direct access to an open WebSocket in async functions.

connect

Asynchronously connects to a web socket port or fails after a timeout. The socket is open, and writable with send, when its promise is fulfilled. Returns a Promise fulfilled with an open WebSocket or rejected with a connection failure.

import {connect} from '@github/stable-socket'

try {
  const socket = await connect('wss://live.example.com', 100)
  socket.send('hi')
} catch (e) {
  console.log('Socket connection failed', e)
}

connectWithRetry

Asynchronously connects to a web socket port, retrying failed connections with exponential backoff. Returns a Promise fulfilled with an open WebSocket or rejected with a connection failure.

import {connectWithRetry} from '@github/stable-socket'

try {
  const policy = {timeout: 100, attempts: Infinity, maxDelay: 60000}
  const socket = await connectWithRetry('wss://live.example.com', policy)
  socket.send('hi')
} catch (e) {
  console.log('Socket connection failed', e)
}

Development

npm install
npm test

License

Distributed under the MIT license. See LICENSE for details.