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

rte-rich-text-editor-ws

v1.0.11

Published

Drop-in WebSocket connector that adds real-time collaboration and auto-save to the RTE rich-text editor. Zero dependencies.

Readme

RTE-WS — WebSocket Connector for RTE Rich Text Editor

npm version downloads zero dependencies license MIT

Docs & demo

Add real-time auto-save and multi-user collaboration to RTE with a single script tag. Zero dependencies.

RTE Rich Text Editor

Install

npm

npm install rte-rich-text-editor-ws

CommonJS

const RTE = require('rte-rich-text-editor');
const RTEWS = require('rte-rich-text-editor-ws');

ES Modules

import RTE from 'rte-rich-text-editor';
import RTEWS from 'rte-rich-text-editor-ws';

Script Tag

<script src="https://rte.whitneys.co/rte.js"></script>
<script src="https://rte.whitneys.co/rte-ws.js"></script>

Quick Start

<div id="editor"></div>

<script src="https://rte.whitneys.co/rte.js"></script>
<script src="https://rte.whitneys.co/rte-ws.js"></script>
<script>
  const editor = RTE.init('#editor');

  const ws = RTEWS.connect(editor, 'wss://yourserver.com/ws', {
    docId: 'doc-123',
    userId: 'user-abc',
    onOpen: () => console.log('Connected'),
    onSaved: (msg) => console.log('Saved, version:', msg.version),
    onRemoteUpdate: (msg) => console.log('Update from:', msg.userId),
  });
</script>

CommonJS

const RTE = require('rte-rich-text-editor');
const RTEWS = require('rte-rich-text-editor-ws');

const editor = RTE.init('#editor');
const ws = RTEWS.connect(editor, 'wss://yourserver.com/ws', { docId: 'doc-1', userId: 'user-1' });

Features

| Feature | Description | |---|---| | Auto-Save | Debounced content sync to backend on every change | | Collaboration | Broadcast and receive changes between multiple users | | Auto-Reconnect | Exponential backoff (1s → 2s → 4s → ... up to 30s) | | Heartbeat | Configurable keep-alive ping (default 30s) | | Cursor Preservation | Local cursor position saved/restored on remote updates |

Configuration

const ws = RTEWS.connect(editor, 'wss://yourserver.com/ws', {
  docId: 'doc-123',         // Document identifier
  userId: 'user-abc',       // User identifier
  debounceMs: 1000,         // Debounce delay before sending changes
  autoSave: true,           // Auto-send changes on editor input
  reconnect: true,          // Auto-reconnect on disconnect
  reconnectBaseMs: 1000,    // Initial reconnect delay
  reconnectMaxMs: 30000,    // Max reconnect delay
  heartbeatMs: 30000,       // Ping interval (0 to disable)
  onOpen: (ws) => {},       // WebSocket connected
  onClose: (e) => {},       // WebSocket closed
  onError: (e) => {},       // Error occurred
  onSaved: (msg) => {},     // Server confirmed save
  onRemoteUpdate: (msg) => {}, // Remote user change applied
  onMessage: (msg) => {},   // Any incoming message
});

API

| Method / Property | Description | |---|---| | ws.save() | Send explicit save request | | ws.send(data) | Send custom JSON message | | ws.disconnect() | Close connection, stop reconnecting | | ws.reconnect() | Manually reconnect | | ws.state | "connecting", "open", "closing", or "closed" | | ws.socket | Raw WebSocket instance |

Message Protocol

Outgoing (Client → Server)

| Type | Fields | Description | |---|---|---| | "join" | docId, userId | Sent on connect | | "change" | docId, userId, html, text, words, chars | Editor content changed | | "save" | docId, userId, html, text, words, chars | Explicit save | | "ping" | — | Heartbeat |

Incoming (Server → Client)

| Type | Fields | Description | |---|---|---| | "load" | html | Load initial content | | "update" | html, userId | Remote user change | | "saved" | version (optional) | Save confirmed | | "error" | message | Server error |

Backend Example (Node.js)

import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080 });
const docs = new Map();

wss.on('connection', (socket) => {
  let docId = null, userId = null;

  socket.on('message', (raw) => {
    const msg = JSON.parse(raw);

    if (msg.type === 'join') {
      docId = msg.docId; userId = msg.userId;
      if (!docs.has(docId)) docs.set(docId, { html: '', clients: new Set() });
      docs.get(docId).clients.add(socket);
      socket.send(JSON.stringify({ type: 'load', html: docs.get(docId).html }));
    }

    if (msg.type === 'change' && docId) {
      docs.get(docId).html = msg.html;
      docs.get(docId).clients.forEach(c => {
        if (c !== socket && c.readyState === 1)
          c.send(JSON.stringify({ type: 'update', html: msg.html, userId }));
      });
    }

    if (msg.type === 'save')
      socket.send(JSON.stringify({ type: 'saved', version: Date.now() }));
  });

  socket.on('close', () => {
    if (docId && docs.has(docId)) docs.get(docId).clients.delete(socket);
  });
});

Related Packages

| Package | Description | |---|---| | rte-rich-text-editor | Core editor — lightweight, 33 toolbar controls | | rte-rich-text-editor-ws | WebSocket connector for RTE | | rte-rich-text-editor-bundle | RTE + WebSocket in one file | | rte-rich-text-editor-pro | Pro editor — 16 toolbar groups, AI, slash commands, mentions | | rte-rich-text-editor-pro-ws | RTEPro + WebSocket in one file | | wskit-client | Universal WebSocket client | | websocket-toolkit | Universal WebSocket client (alternate name) |

Website: rte.whitneys.co · GitHub: MIR-2025/rte

License

MIT

Changelog

All notable changes to rte-rich-text-editor-ws will be documented in this file.

[1.0.9] - 2026-02-18

  • Version bump (no code changes — WebSocket wrapper only)

[1.0.8] - 2026-02-18

  • Version bump (no code changes — WebSocket wrapper only)

[1.0.7] - 2026-02-18

  • Version bump (no code changes — WebSocket wrapper only)

[1.0.5] - 2026-02-18

  • Version bump (no code changes — WebSocket wrapper only)

[1.0.2] - 2026-02-16

  • Added CommonJS and ES Modules usage examples to README

[1.0.1] - 2026-02-16

  • Added related package links to README

[1.0.0] - 2026-02-16

  • Initial release — standalone WebSocket connector for RTE
  • Auto-save with configurable debounce
  • Real-time collaboration with cursor preservation
  • Auto-reconnect with exponential backoff
  • Heartbeat keep-alive
  • UMD wrapper (script tag, CommonJS, AMD)