Communication
Event-driven messaging between clients and server - from single sessions to global broadcasts.
Client to server
Emitting from the client
Handling on the server
Handlers are registered on instances or domains. Events from a session are routed to all instances the session belongs to (and their domains) that have a handler for that event.
Targeting one instance: emitTo
client.emit() dispatches to every joined instance (and relevant domain) with a matching handler. client.emitTo() delivers to exactly one instance the session is a member of - never domain handlers, so nothing dispatches twice. Unknown and unauthorized targets get one generic Event target denied error that does not leak topology.Domain-level handlers
Domains can handle events themselves, so the same event name can mean different things in different domains - a
kick-userin the moderation domain is independent of any other domain's kick-user. Only sessions inside the domain trigger its handlers, so pairing a domain handler with domain roles gives you role-scoped commands for free.Mesh-wide handlers
Shop, wardrobe, game selection and admin events belong to no particular room. Register them on the mesh itself: they receive the event from any session - even one in no instance at all - after the instance and domain handlers. No middleware tricks needed.
ℹ
client.emitTo() stays scoped to its instance and never reaches mesh handlers.Server to client (targeted)
Request/response
Instances can answer client requests directly. The handler's return value resolves the client's promise. Throw a
PlayMeshError(code, message) to reject it with a machine-readable code; a plain throw new Error('...') rejects with that message and code APP_ERROR. Any other thrown value becomes a generic Request failed (code INTERNAL) so internals never reach the wire.Requests target one instance the client is currently a member of. They reject on timeout (10 seconds by default), on disconnect, and when the client leaves the target instance. Responses are correlated by a unique per-request id;
undefined and any JSON-compatible value are valid responses. Type both sides with a request map - a third generic on both SDKs:Instance broadcast
Broadcast to all sessions in an instance, across all nodes.
Filtered broadcast
Send only to the members matching a filter - players in range of an explosion, a team, everyone but the shooter. The filter sees each member's
sessionId and userId from cluster-wide presence, so recipients on any node are reached:For synced state, use
visibleTo instead.Moving players
The server can move a session between instances in one call:
session.move(to, from?) leaves from (default: every instance in the target's domain), then joins to. A role-protected target throws ROLE_REQUIRED before anything is left. mesh.moveUser(userId, to, from?) moves every session of a user on any node.Domain broadcast
Send to every session in any instance of a domain.
Global broadcast
Send to every connected session, across all domains and nodes.
Receiving on the client
Reserved events
⚠
Do not emit events with the
playmesh: prefix from application code. They are filtered on both sides.