@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.
Files changed (3) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/package.json +1 -2
  3. 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.23.2",
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 docs = new Map();
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 getDoc(data) {
42
+ async function getObject(data) {
44
43
  try {
45
44
  if (['_id', 'organization_id'].includes(data.key))
46
45
  return
47
- let docName = getDocName(data);
48
- let doc = docs.get(docName);
46
+ let name = getName(data);
47
+ let object = objects[name];
49
48
 
50
- if (!doc) {
51
- docs.set(docName, new Map());
52
- doc = docs.get(docName);
49
+ if (!object) {
50
+ objects[name] = object = {}
53
51
  }
54
52
 
55
- if (!doc.has('changeLog')) {
53
+ if (!object.changeLog) {
56
54
  let changeLog = [];
57
- doc.set('undoLog', new Map())
58
- doc.set('redoLog', new Map())
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
- status: "resolve",
65
- array: "crdt-transactions",
63
+ array: "crdt",
66
64
  object: {
67
65
  $filter: {
68
66
  query: [{
69
- key: 'docName',
67
+ key: 'name',
70
68
  operator: "$eq",
71
- value: docName
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
- doc.set('changeLog', changeLog);
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 (!doc.has('text')) {
85
+ } else if (!object.text) {
85
86
  await generateText(data, false);
86
87
  }
87
- return doc;
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 doc = docs.get(getDocName(data))
100
-
101
- let string = '';
102
- let changeLog = doc.get('changeLog');
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
- string = string.customSplice(change.start, change.length, change.value);
105
+ object['text'] = object['text'].customSplice(change.start, change.length, change.value);
106
106
  }
107
107
  }
108
108
 
109
- if (string === '' && data.read !== 'false') {
110
- string = await checkDb(data, flag) || ''
109
+ if (object['text'] === '' && data.read !== 'false') {
110
+ object['text'] = await checkDb(data, flag) || ''
111
111
  }
112
112
 
113
- doc.set('text', string);
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}`)) return;
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', status: "resolve", array, object: { _id: object, key } });
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 docName = getDocName(data);
147
- let doc = docs.get(docName);
148
- let changeLog = doc.get('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 = string.substring(change.start, change.length);
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
- doc.set('text', string.customSplice(change.start, change.length, change.value));
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['datetime'] = change.datetime;
213
- data['frameId'] = change.frameId;
212
+ data.datetime = change.datetime;
213
+ data.frameId = change.frameId;
214
214
 
215
215
  broadcastChange(data);
216
- localChange(data, string);
216
+ localChange(data, object.text);
217
217
  } else
218
- localChange(data, string);
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
- message.send({
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
- function persistChange(data) {
241
- let docName = getDocName(data);
242
- let doc = docs.get(docName);
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-transactions',
246
+ array: 'crdt',
248
247
  object: {
249
- _id: data.object,
250
- docName,
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
- message.listen('crdt', function (response) {
274
+
275
+ crud.socket.listen('crdt', function (response) {
272
276
  let data = response.data
273
- let docName = getDocName(data);
274
- let doc = docs.get(docName);
277
+ let name = getName(data);
278
+ let object = objects[name]
275
279
 
276
- if (doc) {
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.frameId === frameId)
291
+ if (data.clientId === clientId)
288
292
  return
289
- if (data.array.includes('crdt-transactions')) {
293
+ if (data.array.includes('crdt')) {
290
294
  if (data.object && data.object[0]) {
291
295
  let Data = data.object[0];
292
- let docName = Data.docName;
293
- let doc = docs.get(docName);
294
- if (doc && Data.crud) {
295
- // let text = doc.get('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 = doc.get('text').length
308
+ Data.crud.length = object['text'].length
305
309
 
306
- doc.set('changeLog', Data.changeLog)
307
- doc.set('text', Data.text)
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 doc = await getDoc(data);
328
- if (doc) {
329
- let value = doc.get('text')
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 doc = await getDoc(data);
355
- if (doc) {
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 doc = await getDoc(data);
383
- if (doc) {
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 docName = getDocName(data);
429
- let doc = docs.get(docName);
430
- let changeLog = doc.get('changeLog');
431
- let undoLog = doc.get('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 docName = getDocName(data);
453
- let doc = docs.get(docName);
454
- let redoLog = doc.get('redoLog')
455
- let undoLog = Array.from(doc.get('undoLog').values());
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 docName = getDocName(data);
477
- let doc = docs.get(docName);
478
- let changeLog = doc.get('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
- // function deleteDoc(docName) {
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
- // function destroyObserver(docName, typeName) {
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 };