UNPKG

playsocketjs

Version:

WebSocket wrapper for creating simple multiplayer systems with ease.

234 lines (170 loc) 9.27 kB
# PlaySocket Client A reactive, optimistic WebSocket library that simplifies game & app development by abstracting away complex sync logic. ## Why use PlaySocket? PlaySocket eliminates the traditional complexity of collaborative experiences: - **Streamlined architecture**: No additional backend code is required, but server-authoritative behavior supported - **State synchronization**: Built-in storage system keeps the full state synchronized across all clients, always conflict-free and in order - **Resilient & secure connections**: Automatic reconnection handling & strict rate-limiting - **Lightweight**: Uses WebSockets for efficient, predictable, reliable communication and has little dependencies ## Installation ```bash npm install playsocketjs ``` ## Usage examples Note that in production, you should **always try...catch** promises, such as socket.init() – they can reject! Initializing the client: ```javascript import PlaySocket from 'playsocketjs'; // Create a new instance const socket = new PlaySocket('unique-client-id', { // You can pass no ID to let the server pick one endpoint: 'wss://example.com/socket' }); // Set up event handlers (optional) socket.onEvent('status', status => console.log('Status:', status)); socket.onEvent('error', status => console.log('Error:', status)); const clientId = await socket.init(); // Initialize the socket ``` Creating a room: ```javascript // Create a new room const roomId = await socket.createRoom(); // Optionally, with initial storage const roomId = await socket.createRoom({ players: ["this-player"], latestPlayer: null, }); ``` Joining a room: ```javascript await socket.joinRoom('room-id'); // Join an existing room ``` Leaving a room: ```javascript socket.destroy(); // To leave the room, destroy the instance ``` Using the storage update event for reactivity: ```javascript const reactiveVariable = useState(); // Or $state(), reactive(), depending on your framework socket.onEvent('storageUpdated', storage => (reactiveVariable = storage)); // Assign on update ``` Interfacing with the synchronized storage (examples): ```javascript const currentState = socket.getStorage; // Synchronous, local access socket.updateStorage('players', 'array-add-unique', { username: 'Player4', level: 2 }); // Special method to enable conflict-free additions for arrays socket.updateStorage('latestPlayer', 'set', 'Player4'); // Regular synced storage update ``` Sending traditional requests to the server: ```javascript socket.sendRequest('chosen-request-name', { fact: "You can build server-authoritative logic using this!" }) ``` ## API Reference ### Constructor Creates a new PlaySocket instance with a specified ID and configuration options. The ID can be set to `null` to let the server pick a unique one. ```javascript new PlaySocket(id?: string, options: PlaySocketOptions) ``` #### Configuration options - `endpoint`: WebSocket server endpoint (e.g., 'wss://example.com/socket') - `customData`: You can pass arbitrary data to the "clientRegistered" server event (optional) - `debug`: Set this property to true to enable extra logging ### Methods - `init()`: Initialize the WebSocket connection – Returns Promise (async) which resolves with the client's ID - `createRoom(initialStorage?: object, maxSize?: number)`: Create a new room and become host – Returns Promise (async) which resolves with the room ID (matches the creator's ID) - `joinRoom(hostId: string)`: Join an existing room – Returns Promise (async) - `destroy()`: Use this to leave a room and close the connection - `updateStorage(key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update the shared storage. Safely update arrays in storage by adding, removing, or updating items. UpdateValue is only required for the 'array-update-matching' operation type - `sendRequest(name: string, data?: any)`: Send requests to the server with optional custom data (handle these in the `requestReceived` server event) - `onEvent(event: string, callback: Function)`: Register an event callback #### Event types - `status`: Connection status updates (returns status `string`) - `error`: Error events (returns error `string`) - `instanceDestroyed`: Destruction event - triggered by manual .destroy() method invocation or by fatal errors and disconnects - `storageUpdated`: Storage state changes (returns storage `object`) - `hostMigrated`: Host changes (returns the new host's ID `string`) - `clientConnected`: New client connected to the room (returns client's ID `string`) - `clientDisconnected`: Client disconnected from the room (returns client's ID `string`, room ID (if available) `string`) ### Properties (Read-only) - `id`: Client's unique identifier on the WebSocket server - `isHost`: If this user is currently assigned the host role - `connectionCount`: Number of active client connections in room (without yourself) - `getStorage`: Retrieve storage object   # PlaySocket Server PlaySocket includes a server implementation that can be set up in seconds. ## Installation To use the server component, you'll need to install playsocketjs and the ws package: ```bash npm install playsocketjs ws ``` ## Usage examples Here are usage examples for a standalone server and an Express.js application. ### Standalone server ```javascript const PlaySocketServer = require('playsocketjs/server'); const server = new PlaySocketServer(); // Create and start the server (default path is /socket) // Gracefully disconnect all clients and close the server (optional) function shutdown() { server.stop(); process.exit(0); } // Handle both SIGINT (Ctrl+C) and SIGTERM (Docker stop) process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown); ``` ### Together with Express.js (or other Backend frameworks) ```javascript const express = require('express'); const http = require('http'); const PlaySocketServer = require('playsocketjs/server'); const app = express(); const httpServer = http.createServer(app); // Create PlaySocket server with your HTTP server const playSocketServer = new PlaySocketServer({ server: httpServer, path: '/socket' }); // Start the server httpServer.listen(3000, () => { console.log('Server running on port 3000'); }); // Gracefully disconnect all clients and close the server (recommended) function shutdown() { server.stop(); process.exit(0); } // Handle both SIGINT (Ctrl+C) and SIGTERM (Docker stop) process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown); ``` ## API Reference ### Constructor ```javascript new PlaySocket(options: PlaySocketServerOptions) ``` Creates a new PlaySocket Server instance with configuration options. ### Configuration options - `port`: Port to listen on (default: 3000, used only if no server provided) - `path`: WebSocket endpoint path (default: '/') - `server`: Existing http server (optional) - `debug`: Set this property to true to enable extra logging ### Methods - `stop`: Closes all active client connections, the websocket server and the underlying http server if it's standalone - `kick(clientId: string, reason?: string)`: Kick a client by their clientID – this will close their connection and set an error message - `onEvent(event: string, callback: Function)`: Register a server-side event callback - `getRoomStorage(roomId: string)`: Get a snapshot of the current room storage (returns storage `object`) - `updateRoomStorage(roomId: string, key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update the shared room storage from the server. #### Event types - `clientRegistered`: Client registered with the server (returns the client's ID `string`, customData `object`) - `clientRegistrationRequested`: Client requests to register (returns the client's ID `string`, customData `object`) – return `false` or a rejection reason `string` to block the registration - `clientDisconnected`: Client disconnected from the server (returns the client's ID `string`) - `clientJoinedRoom`: Client joined a room – note that clients can only leave by disconnecting (returns the client's ID `string`, room ID `string`) - `roomCreated`: Client created a room (returns room ID `string`) - `roomDestroyed`: Room was destroyed, this happens when all participants leave (returns room ID `string`) - `roomCreationRequested`: Room creation requested by client (returns `object` containing the client's ID `string`, room ID `string` and the initialStorage `object`) – if you return an `object` in the callback, it will take that as the initial storage instead - `storageUpdateRequested`: Room storage property update requested by client (returns `object` containing the client's ID `string`, room ID `string` and the update `object`) – if you return `false` in the callback, the update will be blocked - `requestReceived`: Request from client was received by the server (returns `object` containing client's ID `string`, if in room – room ID `string`, request name `string` and optional passed data of type `any`) ### Properties (Read-only) - `getRooms`: Retrieve the rooms object # License MIT