CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-yjs

Conflict-free Replicated Data Type (CRDT) framework for real-time collaborative applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Yjs

Yjs is a Conflict-free Replicated Data Type (CRDT) framework that enables real-time collaborative editing without conflicts. It provides shared data types that multiple users can edit simultaneously, with automatic synchronization and conflict resolution. Yjs is network-agnostic and supports peer-to-peer synchronization, offline editing, undo/redo functionality, and efficient binary serialization.

Package Information

  • Package Name: yjs
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install yjs

Core Imports

import * as Y from "yjs";

For individual imports:

import { Doc, Array as YArray, Map as YMap, Text as YText } from "yjs";

CommonJS:

const Y = require("yjs");
const { Doc, Array: YArray, Map: YMap, Text: YText } = require("yjs");

Basic Usage

import * as Y from "yjs";

// Create a new document
const doc = new Y.Doc();

// Get shared types
const yarray = doc.getArray("my-array");
const ymap = doc.getMap("my-map");
const ytext = doc.getText("my-text");

// Use shared types
yarray.push(["hello", "world"]);
ymap.set("key", "value");
ytext.insert(0, "Hello collaborative world!");

// Observe changes
yarray.observe((event) => {
  console.log("Array changed:", event.changes);
});

// Create updates for synchronization
const update = Y.encodeStateAsUpdate(doc);

// Apply updates from other clients
const otherDoc = new Y.Doc();
Y.applyUpdate(otherDoc, update);

Architecture

Yjs is built around several key components:

  • Document (Doc): Central container managing shared types and synchronization state
  • Shared Data Types: Observable CRDT types (YArray, YMap, YText, YXmlElement) for collaborative editing
  • Transaction System: Atomic change batching for consistent updates and event handling
  • Position System: Relative positions that survive concurrent edits and structural changes
  • Update System: Binary serialization and merging for efficient network synchronization
  • Snapshot System: Time-travel functionality for document state at specific points
  • Undo/Redo System: Multi-level undo/redo with scope management and origin tracking

Capabilities

Document Management

Core document functionality for creating, managing, and synchronizing collaborative documents.

class Doc {
  constructor(options?: DocOpts);
  readonly clientID: number;
  readonly guid: string;
  readonly isLoaded: boolean;
  readonly isSynced: boolean;
  readonly isDestroyed: boolean;
  readonly whenLoaded: Promise<Doc>;
  readonly whenSynced: Promise<void>;
  readonly subdocs: Set<Doc>;
  get<Type>(name: string, TypeConstructor?: Type): InstanceType<Type>;
  getArray<T>(name?: string): YArray<T>;
  getText(name?: string): YText;
  getMap<T>(name?: string): YMap<T>;
  getXmlElement(name?: string): YXmlElement;
  getXmlFragment(name?: string): YXmlFragment;
  transact<T>(f: (transaction: Transaction) => T, origin?: any): T;
  load(): void;
  getSubdocs(): Set<Doc>;
  getSubdocGuids(): Set<string>;
  destroy(): void;
  toJSON(): any;
}

interface DocOpts {
  clientID?: number;
  guid?: string;
  collectionid?: string | null;
  gc?: boolean;
  gcFilter?: (item: Item) => boolean;
  meta?: any;
  autoLoad?: boolean;
  shouldLoad?: boolean;
}

Document Management

Shared Data Types

Observable CRDT types for different collaborative editing scenarios with automatic conflict resolution.

class YArray<T> {
  constructor();
  static from<T>(items: Array<T>): YArray<T>;
  readonly length: number;
  insert(index: number, content: Array<T>): void;
  push(content: Array<T>): void;
  unshift(content: Array<T>): void;
  delete(index: number, length?: number): void;
  get(index: number): T;
  toArray(): Array<T>;
}

class YMap<T> {
  constructor(entries?: Iterable<readonly [string, any]>);
  readonly size: number;
  set<VAL>(key: string, value: VAL): VAL;
  get(key: string): T | undefined;
  has(key: string): boolean;
  delete(key: string): void;
  clear(): void;
}

class YText {
  constructor(string?: string);
  readonly length: number;
  insert(index: number, text: string, attributes?: TextAttributes): void;
  insertEmbed(index: number, embed: Object | AbstractType<any>, attributes?: TextAttributes): void;
  delete(index: number, length: number): void;
  format(index: number, length: number, attributes: TextAttributes): void;
  removeAttribute(attributeName: string): void;
  setAttribute(attributeName: string, attributeValue: any): void;
  getAttribute(attributeName: string): any;
  getAttributes(): {[key: string]: any};
  toString(): string;
}

Shared Data Types

XML Types

XML-aware collaborative types for structured document editing with DOM integration.

class YXmlElement<KV = { [key: string]: any }> {
  constructor(nodeName?: string);
  readonly nodeName: string;
  setAttribute<KEY>(attributeName: KEY, attributeValue: KV[KEY]): void;
  getAttribute<KEY>(attributeName: KEY): KV[KEY] | undefined;
  hasAttribute(attributeName: string): boolean;
  toDOM(document?: Document): Element;
}

class YXmlFragment {
  constructor();
  readonly length: number;
  insert(index: number, content: Array<YXmlElement | YXmlText>): void;
  insertAfter(ref: null | Item | YXmlElement | YXmlText, content: Array<YXmlElement | YXmlText>): void;
  querySelector(query: string): YXmlElement | YXmlText | YXmlHook | null;
  querySelectorAll(query: string): Array<YXmlElement | YXmlText | YXmlHook>;
  createTreeWalker(filter?: (node: AbstractType<any>) => boolean): YXmlTreeWalker;
}

XML Types

Transaction System

Atomic change batching for consistent updates and coordinated event handling.

class Transaction {
  readonly doc: Doc;
  readonly origin: any;
  readonly local: boolean;
  readonly beforeState: Map<number, number>;
  readonly afterState: Map<number, number>;
}

function transact<T>(doc: Doc, f: (transaction: Transaction) => T, origin?: any): T;

Transaction System

Event System

Comprehensive event handling for observing changes to shared types with detailed change information.

abstract class YEvent<T> {
  readonly target: T;
  readonly transaction: Transaction;
  readonly path: Array<string | number>;
  readonly changes: {
    added: Set<Item>;
    deleted: Set<Item>;
    keys: Map<string, any>;
    delta: Array<any>;
  };
}

interface AbstractType<EventType> {
  observe(f: (event: EventType, transaction: Transaction) => void): void;
  unobserve(f: (event: EventType, transaction: Transaction) => void): void;
  observeDeep(f: (events: Array<YEvent<any>>, transaction: Transaction) => void): void;
}

Event System

Position Tracking

Position system that maintains references across concurrent edits and structural changes.

class RelativePosition {
  readonly type: ID | null;
  readonly tname: string | null;
  readonly item: ID | null;
  readonly assoc: number;
}

class AbsolutePosition {
  readonly type: AbstractType<any>;
  readonly index: number;
  readonly assoc: number;
}

function createRelativePositionFromTypeIndex(
  type: AbstractType<any>,
  index: number,
  assoc?: number
): RelativePosition;

function createAbsolutePositionFromRelativePosition(
  rpos: RelativePosition,
  doc: Doc
): AbsolutePosition | null;

function createRelativePositionFromJSON(json: any): RelativePosition;
function encodeRelativePosition(rpos: RelativePosition): Uint8Array;
function decodeRelativePosition(encoded: Uint8Array): RelativePosition;
function relativePositionToJSON(rpos: RelativePosition): any;
function compareRelativePositions(a: RelativePosition, b: RelativePosition): number;

Position Tracking

Synchronization

Binary update system for efficient network synchronization and state management.

function encodeStateAsUpdate(doc: Doc, encodedTargetStateVector?: Uint8Array): Uint8Array;
function encodeStateAsUpdateV2(doc: Doc, encodedTargetStateVector?: Uint8Array): Uint8Array;
function applyUpdate(doc: Doc, update: Uint8Array, transactionOrigin?: any): void;
function applyUpdateV2(doc: Doc, update: Uint8Array, transactionOrigin?: any): void;
function mergeUpdates(updates: Array<Uint8Array>): Uint8Array;
function mergeUpdatesV2(updates: Array<Uint8Array>): Uint8Array;
function readUpdate(decoder: UpdateDecoder, doc: Doc, transactionOrigin?: any): void;
function readUpdateV2(decoder: UpdateDecoder, doc: Doc, transactionOrigin?: any): void;
function encodeStateVector(doc: Doc): Uint8Array;
function decodeStateVector(stateVector: Uint8Array): Map<number, number>;
function parseUpdateMeta(update: Uint8Array): { from: Map<number, number>; to: Map<number, number> };
function parseUpdateMetaV2(update: Uint8Array): { from: Map<number, number>; to: Map<number, number> };
function encodeStateVectorFromUpdate(update: Uint8Array): Uint8Array;
function encodeStateVectorFromUpdateV2(update: Uint8Array): Uint8Array;
function diffUpdate(update: Uint8Array, stateVector: Uint8Array): Uint8Array;
function diffUpdateV2(update: Uint8Array, stateVector: Uint8Array): Uint8Array;
function convertUpdateFormatV1ToV2(update: Uint8Array): Uint8Array;
function convertUpdateFormatV2ToV1(update: Uint8Array): Uint8Array;
function logUpdate(update: Uint8Array): void;
function logUpdateV2(update: Uint8Array): void;

Synchronization

Snapshot System

Time-travel functionality for document state at specific points with diff capabilities.

class Snapshot {
  readonly ds: DeleteSet;
  readonly sv: Map<number, number>;
}

function snapshot(doc: Doc): Snapshot;
function createSnapshot(doc: Doc): Snapshot;
function createDocFromSnapshot(originDoc: Doc, snapshot: Snapshot, newDoc?: Doc): Doc;
function equalSnapshots(snap1: Snapshot, snap2: Snapshot): boolean;
function encodeSnapshot(snapshot: Snapshot): Uint8Array;
function decodeSnapshot(encoded: Uint8Array): Snapshot;
function encodeSnapshotV2(snapshot: Snapshot): Uint8Array;
function decodeSnapshotV2(encoded: Uint8Array): Snapshot;
function snapshotContainsUpdate(snapshot: Snapshot, update: Uint8Array): boolean;

Snapshot System

Undo/Redo System

Multi-level undo/redo functionality with scope management and origin tracking.

class UndoManager {
  constructor(
    typeScope: Doc | AbstractType<any> | Array<AbstractType<any>>,
    options?: UndoManagerOptions
  );
  readonly undoStack: Array<StackItem>;
  readonly redoStack: Array<StackItem>;
  undo(): StackItem | null;
  redo(): StackItem | null;
  canUndo(): boolean;
  canRedo(): boolean;
  clear(clearUndoStack?: boolean, clearRedoStack?: boolean): void;
}

interface UndoManagerOptions {
  captureTimeout?: number;
  captureTransaction?: (transaction: Transaction) => boolean;
  deleteFilter?: (item: Item) => boolean;
  trackedOrigins?: Set<any>;
}

Undo/Redo System

Utility Functions

Essential utility functions for working with Yjs internals and advanced operations.

// Item and structure utilities
function getItem(store: StructStore, id: ID): Item;
function getItemCleanStart(transaction: Transaction, id: ID): Item;
function getItemCleanEnd(transaction: Transaction, id: ID): Item;
function isDeleted(deleteSet: DeleteSet, id: ID): boolean;
function isParentOf(parent: AbstractType<any>, child: Item): boolean;

// ID utilities
function createID(client: number, clock: number): ID;
function compareIDs(a: ID | null, b: ID | null): boolean;
function getState(store: StructStore, client: number): number;

// Delete set utilities
function createDeleteSet(): DeleteSet;
function createDeleteSetFromStructStore(store: StructStore): DeleteSet;
function equalDeleteSets(ds1: DeleteSet, ds2: DeleteSet): boolean;
function mergeDeleteSets(deleteSets: Array<DeleteSet>): DeleteSet;

// Advanced operations
function transact<T>(doc: Doc, f: (transaction: Transaction) => T, origin?: any): T;
function tryGc(deleteSet: DeleteSet, store: StructStore, gcFilter: Function): void;
function cleanupYTextFormatting(type: YText): number;
function findRootTypeKey(type: AbstractType<any>): string;
function getTypeChildren(type: AbstractType<any>): Array<AbstractType<any>>;

Types

interface ID {
  readonly client: number;
  readonly clock: number;
}

interface DeleteSet {
  readonly clients: Map<number, Array<DeleteItem>>;
}

interface TextAttributes {
  [key: string]: any;
}

interface UpdateDecoder {
  readUint8(): number;
  readUint32(): number;
  readVarUint(): number;
  readVarString(): string;
}

interface UpdateEncoder {
  writeUint8(value: number): void;
  writeUint32(value: number): void;
  writeVarUint(value: number): void;
  writeVarString(value: string): void;
  toUint8Array(): Uint8Array;
}

interface DeleteItem {
  clock: number;
  len: number;
}

interface StructStore {
  clients: Map<number, Array<AbstractStruct>>;
  pendingStructs: null | { missing: Map<number, number>; update: Uint8Array };
}

interface Item {
  readonly id: ID;
  readonly left: Item | null;
  readonly right: Item | null;
  readonly origin: ID | null;
  readonly rightOrigin: ID | null;
  readonly parent: AbstractType<any> | ID | null;
  readonly parentSub: string | null;
  readonly content: AbstractContent;
}

// Abstract base classes
abstract class AbstractType<EventType> {
  observe(f: (event: EventType, transaction: Transaction) => void): void;
  unobserve(f: (event: EventType, transaction: Transaction) => void): void;
  observeDeep(f: (events: Array<YEvent<any>>, transaction: Transaction) => void): void;
  clone(): AbstractType<EventType>;
  toJSON(): any;
}

abstract class AbstractStruct {
  readonly id: ID;
  readonly length: number;
}

class YXmlTreeWalker {
  filter: (node: AbstractType<any>) => boolean;
  nextNode(): AbstractType<any> | null;
}

docs

document-management.md

event-system.md

index.md

position-tracking.md

shared-data-types.md

snapshot-system.md

synchronization.md

transaction-system.md

undo-redo-system.md

xml-types.md

tile.json