A framework for shared editing on any data with offline-first peer-to-peer collaboration
pkg:bower/yjs@12.3.x
npx @tessl/cli install tessl/bower-yjs@12.3.0Yjs is a framework for offline-first peer-to-peer shared editing on structured data like text, richtext, JSON, or XML. It provides a modular architecture where users combine connectors (WebRTC, WebSockets, XMPP), database adapters (memory, IndexedDB, LevelDB), and data types (Map, Array, Text, XML, RichText) to build collaborative editing applications. The framework hides the complexity of concurrent editing by automatically resolving conflicts through its CRDT-based approach.
bower install yjsFor browser environments:
// Manual script inclusion
<script src="/bower_components/yjs/y.js"></script>For Node.js/CommonJS environments:
const Y = require('yjs');// Create a Yjs instance with configuration
Y({
db: { name: 'memory' },
connector: {
name: 'websockets-client',
room: 'my-collaborative-room',
url: 'ws://localhost:1234'
},
sourceDir: '/bower_components',
share: {
textarea: 'Text',
chat: 'Array',
drawing: 'Map'
}
}).then(function (y) {
// Access shared types
y.share.textarea.bind(document.getElementById('editor'));
// Listen for changes
y.share.chat.observe(function(event) {
console.log('Chat updated:', event);
});
// Add data
y.share.chat.push(['Hello from user!']);
y.share.drawing.set('stroke1', { x: 10, y: 20, color: 'red' });
});Yjs is built around several key components:
Primary constructor and configuration system for creating Yjs collaborative instances.
/**
* Creates a new Yjs instance with specified configuration
* @param {YjsOptions} options - Configuration object
* @returns {Promise<YjsInstance>} Promise resolving to configured Yjs instance
*/
function Y(options);
interface YjsOptions {
db: DatabaseConfig;
connector: ConnectorConfig;
sourceDir?: string;
share: ShareConfig;
type?: string[];
}
interface DatabaseConfig {
name: 'memory' | 'indexeddb' | 'leveldb';
}
interface ConnectorConfig {
name: 'webrtc' | 'websockets-client' | 'xmpp' | 'test';
room: string;
url?: string;
auth?: any;
checkAuth?: Function;
generateUserId?: boolean;
}
interface ShareConfig {
[key: string]: 'Array' | 'Map' | 'Text' | 'Xml' | 'RichText';
}CRDT-based collaborative data structures for different use cases, from simple arrays to rich text editing.
interface SharedArray {
/** Number of items in the array */
length: number;
push(items: any[]): void;
delete(index: number, length?: number): void;
get(index: number): any;
insert(index: number, items: any[]): void;
toArray(): any[];
observe(callback: (event: ArrayEvent) => void): void;
}
interface SharedMap {
set(key: string, value: any): void;
get(key: string): any;
delete(key: string): void;
observe(callback: (event: MapEvent) => void): void;
}
interface SharedText {
bind(element: HTMLElement): void;
bindMonaco(editor: any): void;
bindAce(editor: any): void;
bindCodeMirror(editor: any): void;
observe(callback: (event: TextEvent) => void): void;
}Real-time synchronization and peer-to-peer communication management.
interface YjsConnector {
onUserEvent(callback: (event: UserEvent) => void): void;
whenSynced(callback: () => void): void;
disconnect(): void;
reconnect(): void;
isSynced: boolean;
}Data persistence layer with garbage collection and transaction management.
interface YjsDatabase {
stopGarbageCollector(): void;
gc: boolean;
gcTimeout: number;
userId: string;
}Framework for creating custom connectors, databases, and shared types.
/**
* Extend Yjs with additional modules
* @param {...any} modules - Modules to add to Yjs
*/
function Y.extend(...modules);
/**
* Array constructor for creating nested array types
*/
Y.Array;
/**
* Map constructor for creating nested map types
*/
Y.Map;
/**
* Text constructor for creating nested text types
*/
Y.Text;
class Y.AbstractConnector {
// Base class for custom connectors
}
class Y.AbstractDatabase {
// Base class for custom database adapters
}interface YjsInstance {
share: ShareInstances;
connector: YjsConnector;
db: YjsDatabase;
isConnected(): boolean;
disconnect(): void;
reconnect(): void;
close(): void;
destroy(): void;
}
interface ShareInstances {
[key: string]: SharedArray | SharedMap | SharedText | SharedXml | SharedRichText;
}
interface ArrayEvent {
type: 'insert' | 'delete';
index: number;
length: number;
values?: any[];
}
interface MapEvent {
type: 'add' | 'update' | 'delete';
name: string;
value?: any;
oldValue?: any;
}
interface TextEvent {
type: 'insert' | 'delete';
index: number;
length: number;
values?: string[];
}
interface UserEvent {
action: 'userJoined' | 'userLeft';
user: string;
}