or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

document-management.mdevent-system.mdindex.mdposition-tracking.mdshared-data-types.mdsnapshot-system.mdsynchronization.mdtransaction-system.mdundo-redo-system.mdxml-types.md
tile.json

tessl/npm-yjs

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

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/yjs@13.6.x

To install, run

npx @tessl/cli install tessl/npm-yjs@13.6.0

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;
}