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

@kyneta/yjs-schema

v1.1.0

Published

Yjs CRDT substrate for @kyneta/schema — collaborative data types with typed refs

Readme

@kyneta/yjs-schema

Yjs CRDT substrate for @kyneta/schema — collaborative data types with typed refs.

Wraps a Y.Doc with schema-aware typed reads, writes, versioning, and export/import through the standard Substrate<YjsVersion> interface. Adding a Yjs substrate proves the schema algebra's portability beyond Loro and opens the door to the entire Yjs ecosystem (y-websocket, y-indexeddb, y-webrtc, Hocuspocus, Liveblocks, etc.).

Quick Start

import {
  createYjsDoc,
  change,
  subscribe,
  Schema,
  text,
  version,
  exportSnapshot,
  exportSince,
  importDelta,
} from "@kyneta/yjs-schema"

// Define a schema
const TodoDoc = Schema.doc({
  title: text(),
  items: Schema.list(
    Schema.struct({
      name: Schema.string(),
      done: Schema.boolean(),
    }),
  ),
})

// Create a document with optional seed values
const doc = createYjsDoc(TodoDoc, {
  title: "My Todos",
  items: [{ name: "Buy milk", done: false }],
})

// Read
doc.title()           // "My Todos"
doc.items.length      // 1

// Write
change(doc, (d) => {
  d.title.insert(9, " (v2)")
  d.items.push({ name: "Walk dog", done: false })
})

// Observe
subscribe(doc, (changeset) => {
  console.log("Changed:", changeset.ops.length, "ops")
})

Schema Types Supported

| Schema type | Yjs backing type | Notes | |---|---|---| | text() | Y.Text | Character-level collaborative editing | | Schema.struct({...}) | Y.Map | Fixed-key product type | | Schema.list(item) | Y.Array | Ordered sequence | | Schema.record(item) | Y.Map | Dynamic-key map | | Schema.string() | Plain value | Stored in parent Y.Map | | Schema.number() | Plain value | Stored in parent Y.Map | | Schema.boolean() | Plain value | Stored in parent Y.Map |

Unsupported

  • Schema.annotated("counter") — Yjs has no native counter type. Use Schema.number() with ReplaceChange instead. Attempting to use a counter annotation will throw at construction time.
  • Schema.annotated("movable") — Yjs has no native movable list. Will throw at construction time.
  • Schema.annotated("tree") — Yjs has no native tree type. Will throw at construction time.

Sync

import {
  createYjsDoc,
  createYjsDocFromSnapshot,
  version,
  exportSnapshot,
  exportSince,
  importDelta,
  change,
} from "@kyneta/yjs-schema"

// Peer A creates a doc
const docA = createYjsDoc(MySchema, { title: "Draft" })

// Peer B bootstraps from a full snapshot
const snapshot = exportSnapshot(docA)
const docB = createYjsDocFromSnapshot(MySchema, snapshot)

// After mutations on A, sync incrementally
const vBefore = version(docB)
change(docA, (d) => d.title.insert(5, " v2"))

const delta = exportSince(docA, vBefore)
importDelta(docB, delta!)
// docB.title() === "Draft v2"

Exchange Integration

import { bindYjs } from "@kyneta/yjs-schema"
import { Schema, text } from "@kyneta/yjs-schema"

const TodoDoc = bindYjs(Schema.doc({
  title: text(),
  items: Schema.list(Schema.struct({
    name: Schema.string(),
    done: Schema.boolean(),
  })),
}))

// Use with @kyneta/exchange
const doc = exchange.get("my-todos", TodoDoc)

bindYjs produces a BoundSchema with strategy: "causal", which the exchange uses for bidirectional CRDT sync.

Escape Hatch

Access the underlying Y.Doc for direct Yjs API usage:

import { yjs } from "@kyneta/yjs-schema"

const doc = createYjsDoc(MySchema)
const yjsDoc = yjs(doc)

// Use with Yjs ecosystem
// y-websocket, y-indexeddb, y-webrtc, Hocuspocus, etc.
yjsDoc.getMap("root").toJSON()  // raw state
yjsDoc.clientID                  // client ID

Yjs Ecosystem Compatibility

Because yjs(doc) returns a standard Y.Doc, the entire Yjs provider ecosystem works out of the box:

  • y-websocket — WebSocket sync
  • y-indexeddb — Local persistence
  • y-webrtc — Peer-to-peer sync
  • Hocuspocus — Scalable Yjs server
  • Liveblocks — Managed collaboration infrastructure
  • y-prosemirror / y-codemirror — Rich text editor bindings

API Reference

Batteries-included (most users)

| Export | Description | |---|---| | createYjsDoc(schema, docOrSeed?) | Create a live Yjs-backed document | | createYjsDocFromSnapshot(schema, payload) | Reconstruct from snapshot | | version(doc) | Current YjsVersion | | exportSnapshot(doc) | Full state as SubstratePayload | | exportSince(doc, since) | Delta since version | | importDelta(doc, payload, origin?) | Apply delta from peer | | change(doc, fn) | Transactional mutation | | subscribe(doc, callback) | Observe changes | | bindYjs(schema) | Bind schema for exchange use | | yjs(ref) | Escape hatch → Y.Doc | | text() | Schema.annotated("text") convenience |

Low-level primitives (power users)

| Export | Description | |---|---| | YjsVersion | Version class wrapping Yjs state vectors | | yjsStoreReader(doc, schema) | Live StoreReader over Yjs types | | resolveYjsType(rootMap, schema, path) | Path resolution | | applyChangeToYjs(rootMap, schema, path, change) | kyneta → Yjs | | eventsToOps(events) | Yjs → kyneta | | populateRoot(doc, schema, seed) | Root container population | | createYjsSubstrate(doc, schema) | Low-level substrate construction | | yjsSubstrateFactory | SubstrateFactory<YjsVersion> |

License

MIT