0
# Extensions
1
2
Framework for creating custom connectors, databases, and shared types to extend Yjs functionality beyond the built-in modules.
3
4
## Capabilities
5
6
### Module Extension System
7
8
Add external modules to extend Yjs functionality before creating instances.
9
10
```javascript { .api }
11
/**
12
* Extend Yjs with additional modules
13
* Must be called before creating instances that use the modules
14
* @param {...any} modules - Connector, database, or type modules to add
15
*/
16
Y.extend(...modules);
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
// Node.js - Manual module loading
23
const Y = require('yjs');
24
25
// Load required modules
26
Y.extend(
27
require('y-memory'), // Memory database
28
require('y-array'), // Array shared type
29
require('y-map'), // Map shared type
30
require('y-text'), // Text shared type
31
require('y-websockets-client') // WebSocket connector
32
);
33
34
// Now create instance with loaded modules
35
Y({
36
db: { name: 'memory' },
37
connector: { name: 'websockets-client', room: 'test' },
38
share: { doc: 'Text', list: 'Array' }
39
}).then(function(y) {
40
console.log('Yjs ready with extended modules');
41
});
42
43
// Browser - Conditional module loading
44
if (typeof window !== 'undefined') {
45
// Browser environment - modules loaded automatically
46
Y({
47
sourceDir: '/bower_components',
48
type: ['Array', 'Map', 'Text', 'WebSocketsClient', 'Memory'],
49
db: { name: 'memory' },
50
connector: { name: 'websockets-client', room: 'browser-test' },
51
share: { content: 'Text' }
52
});
53
} else {
54
// Node.js environment - manual loading required
55
Y.extend(require('y-memory'), require('y-text'));
56
}
57
```
58
59
### Abstract Base Classes
60
61
Base classes for implementing custom connectors and database adapters.
62
63
```javascript { .api }
64
/**
65
* Abstract base class for custom connectors
66
* Implement communication protocols for peer synchronization
67
*/
68
class Y.AbstractConnector {
69
constructor(y, options);
70
71
/**
72
* Send message to connected peers
73
* @param {ArrayBuffer} message - Binary message to send
74
*/
75
send(message);
76
77
/**
78
* Handle received message from peer
79
* @param {ArrayBuffer} message - Binary message received
80
*/
81
onMessage(message);
82
83
/**
84
* Connect to peers
85
*/
86
connect();
87
88
/**
89
* Disconnect from peers
90
*/
91
disconnect();
92
93
/**
94
* Check if connected to any peers
95
* @returns {boolean} Connection status
96
*/
97
isConnected();
98
}
99
100
/**
101
* Abstract base class for custom database adapters
102
* Implement persistence and transaction management
103
*/
104
class Y.AbstractDatabase {
105
constructor(y, options);
106
107
/**
108
* Store operation in database
109
* @param {Operation} op - Operation to store
110
*/
111
storeOperation(op);
112
113
/**
114
* Retrieve operations from database
115
* @param {any} criteria - Search criteria
116
* @returns {Operation[]} Matching operations
117
*/
118
getOperations(criteria);
119
120
/**
121
* Delete operations from database
122
* @param {any} criteria - Deletion criteria
123
*/
124
deleteOperations(criteria);
125
126
/**
127
* Start garbage collection
128
*/
129
startGarbageCollector();
130
131
/**
132
* Stop garbage collection
133
*/
134
stopGarbageCollector();
135
}
136
```
137
138
**Usage Examples:**
139
140
```javascript
141
// Custom WebSocket connector implementation
142
class CustomWebSocketConnector extends Y.AbstractConnector {
143
constructor(y, options) {
144
super(y, options);
145
this.url = options.url;
146
this.room = options.room;
147
this.ws = null;
148
this.connected = false;
149
}
150
151
connect() {
152
this.ws = new WebSocket(this.url);
153
154
this.ws.onopen = () => {
155
this.connected = true;
156
this.ws.send(JSON.stringify({
157
type: 'join',
158
room: this.room
159
}));
160
};
161
162
this.ws.onmessage = (event) => {
163
const data = JSON.parse(event.data);
164
if (data.type === 'sync') {
165
this.onMessage(data.message);
166
}
167
};
168
169
this.ws.onclose = () => {
170
this.connected = false;
171
};
172
}
173
174
send(message) {
175
if (this.connected) {
176
this.ws.send(JSON.stringify({
177
type: 'sync',
178
room: this.room,
179
message: message
180
}));
181
}
182
}
183
184
disconnect() {
185
if (this.ws) {
186
this.ws.close();
187
this.connected = false;
188
}
189
}
190
191
isConnected() {
192
return this.connected;
193
}
194
}
195
196
// Register custom connector
197
Y.extend({
198
name: 'custom-websocket',
199
connector: CustomWebSocketConnector
200
});
201
202
// Use custom connector
203
Y({
204
db: { name: 'memory' },
205
connector: {
206
name: 'custom-websocket',
207
url: 'ws://custom-server.com:8080',
208
room: 'custom-room'
209
},
210
share: { doc: 'Text' }
211
});
212
```
213
214
### Utility Classes and Functions
215
216
Helper utilities for building extensions and custom functionality.
217
218
```javascript { .api }
219
/**
220
* Utility functions and classes namespace
221
*/
222
Y.utils: {
223
/**
224
* Event listener handler for managing DOM events
225
*/
226
EventListenerHandler: Function,
227
228
/**
229
* Extended event handling with custom event types
230
*/
231
EventHandler: Function,
232
233
/**
234
* Base class for custom shared types
235
*/
236
CustomType: Function,
237
238
/**
239
* Type definition utilities for custom types
240
*/
241
CustomTypeDefinition: Function,
242
243
/**
244
* Deep copy utility for objects
245
* @param {any} obj - Object to copy
246
* @returns {any} Deep copy of object
247
*/
248
copyObject: Function,
249
250
/**
251
* Copy operation data structures
252
* @param {Operation} op - Operation to copy
253
* @returns {Operation} Copy of operation
254
*/
255
copyOperation: Function,
256
257
/**
258
* Compare operation IDs for ordering
259
* @param {ID} id1 - First ID
260
* @param {ID} id2 - Second ID
261
* @returns {number} Comparison result
262
*/
263
compareIds: Function,
264
265
/**
266
* Generate unique identifier
267
* @returns {string} Unique GUID
268
*/
269
generateGuid: Function
270
};
271
```
272
273
**Usage Examples:**
274
275
```javascript
276
// Custom shared type using utilities
277
class CustomCounter extends Y.utils.CustomType {
278
constructor() {
279
super();
280
this.value = 0;
281
this.eventHandler = new Y.utils.EventHandler();
282
}
283
284
increment() {
285
this.value++;
286
this.eventHandler.callEventListeners('change', [{
287
type: 'increment',
288
newValue: this.value,
289
id: Y.utils.generateGuid()
290
}]);
291
}
292
293
decrement() {
294
this.value--;
295
this.eventHandler.callEventListeners('change', [{
296
type: 'decrement',
297
newValue: this.value,
298
id: Y.utils.generateGuid()
299
}]);
300
}
301
302
observe(callback) {
303
this.eventHandler.addEventListener('change', callback);
304
}
305
306
getValue() {
307
return this.value;
308
}
309
}
310
311
// Register custom type
312
Y.extend({
313
name: 'Counter',
314
type: CustomCounter
315
});
316
317
// Use custom type
318
Y({
319
db: { name: 'memory' },
320
connector: { name: 'test', room: 'counter-test' },
321
share: { counter: 'Counter' }
322
}).then(function(y) {
323
const counter = y.share.counter;
324
325
counter.observe(function(event) {
326
console.log('Counter changed:', event);
327
});
328
329
counter.increment(); // Triggers change event
330
console.log('Current value:', counter.getValue());
331
});
332
333
// Advanced utilities usage
334
function createAdvancedExtension() {
335
// Use object copying for state management
336
const baseState = { version: 1, features: ['sync', 'offline'] };
337
const customState = Y.utils.copyObject(baseState);
338
customState.features.push('custom-extension');
339
340
// Generate unique IDs for operations
341
const operationId = Y.utils.generateGuid();
342
343
return {
344
name: 'advanced-extension',
345
state: customState,
346
operationId: operationId,
347
348
compare: function(id1, id2) {
349
return Y.utils.compareIds(id1, id2);
350
}
351
};
352
}
353
354
Y.extend(createAdvancedExtension());
355
```
356
357
### External Module Ecosystem
358
359
Overview of available external modules that can be loaded with Y.extend().
360
361
#### Connector Modules
362
363
```javascript { .api }
364
// Available connector modules (require separate installation)
365
const connectorModules = {
366
'y-webrtc': 'Browser-to-browser peer-to-peer via WebRTC',
367
'y-websockets-client': 'WebSocket client connector',
368
'y-xmpp': 'XMPP multi-user chat rooms',
369
'y-ipfs': 'IPFS distributed network connector',
370
'y-test': 'Testing connector for development'
371
};
372
```
373
374
#### Database Modules
375
376
```javascript { .api }
377
// Available database modules (require separate installation)
378
const databaseModules = {
379
'y-memory': 'In-memory storage (no persistence)',
380
'y-indexeddb': 'Browser offline storage',
381
'y-leveldb': 'Node.js persistent storage'
382
};
383
```
384
385
#### Shared Type Modules
386
387
```javascript { .api }
388
// Available shared type modules (require separate installation)
389
const typeModules = {
390
'y-array': 'Collaborative arrays',
391
'y-map': 'Collaborative key-value maps',
392
'y-text': 'Collaborative text with editor bindings',
393
'y-xml': 'Collaborative XML/DOM manipulation',
394
'y-richtext': 'Rich text with Quill editor binding'
395
};
396
```
397
398
### Module Loading Patterns
399
400
#### Node.js Pattern
401
402
```javascript
403
// Explicit require and extend
404
const Y = require('yjs');
405
Y.extend(
406
require('y-memory'),
407
require('y-websockets-client'),
408
require('y-array'),
409
require('y-map')
410
);
411
```
412
413
#### Browser Pattern
414
415
```javascript
416
// Automatic loading via configuration
417
Y({
418
sourceDir: '/bower_components',
419
type: ['Memory', 'WebSocketsClient', 'Array', 'Map'],
420
// ... rest of config
421
});
422
```
423
424
#### Conditional Loading
425
426
```javascript
427
// Environment-specific loading
428
if (typeof require !== 'undefined') {
429
// Node.js
430
Y.extend(require('y-leveldb'));
431
} else {
432
// Browser - will auto-load IndexedDB
433
console.log('Browser environment detected');
434
}
435
```
436
437
### Custom Module Development
438
439
Template for creating new Yjs modules:
440
441
```javascript { .api }
442
// Module template structure
443
const CustomModule = {
444
// Module identification
445
name: 'custom-module',
446
version: '1.0.0',
447
448
// Module type (connector, database, or type)
449
type: 'connector', // or 'database' or 'type'
450
451
// Implementation class
452
implementation: CustomImplementationClass,
453
454
// Optional initialization
455
init: function(Y) {
456
// Setup code when module is loaded
457
},
458
459
// Optional cleanup
460
destroy: function() {
461
// Cleanup code when module is unloaded
462
}
463
};
464
465
// Export for use with Y.extend()
466
module.exports = CustomModule;
467
```