@hydre/shimio
v5.0.1
Published
A minimal multiplexed Websocket server and client
Readme
Install
npm install @hydre/shimioRequirements
- Node.js: >= 20.0.0
- ws: v8.x (upgraded from v7.x)
What's New in v5.0.0
- ✨ Upgraded to
wsv8.18.0 (from v7.3.1) - 🚀 Node.js 20+ support with native private methods and class properties
- 🧹 Removed Babel dependencies (no longer needed for modern Node.js)
- 📦 Modernized development dependencies
- 🔧 Simplified test scripts (removed
--harmonyflags)
Use
Client
threshold represent the maximum WebSocket bufferedAmount length
before starting to delay write operations
The client emit 3 events
connectedwhen connecteddisconnectedwhen disconnectedchannelwhen a new channel was openned
import Client from '@hydre/shimio/client'
const client = Client({
host: 'ws://0.0.0.0:3000',
threshold: 4096,
retry_strategy: attempts => 100 // retry connection every 100ms
})
// possible to pass an option object for testing in nodejs
// see https://github.com/websockets/ws/blob/41b0f9b36749ca1498d22726d22f72233de1424a/lib/websocket.js#L445
await client.connect({
headers: {}
})open some channel (must be awaited but do not make any network request so it's free)
const foo = await client.open_channel()
const bar = await client.open_channel()
const baz = await client.open_channel()- write is an async function in which you have to pass an Uint8Array
- read is an async Iterable
A channel emit a close event
await foo.write(Uint8Array.of(100))
await bar.write(Uint8Array.of(42))
await baz.write(Uint8Array.of(100))
for await const(chunk of bar.read)
console.log(chunk) // Uint8Array<42>Server
import Server from '@hydre/shimio/server'
import Koa from 'koa'
// not a Class
const server = Server({
koa: new Koa(),
timeout: 30_000, // dropping unresponding clients
on_upgrade: ({ request, socket, head, context }) => true, // authentication
on_socket : ({ socket, context }) => {
// the client opened a channel (and wrote at least once)
socket.on('channel', async channel => {
// let's send back all datas transparently
for await (const chunk of channel.read)
await channel.write(chunk)
})
},
channel_limit: 50, // prevent a client from openning too much channel (encoded on an Uint32 (4,294,967,295))
threshold : 4096, // max bufferedAmount before delaying writes
ws_options : { // @see https://github.com/websockets/ws
path : '/',
perMessageDeflate: false,
maxPayload : 4096 * 4,
},
request_limit: { // 20 request max every 10s
max : 20,
every: 1000 * 10,
},
time_between_connections: 1000 * 30, // min 30s between 2 connection for an ip
})
await server.listen(3000) // promisified for you folks
await server.close()Testing Pattern: Lazy Server Startup
For test environments, avoid auto-starting the server on module import. Instead, export startup/shutdown functions:
// src/index.js - Application setup
import Server from '@hydre/shimio/server'
import Koa from 'koa'
// Create server instance (does NOT start listening)
export const server = Server({
koa: new Koa(),
on_upgrade: () => true,
on_socket: ({ socket }) => {
socket.on('channel', async channel => {
for await (const chunk of channel.read)
await channel.write(chunk)
})
},
ws_options: { path: '/ws' }
})
// Export start/shutdown functions
export async function start() {
await server.listen(3000)
console.log('Server started on port 3000')
}
export async function shutdown() {
await server.close()
console.log('Server stopped')
}// src/server.js - Production entry point
import { start } from './index.js'
await start()// test/server.test.js - Tests create their own instances
import { describe, it, before, after } from 'node:test'
import Server from '@hydre/shimio/server'
import Koa from 'koa'
describe('Server tests', () => {
let server
before(async () => {
server = Server({ koa: new Koa(), /* ... */ })
await server.listen(4000)
})
after(async () => {
await server.close()
})
it('should work', async () => {
// test logic
})
})Key Points:
- The exported
serverinstance is never started in test environment - Tests create and manage their own server instances in
before/afterhooks - Production uses a separate entry point that calls
start() - This prevents tests from hanging due to open server connections
Migration from v4.x
Breaking Changes
ws v8 Import Changes
If you were importing ws directly in your code (not recommended, but if you did):
v4.x (ws v7):
import ws from 'ws'
const wss = new ws.Server({ port: 3000 })
globalThis.WebSocket = wsv5.0.0 (ws v8):
import { WebSocketServer } from 'ws'
import WebSocket from 'ws'
const wss = new WebSocketServer({ port: 3000 })
globalThis.WebSocket = WebSocketNote: If you only use @hydre/shimio/client and @hydre/shimio/server, no code changes needed! The ws v8 migration is handled internally.
Node.js Version
Upgrade to Node.js >= 20.0.0 before upgrading shimio to v5.0.0.
No Other Breaking Changes
The shimio API remains unchanged. All client and server APIs are backward compatible.
