itty-sockets
v0.7.1
Published
WebSockets : simplified and minified.
Readme
Documentation | Discord
Say goodbye to WebSocket boilerplate.
Your own wrapper is bigger, I promise.
Or [optionally] go a step further and use the integrated itty.ws connection to send messages (zero-config, zero-tracking, 100% free).
Features ✨
- DX perks - JSON-in/out, queued messages, easy-reconnect, chainable everything
- Works with any JSON-based WebSocket server - it's just a raw WebSocket wrapper, after all
- Powerful routing - easily handle your own message formats
- Type-safe message handling - so your app knows what to expect
- No socket server needed - Use itty.ws public channels to get started even faster
- Tiny - under 500 bytes total
Basic Example
import { connect } from 'itty-sockets'
// connect to the channel
const channel = connect('wss://example.com')
channel
// log all messages
.on('message', e => console.log(e.message))
// send some messages
.send('hey!')
.send({ foo: 'bar' })Optional use with itty.ws public, privacy-first server
itty-sockets has been designed to work with the public itty.ws service for even easier integrations. With this path, it's possible to add realtime features without hosting a backend server at all. We recommend using this for testing, prototyping, or simple projects. As your needs expand, you can always replace itty.ws with your own server(s) - nothing in the client changes.
Using itty.ws channels provides a few features to the client (fully typed by passing the UseItty generic to connect):
connect<UseItty>('my-channel')- connect to a channel and go- adds
uid,alias, anddateto all messages - adds
joinandleaveevents to announce user changes - allows private messaging (by uid)
Installation
Option 1: Import
npm install itty-socketsimport { connect } from 'itty-sockets'Option 2: Just copy this snippet:
let connect=(e,s={})=>{let a,t,n=[],p={},o=()=>(a||(a=new WebSocket((/^wss?:/.test(e)?e:"wss://itty.ws/c/"+e)+"?"+new URLSearchParams(s)),a.onmessage=(e,s=JSON.parse(e.data),a=s?.message,t={...null==a?.[0]&&a,...s})=>[t.type,s.type?0:"message","*"].map(e=>p[e]?.map(e=>e(t))),a.onopen=()=>(n.splice(0).map(e=>a.send(e)),p.open?.map(e=>e(t)),t&&a?.close()),a.onclose=()=>(t=a=null,p.close?.map(e=>e(t)))),l),l={open:o,send:(e,s)=>(e=(s?`${s}`:"")+JSON.stringify(e),1&a?.readyState?a.send(e):n.push(e),o()),on:(e,s)=>((p[e?.[0]?e:"*"]??=[]).push(e?.[0]?s:a=>e?.(a)&&s(a)),o()),remove:(e,s)=>(p[e]=p[e]?.filter(e=>e!=s),l),close:()=>(1&a?.readyState?a.close():t=1,l),push:(e,s)=>(t=1,l.send(e,s))};return l};Note: This will lose TypeScript support.
Example 2 - Receiving basic messages
Assume the following simple client
import { connect } from 'itty-sockets'
connect('wss://example.com')
// listen for every message
.on('message', console.log)
// and just { type: 'chat' }
.on('chat',
({ user, text }) => console.log(`${user} says: ${text}`)
)Now let's assume the following 2 messages are sent:
// message 1
{
"type": "chat",
"user": "Kevin",
"text": "Hey!"
}// message 2
{
"date": 1754659171196,
"items": [1, 2, 3],
}This will output the following to the console:
// message 1
{ type: "chat", user: "Kevin", text: "Hey!" }
"Kevin says: Hey!"
// message 2
{ date: 1754659171196, items: [1, 2, 3] }Example 3 - Reconnection
Using itty-sockets, you can safely fire .open() on the connection at any time, even if already connected. All listeners will continue to work perfectly once reconnected.
const channel = connect('wss://example.com')
.on('message', console.log)
.on('open', () => console.log('connected'))
.on('close', () => console.log('disconnected'))
// we'll just reconnect every second - this is safe!
setInterval(channel.open, 1000)