npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@polytric/openws-spec

v0.0.4

Published

Polytric OpenWS Specification

Readme

OpenWS Specification

npm license

OpenWS is a specification for describing WebSocket-based systems in the same way OpenAPI describes HTTP APIs. It models WebSocket communication as an asymmetrical 2-way request-response mesh: multiple components exchange named messages, and "responses" are simply messages sent back through the same network.

An OpenWS document describes:

  • Networks: logical WebSocket systems where messages are exchanged
  • Roles: role-based API surfaces with statically defined message contracts
  • Messages: named message definitions that contain a payload
  • Payload: the shape of application data transmitted through WebSocket messages, defined with JSON Schema
  • Metadata & connection hints: document metadata (title, version, description) and optional connection hints (endpoints)

Conceptually (at runtime), we also use the following terms throughout this document:

  • Participants: runtime instances/connections that assume a role on a network
  • Handlers: runtime message-processing functions invoked when a participant receives a message

Participants and handlers are not serialized in the OpenWS JSON document. They are explanatory terms used to describe how role/message contracts are typically implemented.

This spec intentionally does not describe behavior or execution.

Conventions

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119.

Unless otherwise noted:

  • OpenWS documents are JSON objects.
  • Examples are written as valid JSON (no comments, no trailing commas).
  • payload schemas use JSON Schema. A specific JSON Schema dialect may be chosen by downstream tooling; OpenWS itself describes shapes rather than enforcing a single validator implementation.

Note: The OpenWS document describes contracts. Runtime details such as routing, correlation, authentication, and connection lifecycle are intentionally left to runtime layers.

Document Structure

An OpenWS document is a JSON object with the following top-level fields:

  • openws (REQUIRED): the OpenWS specification version as a string.
  • title (OPTIONAL): a human-readable name for the document.
  • version (OPTIONAL): the version of the described system/API (not the OpenWS spec version).
  • description (OPTIONAL): a longer explanation of the document.
  • networks (REQUIRED): a map of network names to network definitions.

An implementation:

  • MUST ignore unknown fields (to allow forward compatibility and extensions).
  • SHOULD preserve unknown fields when round-tripping documents (when feasible).
  • MAY support custom extension fields anywhere in the document (see Metadata & Connection Hints).

Minimal skeleton:

{
    "openws": "0.0.2",
    "title": "My WebSocket System",
    "version": "1.0.0",
    "description": "Optional, human-readable description.",
    "networks": {
        "example": {
            "roles": {
                "server": {
                    "messages": {}
                }
            }
        }
    }
}

Ecosystem

OpenWS is designed as a tooling ecosystem, similar in spirit to OpenAPI: a spec, plus runtimes, adapters, generators, and framework integrations.

This repository/spec is intended to support a full "fleet" of packages, including (but not limited to):

The spec intentionally stays framework-agnostic; framework integrations and SDKs belong to the ecosystem layer.

Core Concepts

Networks

A network is a logical WebSocket system, with multiple participants on the network forming a mesh. It is common to run multiple isolated features over WebSocket on a single host. For example, a chess game client may have a chat room, a tournament entry, and the actual chess game. They are logically separated like this in the spec:

{
    "networks": {
        "chat": {},
        "tournament": {},
        "chess": {}
    }
}

[!NOTE] Examples in the core concepts sections have omitted details for brevity; they are not valid standalone. Consult the complete example towards the bottom of the doc for a fully working example.

On the backend side, there may be a dedicated service for each of these components, so each service would typically define just one network:

Chat service:

{
    "networks": {
        "chat": {}
    }
}

Tournament service:

{
    "networks": {
        "tournament": {}
    }
}

Chess service:

{
    "networks": {
        "chess": {}
    }
}

A network definition:

  • MUST define roles.
  • MAY include metadata such as description.
  • MAY include custom extension fields.

Roles

In the OpenWS document, we define roles. At runtime, a participant is a connected instance that assumes a role on a network.

Multiple participants of the same role may exist on the same network. For example, in a chat service, a server is normally connected to many clients. OpenWS defers modeling one-to-one, one-to-many, or many-to-many relationships to the application/runtime.

{
    "networks": {
        "chat": {
            "roles": {
                "server": {},
                "client": {}
            }
        }
    }
}

It is common for different components of a system to expose different APIs and provide different behaviors. This is naturally modeled by participants on the same network having different roles. Continuing the chat example, imagine we now have a mobile client, a customer web portal, and an admin console. To serve both customer and admin needs, the server is split into two separate roles, while a single backend may implement both roles. Distinct roles can be set up like this:

{
    "roles": {
        "adminServer": {},
        "customerServer": {},
        "mobile": {},
        "portal": {},
        "console": {}
    }
}

IMPORTANT: this is not a role-based access control system, but the clean API boundary is intended to make layering an auth system trivial.

A role definition:

  • MUST define messages (it MAY be empty).
  • MAY include metadata such as description or connection hints such as endpoints.
  • MAY include custom extension fields.

Messages

In the OpenWS document, roles declare the data shapes they accept as messages. Messages are indexed by name.

Message definitions are scoped to the receiving role. At runtime:

  • A participant receives a message by name, and dispatches it to a handler.
  • A participant sends a message by targeting some other participant(s) whose role defines that message name and payload shape.

OpenWS intentionally describes contracts, not delivery semantics. Routing (broadcast, directed, room-based, etc.) is runtime-specific.

For example, a chat server may accept message, join, createRoom, while the customer portal may accept channelStats. The meaning of messages differs depending on perspective: the chat server accepts join as an incoming message and handles it to update its state, while the portal can send join to the server. Similarly, the portal accepts channelStats as an incoming message, while the server can send channelStats to the portal.

{
    "roles": {
        "server": {
            "messages": {
                "message": {},
                "join": {},
                "createRoom": {}
            }
        },
        "portal": {
            "messages": {
                "channelStats": {}
            }
        }
    }
}

A message definition:

  • MUST define payload.
  • MAY include metadata such as description.
  • MUST be uniquely named within its role (message names under the same role MUST NOT collide).
  • MAY include custom extension fields.

Request/response modeling

OpenWS supports request/response patterns, but does not mandate a single correlation mechanism. If your system uses request/response semantics, runtimes SHOULD define a correlation convention (for example, an ID field inside the payload or an envelope-level correlation ID).

Payload

Each message declares its payload shape using JSON Schema:

{
    "message": {
        "payload": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
        }
    }
}

Payload schemas:

  • MUST be valid JSON Schema objects (as interpreted by the runtime/tooling).
  • SHOULD be compatible with your chosen JSON Schema dialect across toolchains.
  • MAY use common JSON Schema keywords such as type, properties, required, enum, and format.

A role's handlers are the runtime functions that process incoming messages whose payloads match the message definitions in the spec.

Metadata & Connection Hints

OpenWS includes a small set of well-known metadata fields for product-grade tooling, while still allowing custom metadata anywhere in the document.

Document metadata

OpenWS supports a small set of well-known metadata fields at the root of the document:

  • title (SHOULD): a human-readable name for the document.
  • version (SHOULD): the version of the described system/API (not the OpenWS spec version).
  • description (MAY): a longer explanation of the document.

Tooling MAY use these fields for documentation, generation, and display.

Connection hints

Endpoints are optional connection hints that help participants determine how to establish connections. They do not prescribe deployment topology, discovery, authentication, or load-balancing.

An endpoint is typically attached to a role definition:

{
    "networks": {
        "chat": {
            "roles": {
                "server": {
                    "endpoints": [
                        { "scheme": "wss", "host": "localhost", "port": 8082, "path": "/abc" }
                    ]
                }
            }
        }
    }
}

Endpoint objects:

  • MAY include scheme (ws or wss), host, port, and path.
  • SHOULD be treated as hints. Implementations MAY connect using other configuration (service discovery, environment variables, user choice, etc.).
  • Dynamic endpoint resolution is outside the scope of this spec.

Custom metadata and extensions

Custom metadata fields MAY be added anywhere in the JSON structure. Implementations:

  • MUST ignore fields they do not understand.
  • SHOULD encourage a consistent prefix such as x-... for extension fields to reduce the chance of collisions with future spec fields.

Complete Example

The following example is a minimal but complete OpenWS document modeling a chat system. It uses:

  • a single chat network
  • three roles (server, client, portal)
  • message contracts scoped to the receiving role
  • connection hints via endpoints
  • one extension field (x-routingNotes) to document intended flows
{
    "openws": "0.0.2",
    "title": "Example Chat Service",
    "version": "1.0.0",
    "description": "A minimal OpenWS document modeling a chat network.",
    "networks": {
        "chat": {
            "description": "Realtime chat network.",
            "roles": {
                "server": {
                    "description": "Backend that hosts rooms and broadcasts messages.",
                    "endpoints": [
                        {
                            "scheme": "wss",
                            "host": "chat.example.com",
                            "port": 443,
                            "path": "/ws/chat"
                        }
                    ],
                    "messages": {
                        "join": {
                            "description": "Request to join a room.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["userId", "roomId"],
                                "properties": {
                                    "userId": { "type": "string", "minLength": 1 },
                                    "roomId": { "type": "string", "minLength": 1 }
                                }
                            }
                        },
                        "message": {
                            "description": "Send a chat message to a room.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["userId", "roomId", "text"],
                                "properties": {
                                    "userId": { "type": "string", "minLength": 1 },
                                    "roomId": { "type": "string", "minLength": 1 },
                                    "text": { "type": "string", "minLength": 1, "maxLength": 2048 }
                                }
                            }
                        },
                        "createRoom": {
                            "description": "Create a new room.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["userId", "name"],
                                "properties": {
                                    "userId": { "type": "string", "minLength": 1 },
                                    "name": { "type": "string", "minLength": 1, "maxLength": 128 }
                                }
                            }
                        },
                        "requestStats": {
                            "description": "Request channel statistics.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["roomId"],
                                "properties": {
                                    "roomId": { "type": "string", "minLength": 1 }
                                }
                            }
                        }
                    }
                },
                "client": {
                    "description": "End-user client that receives events from the server.",
                    "messages": {
                        "roomJoined": {
                            "description": "Emitted after a join succeeds.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["roomId"],
                                "properties": {
                                    "roomId": { "type": "string", "minLength": 1 }
                                }
                            }
                        },
                        "messageReceived": {
                            "description": "Broadcast of a message to participants in a room.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["roomId", "text", "senderId", "sentAt"],
                                "properties": {
                                    "roomId": { "type": "string", "minLength": 1 },
                                    "text": { "type": "string", "minLength": 1, "maxLength": 2048 },
                                    "senderId": { "type": "string", "minLength": 1 },
                                    "sentAt": { "type": "integer" }
                                }
                            }
                        }
                    }
                },
                "portal": {
                    "description": "Internal web portal that receives aggregated stats.",
                    "messages": {
                        "channelStats": {
                            "description": "Room-level metrics snapshot.",
                            "payload": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": ["roomId", "members", "messagesLastMinute"],
                                "properties": {
                                    "roomId": { "type": "string", "minLength": 1 },
                                    "members": { "type": "integer", "minimum": 0 },
                                    "messagesLastMinute": { "type": "integer", "minimum": 0 }
                                }
                            }
                        }
                    }
                }
            },
            "x-routingNotes": "Clients send server.join/server.message. Server emits client.roomJoined/client.messageReceived and portal.channelStats."
        }
    }
}