@cocreate/crdt 1.23.3 → 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 CHANGED
@@ -1,3 +1,16 @@
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
+
1
14
  ## [1.23.3](https://github.com/CoCreate-app/CoCreate-crdt/compare/v1.23.2...v1.23.3) (2023-10-19)
2
15
 
3
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/crdt",
3
- "version": "1.23.3",
3
+ "version": "1.24.0",
4
4
  "description": "CoCreate crdt",
5
5
  "author": "CoCreate LLC",
6
6
  "license": "AGPL-3.0",
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 docs = new Map();
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 getDoc(data) {
42
+ async function getObject(data) {
43
43
  try {
44
44
  if (['_id', 'organization_id'].includes(data.key))
45
45
  return
46
- let docName = getDocName(data);
47
- let doc = docs.get(docName);
46
+ let name = getName(data);
47
+ let object = objects[name];
48
48
 
49
- if (!doc) {
50
- docs.set(docName, new Map());
51
- doc = docs.get(docName);
49
+ if (!object) {
50
+ objects[name] = object = {}
52
51
  }
53
52
 
54
- if (!doc.has('changeLog')) {
53
+ if (!object.changeLog) {
55
54
  let changeLog = [];
56
- doc.set('undoLog', new Map())
57
- doc.set('redoLog', new Map())
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
- status: "resolve",
64
- array: "crdt-transactions",
63
+ array: "crdt",
65
64
  object: {
66
65
  $filter: {
67
66
  query: [{
68
- key: 'docName',
67
+ key: 'name',
69
68
  operator: "$eq",
70
- value: docName
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
- doc.set('changeLog', changeLog);
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 (!doc.has('text')) {
85
+ } else if (!object.text) {
84
86
  await generateText(data, false);
85
87
  }
86
- return doc;
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 doc = docs.get(getDocName(data))
99
-
100
- let string = '';
101
- let changeLog = doc.get('changeLog');
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
- string = string.customSplice(change.start, change.length, change.value);
105
+ object['text'] = object['text'].customSplice(change.start, change.length, change.value);
105
106
  }
106
107
  }
107
108
 
108
- if (string === '' && data.read !== 'false') {
109
- string = await checkDb(data, flag) || ''
109
+ if (object['text'] === '' && data.read !== 'false') {
110
+ object['text'] = await checkDb(data, flag) || ''
110
111
  }
111
112
 
112
- doc.set('text', string);
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}`)) return;
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', status: "resolve", array, object: { _id: object, key } });
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 docName = getDocName(data);
146
- let doc = docs.get(docName);
147
- let changeLog = doc.get('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 = string.substring(change.start, change.length);
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
- doc.set('text', string.customSplice(change.start, change.length, change.value));
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['datetime'] = change.datetime;
212
- data['frameId'] = change.frameId;
212
+ data.datetime = change.datetime;
213
+ data.frameId = change.frameId;
213
214
 
214
215
  broadcastChange(data);
215
- localChange(data, string);
216
+ localChange(data, object.text);
216
217
  } else
217
- localChange(data, string);
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
- function persistChange(data) {
240
- let docName = getDocName(data);
241
- let doc = docs.get(docName);
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-transactions',
246
+ array: 'crdt',
247
247
  object: {
248
- _id: data.object,
249
- docName,
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 docName = getDocName(data);
273
- let doc = docs.get(docName);
277
+ let name = getName(data);
278
+ let object = objects[name]
274
279
 
275
- if (doc) {
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.frameId === frameId)
291
+ if (data.clientId === clientId)
287
292
  return
288
- if (data.array.includes('crdt-transactions')) {
293
+ if (data.array.includes('crdt')) {
289
294
  if (data.object && data.object[0]) {
290
295
  let Data = data.object[0];
291
- let docName = Data.docName;
292
- let doc = docs.get(docName);
293
- if (doc && Data.crud) {
294
- // 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']
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 = doc.get('text').length
308
+ Data.crud.length = object['text'].length
304
309
 
305
- doc.set('changeLog', Data.changeLog)
306
- doc.set('text', Data.text)
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 doc = await getDoc(data);
327
- if (doc) {
328
- let value = doc.get('text')
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 doc = await getDoc(data);
354
- if (doc) {
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 doc = await getDoc(data);
382
- if (doc) {
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 docName = getDocName(data);
428
- let doc = docs.get(docName);
429
- let changeLog = doc.get('changeLog');
430
- 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;
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 docName = getDocName(data);
452
- let doc = docs.get(docName);
453
- let redoLog = doc.get('redoLog')
454
- 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());
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 docName = getDocName(data);
476
- let doc = docs.get(docName);
477
- let changeLog = doc.get('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
- // function deleteDoc(docName) {
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
- // function destroyObserver(docName, typeName) {
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 };