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

@jodit/collab-protocol

v0.1.7

Published

Wire protocol for Jodit collaborative editing: id-addressed patches, OT transform, sequencer/client-sync reference implementation, auth/identity contract. Pure TypeScript — no DOM, no Jodit.

Readme

@jodit/collab-protocol

The wire protocol for Jodit collaborative editing — shared by the editor plugin (@jodit/collab) and any backend implementation. Pure TypeScript: no DOM, no Jodit, no IO. This package IS the spec: implement your own server against these types, schemas and transform functions, or reuse the reference DocumentSession / ClientSync directly.

What's inside

| Module | Purpose | | ------------- | -------------------------------------------------------------------------- | | patch.ts | Wire format: id-addressed insert / remove / text(splice) / attr patches | | doc.ts | Pure JSON document model: applyPatch, invertPatch, tolerance rules | | text-op.ts | Character-level OT for one text node (retain/delete/insert) | | xform.ts | xform/xformBatch: transform concurrent batches; convergence guaranteed | | session.ts | Reference sequencer (DocumentSession) + client rebase (ClientSync) | | identity.ts | Auth contract: resolveIdentity, roles, guest generator | | messages.ts | Zod schemas for every WS message (client schemas are strict) |

Concurrency model in one paragraph

Patches address nodes by stable ids, so structural edits commute; the only index in the format is the character offset inside a single text node, which is transformed with classic text OT. The server is the authoritative sequencer: a submit {opId, baseSeq, patches} is rebased against everything the author had not seen, gets the next seq, and is broadcast to everyone — including the author, who treats it as the ack. Clients rebase incoming batches over their pending (unacknowledged) edits with the same xform functions the server uses. Convergence — apply(apply(d,B),A') === apply(apply(d,A),B') — is enforced by property-based tests (fast-check) and a randomized client/server fuzz harness.

Identity: always server-assigned

The client's hello carries a token and nothing else — the schemas are strict, so a frontend sending name/color is a validation error, not a suggestion. Who you are comes back in welcome.self; who your peers are comes in welcome.peers / peer.join / server-enriched presence.

import { resolveIdentity, type AuthOptions } from '@jodit/collab-protocol';

// Production: plug in your own token check (JWT, session store, API key…)
const auth: AuthOptions = {
  checkAuthentication: async (token, ctx) => {
    const user = await verifyJwt(token);
    return user
      ? { userId: user.id, name: user.displayName, color: user.color, role: user.role }
      : null; // invalid token → connection rejected ('auth_failed')
  },
  authorize: (identity, docId, action) => acl.check(identity.userId, docId, action),
};

// Demo mode: no tokens, every connection gets a generated identity
// ("Guest Amber Fox", stable per seed) — names never come from the frontend.
const demoAuth: AuthOptions = { allowAnonymous: true, guestRole: 'writer' };

Flow (resolveIdentity implements it, use it on the WS upgrade):

token present → checkAuthentication → identity | 'auth_failed'
token absent  → allowAnonymous ? guest identity : 'auth_required'

Note: an invalid token is rejected even in anonymous mode — silent downgrade to guest would mask broken tokens.

Reference sync loop

import { DocumentSession, ClientSync } from '@jodit/collab-protocol';

// server
const session = new DocumentSession(initialDoc);
const entry = session.submit(clientId, msg.opId, msg.baseSeq, msg.patches);
broadcastToRoom(entry); // to everyone, author included (= ack)

// client
const sync = new ClientSync(clientId, initialDoc);
const submit = sync.local(patchesFromEditor); // → send if not null
const { apply, submit: next } = sync.receive(broadcast);
editor.collab.applyRemote(apply); // rebased against local pending edits
if (next) send(next);

Scripts

npm test        # unit, property-based convergence, session fuzz, OT window
npm run build   # dist ESM+CJS+d.ts (tsup)

License

Commercial — see LICENSE.md. Free to evaluate; a paid license is required for production use. Read more at https://xdsoft.net/jodit/pro/.