Client and server WebSocket interfaces for CoCreate. Send JSON envelopes from browsers or Node.js, route them through application handlers and the server mesh, and relay responses across browser contexts.
For complete API references, protocol event schemas, configuration guides, and examples, visit the CoCreate Socket Documentation.
- Documentation
- Client and server exports
- Client usage
- Client routing controls
- Browser-context delivery
- Connection
- Socket collection
- Message routing
- Client and socket selection
- Authorization
- Server mesh
- Heartbeat and disconnection
- Installation
- Announcements and roadmap
- About
- Tests
- How to Contribute
- License
This package now contains both implementations under src/client/ and src/server/. Both roles share one package and retain their own transport lifecycle.
import { SocketServer, SocketClient } from "@cocreate/socket";
// Separate entry points:
import Server from "@cocreate/socket/server";
import Client from "@cocreate/socket/client";The Node entry exports both roles. Browser builds resolve the client entry without loading Node server dependencies. The root default export is SocketClient for compatibility with generated CoCreate dependency loaders. The client retains its existing initialization on import. Use the server entry point to import only the server.
Messages use one envelope. The method selects the event or operation and the remaining properties contain its payload.
import { SocketClient } from "@cocreate/socket";
const response = await SocketClient.send({
method: "notification",
message: "The workspace was updated",
broadcast: false,
broadcastClient: true
});The socket client automatically supplies connection metadata including clientId, frameId, socketId, organization_id, uuid, and timeStamp.
clientIdidentifies the browser and is shared by its tabs, windows, and same-origin frames.frameIdidentifies one client runtime, such as a tab, window, or iframe.socketIdidentifies an individual WebSocket instance. It is generated for each socket and is not shared through session storage.broadcastcontrols server delivery.falsetargets the originating or selected client;truetargets eligible clients in the organization.broadcastClientcontrols whether a received server message is relayed to the browser's other same-origin contexts.broadcastSender: falseprevents the originating frame from firing normal method listeners for the response. The response still returns and resolves its UUID promise.
The socket server sends to one connected socket for each selected clientId. If one socket cannot be reached, it can try another socket belonging to that client. Browser-context distribution is then handled by the client when broadcastClient is enabled.
The client stores the complete relay payload in the localSocketMessages array of the shared system IndexedDB database. The messageQueue array uses the same internal database. Records retain organization_id for organization-scoped filtering, while application databases remain free of socket transport state. The client writes only the record ID and organization ID to the localSocketMessage local-storage key, allowing other contexts to retrieve the message without being constrained by local-storage value limits.
The native storage event fires in the other same-origin contexts, not in the context that performed the write. The receiving contexts read the IndexedDB record and fire their local listeners. Each new relay also removes records older than five seconds.
Initialize the socket manager with a CoCreate server instance. The server supplies its HTTP and/or HTTPS upgrade source along with optional authentication, authorization, usage, and mesh services.
import { SocketServer } from "@cocreate/socket";
const wsManager = await SocketServer.init(server);
server.wsManager = wsManager; // Existing integrations remain supported.
server.socket = wsManager.collection;The first WebSocket URL path segment is the organization_id. Connection options can be supplied as query parameters or as an encoded JSON WebSocket protocol value. Socket-client supplies socketId, clientId, client information, user information, and an authentication token.
The server groups each connection as:
organization_id -> clientId -> socketId -> WebSocket
clientIdidentifies a browser client and may have multiple connected sockets.socketIdidentifies one WebSocket connection.frameIdidentifies the originating client runtime, but is message metadata rather than a server-side delivery selector.
CoCreate Server exposes server.socket over the existing manager's live indexes and delivery implementation.
server.socket.get(socketId); // Original WebSocket object.
server.socket.set(socketId, { label: "editor" });
server.socket.size; // Live sockets in this process.
server.socket.send(envelope);
server.socket.delete(socketId); // Close and clean up.
server.socket.clients.get(clientId)?.get(socketId);
server.socket.organizations.get(organizationId)?.clients.get(clientId);
server.socket.organizations.get(organizationId)?.subscriptions;Socket collections support get, has, add, set, delete, clear, size, and iteration. set updates metadata in place without replacing transport methods, identity, or bookkeeping. It does not create missing sockets.
Client and organization collections support get, has, add, delete, clear, size, and iteration. All add methods accept an already authenticated WebSocket with id, clientId, and organization_id, using the existing connection lifecycle. Root add returns the socket; client and organization add return their corresponding record. Re-adding the same socket is idempotent; conflicting socket IDs are rejected.
Client deletion closes its sockets using the normal organization disconnect grace period. Organization deletion immediately evicts its sockets and presence. Operations preserve the existing orgConnected and orgDisconnected event flow. wsManager remains available for existing integrations.
Messages are JSON objects and must contain method. The same envelope is passed through application handlers and returned to clients.
{
method: "notification",
message: "The workspace was updated",
organization_id: "ORGANIZATION_ID",
clientId: "CLIENT_ID",
broadcast: false
}Incoming envelopes are dispatched as follows:
apienvelopes emit theapievent.- CRUD methods beginning with
storage,database,array,index, orobjectemit their complete method name. crdtandcursormessages enterserver.send().- Other messages emit the top-level portion of
method.
send(data) resolves recipients by organization and client:
broadcast: trueselects every client in the organization.socketIdidentifies the originating socket and its client.- A server-originated direct message can provide
clientIdas one string or an array of strings.
For each selected client, the server attempts its connected sockets in order and stops after the first successful write. The originating socket is tried first for its client, including subscription delivery. Subscription matches select clients, with other sockets for those clients available as fallbacks. A write succeeds only when the WebSocket send callback reports no error. This provides socket failover without sending duplicate copies to every socket belonging to the same browser client.
broadcastClient and broadcastSender are forwarded to socket-client. Browser-context relaying and originating-frame listener suppression are handled on the client; they do not change socket selection on the server.
When authentication is configured, the connection token is decoded and a successfully authenticated socket receives socket.user_id. When authorization is configured, incoming messages are checked before dispatch and outgoing messages are checked once per selected client before a socket write is attempted.
Incoming messages receive trusted user_id, socketId, clientId, organization_id, and host values from the connection. A socket payload field has no transport meaning and is preserved as ordinary application data. Authorization receives the authenticated user separately. replyOrganizationId is also stamped by the server so CRUD can restore the connection's reply scope when authorization redirects an operation to platform storage; it is removed from outgoing socket messages.
Activity writes use log: false, and records in activities do not generate further activity records.
Authorization may reject a message or return an authorized envelope. The authorized envelope becomes the payload delivered to that client.
Components send responses through server.send(envelope). The coordinator starts
local server.socket.send() delivery, IPC delivery to the organization's workers,
and primary-owned server.cluster.send() forwarding without waiting for the
local socket loop first. Receiving workers call their local socket transport.
Socket send does not call server send, so no socket forwarding flag is needed.
workerId and serverId identify the origin to prevent duplicate delivery.
Direct server.socket.send() delivers only to this process's clients. Its Promise
resolves to undefined after local authorization and write attempts; awaiting it
does not wait for a client application response. Use server.send() for normal
component responses and cross-worker or peer delivery.
The server sends WebSocket ping frames every 30 seconds. Connections that do not answer with a pong before the next heartbeat are terminated and removed from the organization, client, socket, and user maps. Reconnection and queued client messages are managed by socket-client rather than buffered by the server.
npm install @cocreate/socketyarn add @cocreate/socketUpdates are recorded in CHANGELOG.md and GitHub releases. Follow issues and pull requests for planned work and feedback.
CoCreate Socket is maintained and funded by CoCreate and supported by the CoCreate Developer Experience Team. Contact develop@CoCreateJS.com with questions. CoCreate names and logos are trademarks of CoCreate, LLC.
Tests are grouped by transport role under test/server/ and test/client/.
npm test # Both roles.
npm run test:server # Server collections and delivery.
npm run test:client # Client indexes and transport round trips.We encourage contributions to all CoCreate libraries. Please see our CONTRIBUTING.md guide for development workflows and contribution guidelines.
If you discover a bug or would like to request a feature, please open an issue on our GitHub Issues tracker.
For complete documentation, examples, and integration guides, visit:
https://cocreatejs.com/docs/socket
This software is dual-licensed under the GNU Affero General Public License version 3 (AGPLv3) and a commercial license.
- Open Source Use: For open-source projects and non-commercial use, this software is available under the AGPLv3. See the LICENSE file for the complete license text.
- Commercial Use: Commercial users must obtain a commercial license. Commercial licenses are available when signing up for an API key through the CoCreate platform.