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

@editora/collaboration

v0.1.4

Published

Real-time collaborative editing for Editora, backed by Yjs CRDT sync and awareness-based presence.

Readme

@editora/collaboration

Version License TypeScript Size

[!IMPORTANT] Live Website: https://editora-ecosystem.netlify.app/ Storybook: https://editora-ecosystem-storybook.netlify.app/

Real-time collaborative editing for Editora, backed by Yjs CRDT sync and awareness-based presence.

What It Does

  • Syncs a contentEditable editor's content across every connected client in real time, using Yjs's conflict-free merging so concurrent edits from different people never overwrite each other.
  • Shows who else is editing: connected-peer avatars and live, labeled remote cursors/selections rendered directly over the editor.
  • Ships collaborative undo/redo (Cmd/Ctrl+Z / Cmd/Ctrl+Shift+Z) - each person only undoes their own edits, never a peer's.
  • Works with any y-websocket-compatible sync server, or a provider you construct yourself (y-webrtc, a custom transport, etc.).

How It Works

@editora/core's live edit path is raw contentEditable HTML - there's no structured document model in the editor to bind a CRDT to the way y-prosemirror binds one to ProseMirror's document tree. This plugin instead mirrors the editor's DOM subtree element-for-element into a Y.XmlFragment: every DOM element becomes a Y.XmlElement with matching tag and attributes, every text node becomes a Y.XmlText. Local DOM mutations are reconciled into the fragment (minimal text diffs where only content changed, full rebuilds of the affected subtree where structure changed); remote updates are reconciled back onto the DOM, preserving the local caret position across the patch.

Remote cursors are broadcast through Yjs's awareness protocol as a child-index path into the shared DOM tree, then resolved back into a Range on each receiving client to position a caret and, for an active selection, a highlighted region.

Installation

npm install @editora/collaboration

Or bundle install:

npm install @editora/plugins

Usage

import { CollaborationPlugin } from "@editora/collaboration";

const plugins = [
  CollaborationPlugin({
    websocketUrl: "wss://your-sync-server.example.com",
    roomName: "document-42",
    userName: "Ava",
    userColor: "#f97316",
  }),
];

Or declaratively through the web component:

<editora-editor></editora-editor>
<script>
  const editor = document.querySelector("editora-editor");
  editor.jsConfig = {
    plugins: ["collaboration"],
    pluginConfig: {
      collaboration: {
        websocketUrl: "wss://your-sync-server.example.com",
        roomName: "document-42",
        userName: "Ava",
      },
    },
  };
</script>

Options

| Option | Type | Default | Description | | -------------- | ---------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------- | | websocketUrl | string | "wss://demos.yjs.dev" | y-websocket server URL. The default is Yjs's public demo server - fine for trying the plugin, not for real documents. | | roomName | string \| (el: HTMLElement) => string | the editor's id, or a shared default | Room shared by every client editing the same document. | | userName | string | a random guest name | Shown on this client's presence avatar and remote cursor label. | | userColor | string | a random palette color | Color used for this client's cursor and avatar. | | doc | Y.Doc | created internally | Supply your own Y.Doc instead of letting the plugin create one. | | provider | WebsocketProvider | created internally | Supply your own provider (e.g. pre-connected, or a different transport) instead of letting the plugin create one. |

Running Your Own Sync Server

y-websocket ships a runnable server:

npx y-websocket

For production, run it behind TLS and point websocketUrl at it. Yjs updates are CRDT operations, not the document itself - the server only relays and (optionally) persists them.

Limitations

  • Content sync mirrors the DOM tree with a full child-list comparison, not a minimal edit-distance diff - most edits (typing, deleting) are cheap, but a structural change (e.g. a new paragraph) rebuilds the affected subtree rather than computing the smallest possible set of operations. This is a simplicity/op-count trade-off, not a correctness issue.
  • Very rare, tag-boundary-adjacent concurrent edits (two people editing right at the edge of where an HTML tag opens or closes, at the same instant) can occasionally merge in a way that isn't byte-identical to what a fully structural CRDT (like ProseMirror + y-prosemirror) would produce, though it won't corrupt the document. A dedicated structured document model in @editora/core would remove this class of edge case entirely; the editor doesn't have one today.
  • Remote cursor positions are computed from a DOM child-index path and re-resolved on receipt; there's a small (self-correcting, sub-selectionchange-event) window where a cursor badge can lag behind very fast concurrent structural edits.

Browser Support

Works anywhere contentEditable, MutationObserver, and WebSocket are supported - all evergreen browsers.

Notes

  • Public package entry exports CollaborationPlugin and its CollaborationPluginOptions/CollaborationUser types.
  • yjs, y-websocket, and y-protocols are real dependencies of this package, not peer dependencies - they ship with it.