Releases: colyseus/colyseus
@colyseus/sdk v0.17.43
- Fix
client.getLatency()(and thereforeClient.selectByLatency()) hanging on unresponsive endpoints. The measurement only settled on a pong oronerror, so a server that closed the socket cleanly without replying (onlyonclosefires) left the promise pending forever, and a blackholed/filtered host stalled until the OS-level TCP timeout.getLatency()now also rejects ononcloseand on a configurabletimeout(LatencyOptions.timeout, default1500ms, also forwarded throughselectByLatency()), so a single wedged endpoint can no longer stall the whole selection. Closes #941 — thanks @TJEvans for reporting!
@colyseus/core v0.17.43
- Fix
defineServer()+server.listen()not configuringRedisDriver/RedisPresenceon Colyseus Cloud. TheServerconstructor was pre-instantiatingLocalPresence/LocalDriver, shadowing the cloud auto-detection inmatchMaker.setup()(utils/Env.ts). Now passesoptions.presence/options.driverthrough as-is sogetDefaultPresence/getDefaultDrivercan pick Redis when running on Cloud. Env.tsgetDefaultPresence/getDefaultDrivernow gate Redis selection onos.cpus().length > 1 || REDIS_URI, matching the existing behavior in@colyseus/tools. Single-CPU Cloud instances withoutREDIS_URIkeep using Local.- Guard
Server.gracefullyShutdown()againstpresence/driverbeing unset during the brief window beforematchMaker.setup()resolves (relevant when setup is slow, e.g. Redis client connecting).
@colyseus/sdk v0.17.42
- Fix
H3Transportframe reassembly: a single WebTransportreader.read()is not guaranteed to land on a frame boundary, so chunks ending mid-payload or mid-varint-prefix caused sporadic handshake failures andROOM_STATE_PATCHdecode errors on rooms with larger initial state. The reader now buffers partial data across reads and only dispatches complete length-prefixed frames. Closes #934 — thanks @anaibol for reporting and contributing the initial fix!
@colyseus/h3-transport v0.17.11
- Fix
H3Clientframe reassembly: buffer partial frames acrossreader.read()calls on both the bidirectional stream and datagram reader. A chunk ending mid-payload or inside the varint length prefix no longer causes truncated message dispatch or aborted read loops. Mirrors the SDK-side fix — thanks @anaibol for reporting!
colyseus v0.17.10
Vite plugin fixes
-
Fix
expressinterop in dev mode.(await dynamicImport('express')).defaultcould resolve toundefinedin some ESM module-loader setups, causing the plugin to silently fall back to[colyseus] Express not available. Install express to use the express option.The plugin now accepts both shapes viaexpressModule?.default ?? expressModule. (thanks to @ASteinheiser) -
Support
server.middlewareMode. When Vite is wrapped by a custom parent server (e.g. Express hosting GraphQL alongside the Vite dev middleware), the Colyseus plugin previously threw[colyseus] Vite HTTP server not available.becauseserver.httpServeris null in middleware mode. A newhttpServerplugin option lets you pass your ownhttp.Serverfor the WebSocket transport to attach to:import http from 'http'; import express from 'express'; import { createServer as createViteServer } from 'vite'; import { colyseus } from 'colyseus/vite'; const app = express(); const httpServer = http.createServer(app); const vite = await createViteServer({ plugins: [ colyseus({ serverEntry: '/src/server/index.ts', httpServer }), ], server: { middlewareMode: true }, appType: 'custom', }); app.use(vite.middlewares); httpServer.listen(3000);
-
Await async
expresscallback. The dev-mode path now awaitsconfig.options.express(expressApp)so async setup (e.g.await apolloServer.start()before mountingexpressMiddleware) resolves before any request is served, matching the behavior ofbeforeListen.
@colyseus/core v0.17.42
defineServer()/new Server():expresscallback can now return aPromise<void>, and is awaited before the transport is marked ready. This lets async setup inside the callback (e.g.await apolloServer.start()) complete before any request is served.
@colyseus/sdk v0.17.41
- Isolate
debug.jspanel inside a Shadow DOM root so page-level CSS (e.g. a globalcanvas { width: 100vw }rule) can no longer stretch or restyle the debug UI.
@colyseus/traefik v0.17.7
- Add IPv6 support for
internalAddress. Bracketed ([::1]:2567) and bare
(fd12::1) forms are accepted, and registered URLs are properly bracketed. autoDetectInternalIP()now falls back to the first non-internal,
non-link-local IPv6 address when no routable IPv4 is available — needed for
IPv6-only private networks (e.g. Railway).
@colyseus/sdk v0.17.40
- Fix
client.http.*type inference wrongly requiringqueryandparamson endpoints that declared neither (most visible understrictNullChecks: false). Closes #933 - thanks @thedomeffm for reporting!
colyseus v0.17.9
Vite Integration
First-class Vite plugin that lets you develop and build your multiplayer game from a single config.
npm install colyseus viteSetup — create a vite.config.ts:
import { defineConfig } from 'vite';
import { colyseus } from 'colyseus/vite';
export default defineConfig({
plugins: [
colyseus({
serverEntry: '/src/server/index.ts',
serveClient: true,
}),
],
});Server entry — define rooms, routes, and middleware in one place:
// src/server/index.ts
import { defineServer, defineRoom, createRouter, createEndpoint, monitor } from 'colyseus';
import { MyRoom } from './MyRoom';
export const server = defineServer({
rooms: {
my_room: defineRoom(MyRoom),
},
express: (app) => {
app.use('/monitor', monitor());
},
routes: createRouter({
hello: createEndpoint("/hello", { method: "GET" }, async (ctx) => {
return { message: "Hello world!" };
}),
}),
});Run npx vite — client and game server on the same port, no separate process.
Features:
- Shares Vite's dev HTTP server — WebSocket upgrades for room connections are filtered and forwarded to the Colyseus transport, everything else stays with Vite.
/matchmake/*endpoints are injected as middleware — client SDK connects to the same origin, no proxy or CORS needed.- Hot module reloading — edit room classes and see changes immediately. Running rooms preserve state and connected clients auto-reconnect.
@colyseus/monitor,@colyseus/playground, and any package importingmatchMakerwork correctly in dev mode.devModeis automatically enabled unless explicitly set tofalseindefineServer().
Production builds:
npx vite build --appProduces dist/client/ (static assets) and dist/server/server.mjs (standalone Node.js entry).
When serveClient: true is set, the production server automatically serves the built client files via express.static() with SPA fallback — deploy as a single process:
node dist/server/server.mjsPlugin options:
serverEntry(required) — path to your server entry module.port— port for the production server (default:2567).serveClient— serve built client files in production viaexpress.static()with SPA fallback (default:false).quiet— suppress per-reload log messages during development.loadWsTransport— custom transport loader (advanced).