npm.io
0.1.1 • Published 3 months ago

@moq/web-socket-stream

Licence
(MIT OR Apache-2.0)
Version
0.1.1
Deps
0
Size
29 kB
Vulns
0
Weekly
0
Stars
269

@moq/web-socket-stream

A polyfill for the WebSocketStream API, which exposes a WebSocket as a { readable, writable } pair of streams with backpressure on the writable.

WebSocketStream currently ships only in Chromium. This package wraps a plain WebSocket to present the same surface (opened, closed, close()) on every platform — browsers, Node, and Bun.

Note: a ponyfill can only approximate write backpressure by polling WebSocket.bufferedAmount against a high-water mark; only the native API observes the real send buffer. Use openWebSocketStream to get the native implementation when it's available.

Install

npm install @moq/web-socket-stream

Usage

Prefer native

openWebSocketStream returns the native WebSocketStream when present and falls back to this ponyfill otherwise:

import { openWebSocketStream } from "@moq/web-socket-stream"

const wss = openWebSocketStream("wss://example.com", { protocols: ["my-proto"] })
const { readable, writable, protocol } = await wss.opened

const reader = readable.getReader()
const writer = writable.getWriter()
await writer.ready          // backpressure
await writer.write(new Uint8Array([1, 2, 3]))
Global polyfill

Install as a global WebSocketStream if the platform doesn't ship one:

import { install } from "@moq/web-socket-stream"

// Only installs if native WebSocketStream is unavailable
install()

const wss = new WebSocketStream("wss://example.com")
Node / Bun

Modern Node and Bun expose a global WebSocket, which is used automatically. To use a specific implementation (e.g. the ws package), inject it — this forces the ponyfill:

import WebSocket from "ws"
import { WebSocketStream } from "@moq/web-socket-stream"

const wss = new WebSocketStream("wss://example.com", { webSocket: WebSocket, highWaterMark: 32 * 1024 })
Adopting an existing socket

A server has no URL to dial: the socket arrives from an HTTP upgrade, already open and with its subprotocol negotiated. adopt wraps one in place, resolving opened without waiting for an onopen that has already fired:

import { WebSocketStream } from "@moq/web-socket-stream"

const { socket, response } = Deno.upgradeWebSocket(req)
const wss = WebSocketStream.adopt(socket)
const { readable, writable } = await wss.opened

Adoption takes ownership of the socket's event handlers, so adopt it before anything else reads from it — messages delivered beforehand are dropped by the platform rather than buffered.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Keywords