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