@cocreate/crdt 1.23.2 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/package.json +1 -2
- package/src/index.js +99 -102
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
# [1.24.0](https://github.com/CoCreate-app/CoCreate-crdt/compare/v1.23.3...v1.24.0) (2023-10-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* update to dotnotation ([64da6bf](https://github.com/CoCreate-app/CoCreate-crdt/commit/64da6bfd05ee3ebea1de623add45d7c4fd111aab))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* persistChange() uses crud $push operator ([7e032a7](https://github.com/CoCreate-app/CoCreate-crdt/commit/7e032a7d9c9e7d04a65a74184f04f04668cd682e))
|
|
12
|
+
* replace maps() with object to make crdt objects portable ([fac31c5](https://github.com/CoCreate-app/CoCreate-crdt/commit/fac31c580a3b4ed420dc2eb2223f9198487a2b8e))
|
|
13
|
+
|
|
14
|
+
## [1.23.3](https://github.com/CoCreate-app/CoCreate-crdt/compare/v1.23.2...v1.23.3) (2023-10-19)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* removed @cocreate/message-client ([8cd41ca](https://github.com/CoCreate-app/CoCreate-crdt/commit/8cd41ca5059e0b2852aa9d0cf7038eb087eab996))
|
|
20
|
+
|
|
1
21
|
## [1.23.2](https://github.com/CoCreate-app/CoCreate-crdt/compare/v1.23.1...v1.23.2) (2023-10-17)
|
|
2
22
|
|
|
3
23
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/crdt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "CoCreate crdt",
|
|
5
5
|
"author": "CoCreate LLC",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@cocreate/crud-client": "^1.28.4",
|
|
44
44
|
"@cocreate/local-storage": "^1.10.5",
|
|
45
|
-
"@cocreate/message-client": "^1.8.3",
|
|
46
45
|
"@cocreate/utils": "^1.25.3"
|
|
47
46
|
}
|
|
48
47
|
}
|
package/src/index.js
CHANGED
|
@@ -22,14 +22,13 @@
|
|
|
22
22
|
|
|
23
23
|
/*globals config, atob, btoa, localStorage, CustomEvent*/
|
|
24
24
|
import crud from '@cocreate/crud-client';
|
|
25
|
-
import message from '@cocreate/message-client';
|
|
26
25
|
import uuid from '@cocreate/uuid';
|
|
27
26
|
import localStorage from '@cocreate/local-storage';
|
|
28
27
|
|
|
29
|
-
const
|
|
28
|
+
const objects = {}
|
|
29
|
+
const clientId = crud.socket.clientId || uuid.generate(12);
|
|
30
30
|
const frameId = crud.socket.frameId || uuid.generate(12);
|
|
31
31
|
const checkedDb = new Map();
|
|
32
|
-
const isInit = new Map();
|
|
33
32
|
|
|
34
33
|
function init(data) {
|
|
35
34
|
getText(data).then(value => {
|
|
@@ -40,35 +39,34 @@ function init(data) {
|
|
|
40
39
|
});
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
async function
|
|
42
|
+
async function getObject(data) {
|
|
44
43
|
try {
|
|
45
44
|
if (['_id', 'organization_id'].includes(data.key))
|
|
46
45
|
return
|
|
47
|
-
let
|
|
48
|
-
let
|
|
46
|
+
let name = getName(data);
|
|
47
|
+
let object = objects[name];
|
|
49
48
|
|
|
50
|
-
if (!
|
|
51
|
-
|
|
52
|
-
doc = docs.get(docName);
|
|
49
|
+
if (!object) {
|
|
50
|
+
objects[name] = object = {}
|
|
53
51
|
}
|
|
54
52
|
|
|
55
|
-
if (!
|
|
53
|
+
if (!object.changeLog) {
|
|
56
54
|
let changeLog = [];
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
object.undoLog = new Map()
|
|
56
|
+
object.redoLog = new Map()
|
|
57
|
+
|
|
59
58
|
|
|
60
59
|
if (data.read != 'false') {
|
|
61
60
|
if (!data.newObject) {
|
|
62
61
|
let response = await crud.send({
|
|
63
62
|
method: "read.object",
|
|
64
|
-
|
|
65
|
-
array: "crdt-transactions",
|
|
63
|
+
array: "crdt",
|
|
66
64
|
object: {
|
|
67
65
|
$filter: {
|
|
68
66
|
query: [{
|
|
69
|
-
key: '
|
|
67
|
+
key: 'name',
|
|
70
68
|
operator: "$eq",
|
|
71
|
-
value:
|
|
69
|
+
value: name
|
|
72
70
|
}],
|
|
73
71
|
limit: 1
|
|
74
72
|
}
|
|
@@ -78,13 +76,16 @@ async function getDoc(data) {
|
|
|
78
76
|
changeLog = response.object[0].changeLog;
|
|
79
77
|
}
|
|
80
78
|
}
|
|
81
|
-
|
|
82
|
-
await generateText(data, true);
|
|
79
|
+
object.changeLog = changeLog
|
|
80
|
+
// await generateText(data, true);
|
|
81
|
+
if (!object.text) {
|
|
82
|
+
await generateText(data, true);
|
|
83
|
+
}
|
|
83
84
|
}
|
|
84
|
-
} else if (!
|
|
85
|
+
} else if (!object.text) {
|
|
85
86
|
await generateText(data, false);
|
|
86
87
|
}
|
|
87
|
-
return
|
|
88
|
+
return object;
|
|
88
89
|
} catch (e) {
|
|
89
90
|
console.log('Invalid param', e);
|
|
90
91
|
}
|
|
@@ -96,22 +97,20 @@ String.prototype.customSplice = function (index, absIndex, string) {
|
|
|
96
97
|
|
|
97
98
|
async function generateText(data, flag) {
|
|
98
99
|
try {
|
|
99
|
-
let
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
let
|
|
103
|
-
for (let change of changeLog) {
|
|
100
|
+
let name = getName(data)
|
|
101
|
+
let object = objects[name]
|
|
102
|
+
object['text'] = ''
|
|
103
|
+
for (let change of object['changeLog']) {
|
|
104
104
|
if (change) {
|
|
105
|
-
|
|
105
|
+
object['text'] = object['text'].customSplice(change.start, change.length, change.value);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
if (
|
|
110
|
-
|
|
109
|
+
if (object['text'] === '' && data.read !== 'false') {
|
|
110
|
+
object['text'] = await checkDb(data, flag) || ''
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
return string;
|
|
113
|
+
return object['text'];
|
|
115
114
|
} catch (e) {
|
|
116
115
|
console.error(e);
|
|
117
116
|
}
|
|
@@ -119,14 +118,15 @@ async function generateText(data, flag) {
|
|
|
119
118
|
|
|
120
119
|
async function checkDb(data, flag) {
|
|
121
120
|
let { array, object, key } = data;
|
|
122
|
-
if (checkedDb.get(`${array}${object}${key}`))
|
|
121
|
+
if (checkedDb.get(`${array}${object}${key}`))
|
|
122
|
+
return;
|
|
123
123
|
checkedDb.set(`${array}${object}${key}`, true);
|
|
124
124
|
|
|
125
125
|
let string = ''
|
|
126
126
|
if (data.newObject)
|
|
127
127
|
string = data.newObject
|
|
128
128
|
else {
|
|
129
|
-
let response = await crud.send({ method: 'read.object',
|
|
129
|
+
let response = await crud.send({ method: 'read.object', array, object: { _id: object, key } });
|
|
130
130
|
string = crud.getValueFromObject(response.object[0], key);
|
|
131
131
|
}
|
|
132
132
|
|
|
@@ -139,16 +139,18 @@ async function checkDb(data, flag) {
|
|
|
139
139
|
insertChange(data);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
return string;
|
|
142
|
+
return string || '';
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
function insertChange(data, flag) {
|
|
146
|
-
let
|
|
147
|
-
let
|
|
148
|
-
let changeLog =
|
|
146
|
+
let name = getName(data);
|
|
147
|
+
let object = objects[name];
|
|
148
|
+
let changeLog = object.changeLog;
|
|
149
149
|
if (!changeLog)
|
|
150
150
|
return
|
|
151
151
|
|
|
152
|
+
object.text = object.text || ''
|
|
153
|
+
|
|
152
154
|
let type = 'insert';
|
|
153
155
|
if (data.start == undefined) return;
|
|
154
156
|
if (!data.value)
|
|
@@ -160,6 +162,7 @@ function insertChange(data, flag) {
|
|
|
160
162
|
start: data.start,
|
|
161
163
|
end: data.end,
|
|
162
164
|
length: data.length || 0,
|
|
165
|
+
clientId: data.clientId || clientId,
|
|
163
166
|
frameId: data.frameId || frameId,
|
|
164
167
|
user_id: data.user_id || localStorage.getItem("user_id"),
|
|
165
168
|
type
|
|
@@ -193,43 +196,41 @@ function insertChange(data, flag) {
|
|
|
193
196
|
console.log('null change')
|
|
194
197
|
return
|
|
195
198
|
}
|
|
196
|
-
let string = doc.get('text') || '';
|
|
197
199
|
if (change.length > 0)
|
|
198
|
-
change.removedValue =
|
|
200
|
+
change.removedValue = object.text.substring(change.start, change.length);
|
|
199
201
|
|
|
200
202
|
if (flag == 'replace') {
|
|
201
203
|
// TODO get current string and create new changeLog array then push new change
|
|
202
204
|
changeLog = [change];
|
|
203
|
-
doc.set('changeLog', changeLog)
|
|
204
205
|
} else {
|
|
205
206
|
changeLog.push(change);
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
|
|
209
|
-
string = doc.get('text');
|
|
209
|
+
object.text = object.text.customSplice(change.start, change.length, change.value);
|
|
210
210
|
|
|
211
211
|
if (!data.frameId) {
|
|
212
|
-
data
|
|
213
|
-
data
|
|
212
|
+
data.datetime = change.datetime;
|
|
213
|
+
data.frameId = change.frameId;
|
|
214
214
|
|
|
215
215
|
broadcastChange(data);
|
|
216
|
-
localChange(data,
|
|
216
|
+
localChange(data, object.text);
|
|
217
217
|
} else
|
|
218
|
-
localChange(data,
|
|
218
|
+
localChange(data, object.text);
|
|
219
219
|
|
|
220
220
|
if (data.frameId == frameId && data.save != "false")
|
|
221
|
-
persistChange(data);
|
|
221
|
+
persistChange(data, change);
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
function broadcastChange(data) {
|
|
225
|
-
|
|
225
|
+
crud.socket.send({
|
|
226
|
+
method: "crdt",
|
|
226
227
|
broadcastSender: false,
|
|
227
228
|
broadcastBrowser: true,
|
|
228
|
-
message: "crdt",
|
|
229
229
|
data
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
|
|
233
234
|
function localChange(data, string) {
|
|
234
235
|
const localChange = new CustomEvent('cocreate-crdt-update', {
|
|
235
236
|
detail: { ...data, string },
|
|
@@ -237,25 +238,27 @@ function localChange(data, string) {
|
|
|
237
238
|
window.dispatchEvent(localChange);
|
|
238
239
|
}
|
|
239
240
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
let
|
|
243
|
-
let changeLog = doc.get('changeLog');
|
|
244
|
-
let text = doc.get('text');
|
|
241
|
+
|
|
242
|
+
function persistChange(data, change) {
|
|
243
|
+
let name = getName(data);
|
|
245
244
|
let Data = {
|
|
246
245
|
method: 'update.object',
|
|
247
|
-
array: 'crdt
|
|
246
|
+
array: 'crdt',
|
|
248
247
|
object: {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
changeLog,
|
|
252
|
-
text,
|
|
248
|
+
name,
|
|
249
|
+
'$push.changeLog': change,
|
|
253
250
|
crud: {
|
|
254
251
|
array: data.array,
|
|
255
252
|
object: data.object,
|
|
256
253
|
key: data.key
|
|
257
254
|
}
|
|
258
255
|
},
|
|
256
|
+
$filter: {
|
|
257
|
+
query: [
|
|
258
|
+
{ key: 'name', value: name, operator: '$eq', index: true }
|
|
259
|
+
],
|
|
260
|
+
limit: 1
|
|
261
|
+
},
|
|
259
262
|
upsert: true,
|
|
260
263
|
namespace: data.namespace,
|
|
261
264
|
room: data.room,
|
|
@@ -268,12 +271,13 @@ function persistChange(data) {
|
|
|
268
271
|
crud.send(Data);
|
|
269
272
|
}
|
|
270
273
|
|
|
271
|
-
|
|
274
|
+
|
|
275
|
+
crud.socket.listen('crdt', function (response) {
|
|
272
276
|
let data = response.data
|
|
273
|
-
let
|
|
274
|
-
let
|
|
277
|
+
let name = getName(data);
|
|
278
|
+
let object = objects[name]
|
|
275
279
|
|
|
276
|
-
if (
|
|
280
|
+
if (object) {
|
|
277
281
|
if (data.frameId !== frameId) {
|
|
278
282
|
insertChange(data);
|
|
279
283
|
}
|
|
@@ -284,15 +288,15 @@ crud.listen('update.object', (data) => sync(data))
|
|
|
284
288
|
crud.listen('delete.object', (data) => sync(data))
|
|
285
289
|
|
|
286
290
|
function sync(data) {
|
|
287
|
-
if (data.
|
|
291
|
+
if (data.clientId === clientId)
|
|
288
292
|
return
|
|
289
|
-
if (data.array.includes('crdt
|
|
293
|
+
if (data.array.includes('crdt')) {
|
|
290
294
|
if (data.object && data.object[0]) {
|
|
291
295
|
let Data = data.object[0];
|
|
292
|
-
let
|
|
293
|
-
let
|
|
294
|
-
if (
|
|
295
|
-
// let text =
|
|
296
|
+
let name = Data.name;
|
|
297
|
+
let object = objects[name];
|
|
298
|
+
if (object && Data.crud) {
|
|
299
|
+
// let text = object['text']
|
|
296
300
|
// if (!text && text !== '') {
|
|
297
301
|
// setTimeout(function () {
|
|
298
302
|
// console.log("text empty timout set");
|
|
@@ -301,11 +305,11 @@ function sync(data) {
|
|
|
301
305
|
// } else {
|
|
302
306
|
Data.crud.value = Data.text
|
|
303
307
|
Data.crud.start = 0
|
|
304
|
-
Data.crud.length =
|
|
308
|
+
Data.crud.length = object['text'].length
|
|
305
309
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
// TODO: compare modified dates to check if arrays need to merged and orderd by date or if we just use server
|
|
310
|
+
|
|
311
|
+
object['changeLog'] = Data.changeLog
|
|
312
|
+
object['text'] = Data.text // TODO: compare modified dates to check if arrays need to merged and orderd by date or if we just use server
|
|
309
313
|
localChange(Data.crud, Data.text)
|
|
310
314
|
console.log('crdtSync')
|
|
311
315
|
// }
|
|
@@ -324,9 +328,9 @@ crdt.getText({
|
|
|
324
328
|
*/
|
|
325
329
|
async function getText(data) {
|
|
326
330
|
try {
|
|
327
|
-
let
|
|
328
|
-
if (
|
|
329
|
-
let value =
|
|
331
|
+
let object = await getObject(data);
|
|
332
|
+
if (object) {
|
|
333
|
+
let value = object.text
|
|
330
334
|
return value;
|
|
331
335
|
} else {
|
|
332
336
|
console.log('undefined')
|
|
@@ -351,8 +355,8 @@ crdt.replaceText({
|
|
|
351
355
|
*/
|
|
352
356
|
async function replaceText(data) {
|
|
353
357
|
try {
|
|
354
|
-
let
|
|
355
|
-
if (
|
|
358
|
+
let object = await getObject(data);
|
|
359
|
+
if (object) {
|
|
356
360
|
let oldValue = await getText(data);
|
|
357
361
|
if (oldValue)
|
|
358
362
|
data.length = oldValue.length;
|
|
@@ -379,8 +383,8 @@ crdt.updateText({
|
|
|
379
383
|
})
|
|
380
384
|
*/
|
|
381
385
|
async function updateText(data, flag) {
|
|
382
|
-
let
|
|
383
|
-
if (
|
|
386
|
+
let object = await getObject(data);
|
|
387
|
+
if (object) {
|
|
384
388
|
|
|
385
389
|
insertChange(data, flag);
|
|
386
390
|
|
|
@@ -425,10 +429,10 @@ function createChange(data, change) {
|
|
|
425
429
|
}
|
|
426
430
|
|
|
427
431
|
function undoText(data) {
|
|
428
|
-
let
|
|
429
|
-
let
|
|
430
|
-
let changeLog =
|
|
431
|
-
let undoLog =
|
|
432
|
+
let name = getName(data);
|
|
433
|
+
let object = objects[name];
|
|
434
|
+
let changeLog = object.changeLog;
|
|
435
|
+
let undoLog = object.undoLog;
|
|
432
436
|
|
|
433
437
|
for (let index = changeLog.length - 1; index >= 0; index--) {
|
|
434
438
|
let change = Object.assign({}, changeLog[index]);
|
|
@@ -449,10 +453,10 @@ function undoText(data) {
|
|
|
449
453
|
}
|
|
450
454
|
|
|
451
455
|
function redoText(data) {
|
|
452
|
-
let
|
|
453
|
-
let
|
|
454
|
-
let redoLog =
|
|
455
|
-
let undoLog = Array.from(
|
|
456
|
+
let name = getName(data);
|
|
457
|
+
let object = objects[name];
|
|
458
|
+
let redoLog = object.redoLog
|
|
459
|
+
let undoLog = Array.from(object.undoLog.values());
|
|
456
460
|
|
|
457
461
|
for (let index = undoLog.length - 1; index >= 0; index--) {
|
|
458
462
|
let change = Object.assign({}, undoLog[index]);
|
|
@@ -473,9 +477,9 @@ function redoText(data) {
|
|
|
473
477
|
|
|
474
478
|
async function viewVersion(data) {
|
|
475
479
|
try {
|
|
476
|
-
let
|
|
477
|
-
let
|
|
478
|
-
let changeLog =
|
|
480
|
+
let name = getName(data);
|
|
481
|
+
let object = objects[name];
|
|
482
|
+
let changeLog = object.changeLog;
|
|
479
483
|
let string = '';
|
|
480
484
|
|
|
481
485
|
let log = changeLog.slice(0, data.version)
|
|
@@ -490,21 +494,14 @@ async function viewVersion(data) {
|
|
|
490
494
|
}
|
|
491
495
|
}
|
|
492
496
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
//
|
|
496
|
-
// if (this.docs[docName]) {
|
|
497
|
-
// delete this.docs[docName];
|
|
497
|
+
// function deleteObject(name) {
|
|
498
|
+
// if (objects[name]) {
|
|
499
|
+
// delete objects[name];
|
|
498
500
|
// }
|
|
499
501
|
// }
|
|
500
502
|
|
|
501
|
-
|
|
502
|
-
// this.docs[docName].doc.getText(typeName).unobserve((event) => {});
|
|
503
|
-
// this.docs[docName].socket.awareness.off('change', this._awarenessListener);
|
|
504
|
-
// }
|
|
505
|
-
|
|
506
|
-
function getDocName(data) {
|
|
503
|
+
function getName(data) {
|
|
507
504
|
return `${data.array}${data.object}${data.key}`;
|
|
508
505
|
}
|
|
509
506
|
|
|
510
|
-
export default { init, getText, updateText, replaceText, undoText, redoText, viewVersion };
|
|
507
|
+
export default { init, objects, getName, getText, updateText, replaceText, undoText, redoText, viewVersion };
|