npm install @hydre/shimio- Node.js: >= 20.0.0
- ws: v8.x (upgraded from v7.x)
- ✨ 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)
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>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()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
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.
Upgrade to Node.js >= 20.0.0 before upgrading shimio to v5.0.0.
The shimio API remains unchanged. All client and server APIs are backward compatible.