@y/y 14.0.0-rc.2 → 14.0.0-rc.21

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 (166) hide show
  1. package/README.md +36 -12
  2. package/dist/src/index.d.ts +24 -1
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/structs/AbstractStruct.d.ts +14 -17
  5. package/dist/src/structs/AbstractStruct.d.ts.map +1 -1
  6. package/dist/src/structs/GC.d.ts +9 -14
  7. package/dist/src/structs/GC.d.ts.map +1 -1
  8. package/dist/src/structs/Item.d.ts +569 -31
  9. package/dist/src/structs/Item.d.ts.map +1 -1
  10. package/dist/src/structs/Skip.d.ts +9 -11
  11. package/dist/src/structs/Skip.d.ts.map +1 -1
  12. package/dist/src/utils/BlockSet.d.ts +8 -7
  13. package/dist/src/utils/BlockSet.d.ts.map +1 -1
  14. package/dist/src/utils/Doc.d.ts +4 -9
  15. package/dist/src/utils/Doc.d.ts.map +1 -1
  16. package/dist/src/utils/ID.d.ts +0 -1
  17. package/dist/src/utils/ID.d.ts.map +1 -1
  18. package/dist/src/utils/RelativePosition.d.ts +2 -5
  19. package/dist/src/utils/RelativePosition.d.ts.map +1 -1
  20. package/dist/src/utils/Renderer.d.ts +144 -0
  21. package/dist/src/utils/Renderer.d.ts.map +1 -0
  22. package/dist/src/utils/Snapshot.d.ts +7 -11
  23. package/dist/src/utils/Snapshot.d.ts.map +1 -1
  24. package/dist/src/utils/StructStore.d.ts +45 -23
  25. package/dist/src/utils/StructStore.d.ts.map +1 -1
  26. package/dist/src/utils/Transaction.d.ts +11 -21
  27. package/dist/src/utils/Transaction.d.ts.map +1 -1
  28. package/dist/src/utils/UndoManager.d.ts +13 -14
  29. package/dist/src/utils/UndoManager.d.ts.map +1 -1
  30. package/dist/src/utils/UpdateDecoder.d.ts +1 -1
  31. package/dist/src/utils/UpdateDecoder.d.ts.map +1 -1
  32. package/dist/src/utils/UpdateEncoder.d.ts +0 -1
  33. package/dist/src/utils/UpdateEncoder.d.ts.map +1 -1
  34. package/dist/src/utils/YEvent.d.ts +22 -26
  35. package/dist/src/utils/YEvent.d.ts.map +1 -1
  36. package/dist/src/utils/content-helper.d.ts +2 -0
  37. package/dist/src/utils/content-helper.d.ts.map +1 -0
  38. package/dist/src/utils/delta-helpers.d.ts +2 -3
  39. package/dist/src/utils/delta-helpers.d.ts.map +1 -1
  40. package/dist/src/utils/encoding-helpers.d.ts +6 -0
  41. package/dist/src/utils/encoding-helpers.d.ts.map +1 -0
  42. package/dist/src/utils/encoding.d.ts +16 -18
  43. package/dist/src/utils/encoding.d.ts.map +1 -1
  44. package/dist/src/utils/ids.d.ts +331 -0
  45. package/dist/src/utils/ids.d.ts.map +1 -0
  46. package/dist/src/utils/isParentOf.d.ts +1 -2
  47. package/dist/src/utils/isParentOf.d.ts.map +1 -1
  48. package/dist/src/utils/logging.d.ts +0 -1
  49. package/dist/src/utils/logging.d.ts.map +1 -1
  50. package/dist/src/utils/meta.d.ts +15 -64
  51. package/dist/src/utils/meta.d.ts.map +1 -1
  52. package/dist/src/utils/renderer-helpers.d.ts +99 -0
  53. package/dist/src/utils/renderer-helpers.d.ts.map +1 -0
  54. package/dist/src/utils/schemas.d.ts +3 -0
  55. package/dist/src/utils/schemas.d.ts.map +1 -0
  56. package/dist/src/utils/transaction-helpers.d.ts +18 -0
  57. package/dist/src/utils/transaction-helpers.d.ts.map +1 -0
  58. package/dist/src/utils/updates.d.ts +19 -25
  59. package/dist/src/utils/updates.d.ts.map +1 -1
  60. package/dist/src/ytype.d.ts +144 -41
  61. package/dist/src/ytype.d.ts.map +1 -1
  62. package/global.d.ts +53 -0
  63. package/package.json +12 -16
  64. package/src/index.js +32 -124
  65. package/src/structs/AbstractStruct.js +21 -16
  66. package/src/structs/GC.js +15 -20
  67. package/src/structs/Item.js +992 -318
  68. package/src/structs/Skip.js +16 -19
  69. package/src/utils/BlockSet.js +20 -20
  70. package/src/utils/Doc.js +18 -29
  71. package/src/utils/ID.js +0 -2
  72. package/src/utils/RelativePosition.js +15 -25
  73. package/src/utils/{AttributionManager.js → Renderer.js} +42 -197
  74. package/src/utils/Snapshot.js +15 -37
  75. package/src/utils/StructStore.js +89 -227
  76. package/src/utils/Transaction.js +89 -321
  77. package/src/utils/UndoManager.js +157 -19
  78. package/src/utils/UpdateDecoder.js +2 -3
  79. package/src/utils/UpdateEncoder.js +0 -4
  80. package/src/utils/YEvent.js +20 -26
  81. package/src/utils/content-helper.js +0 -0
  82. package/src/utils/delta-helpers.js +21 -42
  83. package/src/utils/encoding-helpers.js +110 -0
  84. package/src/utils/encoding.js +197 -122
  85. package/src/utils/ids.js +1527 -0
  86. package/src/utils/isParentOf.js +2 -4
  87. package/src/utils/logging.js +0 -4
  88. package/src/utils/meta.js +57 -46
  89. package/src/utils/renderer-helpers.js +110 -0
  90. package/src/utils/schemas.js +3 -0
  91. package/src/utils/transaction-helpers.js +413 -0
  92. package/src/utils/updates.js +24 -146
  93. package/src/ytype.js +626 -255
  94. package/tests/testHelper.js +10 -12
  95. package/dist/src/internals.d.ts +0 -36
  96. package/dist/src/internals.d.ts.map +0 -1
  97. package/dist/src/structs/ContentAny.d.ts +0 -67
  98. package/dist/src/structs/ContentAny.d.ts.map +0 -1
  99. package/dist/src/structs/ContentBinary.d.ts +0 -64
  100. package/dist/src/structs/ContentBinary.d.ts.map +0 -1
  101. package/dist/src/structs/ContentDeleted.d.ts +0 -64
  102. package/dist/src/structs/ContentDeleted.d.ts.map +0 -1
  103. package/dist/src/structs/ContentDoc.d.ts +0 -72
  104. package/dist/src/structs/ContentDoc.d.ts.map +0 -1
  105. package/dist/src/structs/ContentEmbed.d.ts +0 -67
  106. package/dist/src/structs/ContentEmbed.d.ts.map +0 -1
  107. package/dist/src/structs/ContentFormat.d.ts +0 -69
  108. package/dist/src/structs/ContentFormat.d.ts.map +0 -1
  109. package/dist/src/structs/ContentJSON.d.ts +0 -70
  110. package/dist/src/structs/ContentJSON.d.ts.map +0 -1
  111. package/dist/src/structs/ContentString.d.ts +0 -70
  112. package/dist/src/structs/ContentString.d.ts.map +0 -1
  113. package/dist/src/structs/ContentType.d.ts +0 -77
  114. package/dist/src/structs/ContentType.d.ts.map +0 -1
  115. package/dist/src/utils/AttributionManager.d.ts +0 -238
  116. package/dist/src/utils/AttributionManager.d.ts.map +0 -1
  117. package/dist/src/utils/IdMap.d.ts +0 -164
  118. package/dist/src/utils/IdMap.d.ts.map +0 -1
  119. package/dist/src/utils/IdSet.d.ts +0 -163
  120. package/dist/src/utils/IdSet.d.ts.map +0 -1
  121. package/dist/tests/IdMap.tests.d.ts +0 -9
  122. package/dist/tests/IdMap.tests.d.ts.map +0 -1
  123. package/dist/tests/IdSet.tests.d.ts +0 -9
  124. package/dist/tests/IdSet.tests.d.ts.map +0 -1
  125. package/dist/tests/attribution.tests.d.ts +0 -9
  126. package/dist/tests/attribution.tests.d.ts.map +0 -1
  127. package/dist/tests/compatibility.tests.d.ts +0 -5
  128. package/dist/tests/compatibility.tests.d.ts.map +0 -1
  129. package/dist/tests/delta.tests.d.ts +0 -7
  130. package/dist/tests/delta.tests.d.ts.map +0 -1
  131. package/dist/tests/doc.tests.d.ts +0 -13
  132. package/dist/tests/doc.tests.d.ts.map +0 -1
  133. package/dist/tests/encoding.tests.d.ts +0 -5
  134. package/dist/tests/encoding.tests.d.ts.map +0 -1
  135. package/dist/tests/index.d.ts +0 -2
  136. package/dist/tests/index.d.ts.map +0 -1
  137. package/dist/tests/relativePositions.tests.d.ts +0 -11
  138. package/dist/tests/relativePositions.tests.d.ts.map +0 -1
  139. package/dist/tests/snapshot.tests.d.ts +0 -14
  140. package/dist/tests/snapshot.tests.d.ts.map +0 -1
  141. package/dist/tests/testHelper.d.ts +0 -171
  142. package/dist/tests/testHelper.d.ts.map +0 -1
  143. package/dist/tests/undo-redo.tests.d.ts +0 -27
  144. package/dist/tests/undo-redo.tests.d.ts.map +0 -1
  145. package/dist/tests/updates.tests.d.ts +0 -26
  146. package/dist/tests/updates.tests.d.ts.map +0 -1
  147. package/dist/tests/y-array.tests.d.ts +0 -43
  148. package/dist/tests/y-array.tests.d.ts.map +0 -1
  149. package/dist/tests/y-map.tests.d.ts +0 -42
  150. package/dist/tests/y-map.tests.d.ts.map +0 -1
  151. package/dist/tests/y-text.tests.d.ts +0 -49
  152. package/dist/tests/y-text.tests.d.ts.map +0 -1
  153. package/dist/tests/y-xml.tests.d.ts +0 -14
  154. package/dist/tests/y-xml.tests.d.ts.map +0 -1
  155. package/src/internals.js +0 -35
  156. package/src/structs/ContentAny.js +0 -115
  157. package/src/structs/ContentBinary.js +0 -93
  158. package/src/structs/ContentDeleted.js +0 -101
  159. package/src/structs/ContentDoc.js +0 -141
  160. package/src/structs/ContentEmbed.js +0 -98
  161. package/src/structs/ContentFormat.js +0 -105
  162. package/src/structs/ContentJSON.js +0 -119
  163. package/src/structs/ContentString.js +0 -113
  164. package/src/structs/ContentType.js +0 -152
  165. package/src/utils/IdMap.js +0 -673
  166. package/src/utils/IdSet.js +0 -825
@@ -14,94 +14,25 @@
14
14
  * 7: Item with Type
15
15
  */
16
16
 
17
- import {
18
- findIndexSS,
19
- getState,
20
- getStateVector,
21
- readAndApplyDeleteSet,
22
- writeIdSet,
23
- transact,
24
- UpdateDecoderV1,
25
- UpdateDecoderV2,
26
- UpdateEncoderV1,
27
- UpdateEncoderV2,
28
- IdSetEncoderV2,
29
- IdSetDecoderV1,
30
- IdSetEncoderV1,
31
- mergeUpdates,
32
- mergeUpdatesV2,
33
- Skip,
34
- diffUpdateV2,
35
- convertUpdateFormatV2ToV1,
36
- readBlockSet,
37
- createIdSet,
38
- BlockSet, IdSet, IdSetDecoderV2, Doc, Transaction, GC, Item, StructStore, // eslint-disable-line
39
- createID,
40
- IdRange
41
- } from '../internals.js'
42
-
43
17
  import * as encoding from 'lib0/encoding'
44
18
  import * as decoding from 'lib0/decoding'
45
19
  import * as map from 'lib0/map'
46
20
  import * as math from 'lib0/math'
47
21
  import * as array from 'lib0/array'
48
22
 
49
- /**
50
- * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
51
- * @param {Array<GC|Item>} structs All structs by `client`
52
- * @param {number} client
53
- * @param {Array<IdRange>} idranges
54
- *
55
- * @function
56
- */
57
- export const writeStructs = (encoder, structs, client, idranges) => {
58
- let structsToWrite = 0 // this accounts for the skips
59
- /**
60
- * @type {Array<{ start: number, end: number, startClock: number, endClock: number }>}
61
- */
62
- const indexRanges = []
63
- const firstPossibleClock = structs[0].id.clock
64
- const lastStruct = array.last(structs)
65
- const lastPossibleClock = lastStruct.id.clock + lastStruct.length
66
- idranges.forEach(idrange => {
67
- const startClock = math.max(idrange.clock, firstPossibleClock)
68
- const endClock = math.min(idrange.clock + idrange.len, lastPossibleClock)
69
- if (startClock >= endClock) return // structs for this range do not exist
70
- // inclusive start
71
- const start = findIndexSS(structs, startClock)
72
- // exclusive end
73
- const end = findIndexSS(structs, endClock - 1) + 1
74
- structsToWrite += end - start
75
- indexRanges.push({
76
- start,
77
- end,
78
- startClock,
79
- endClock
80
- })
81
- })
82
- structsToWrite += idranges.length - 1
83
- // start writing with this clock. this is updated to the next clock that we expect to write
84
- let clock = indexRanges[0].startClock
85
- // write # encoded structs
86
- encoding.writeVarUint(encoder.restEncoder, structsToWrite)
87
- encoder.writeClient(client)
88
- // write clock
89
- encoding.writeVarUint(encoder.restEncoder, clock)
90
- indexRanges.forEach(indexRange => {
91
- const skipLen = indexRange.startClock - clock
92
- if (skipLen > 0) {
93
- new Skip(createID(client, clock), skipLen).write(encoder, 0)
94
- clock += skipLen
95
- }
96
- for (let i = indexRange.start; i < indexRange.end; i++) {
97
- const struct = structs[i]
98
- const structEnd = struct.id.clock + struct.length
99
- const offsetEnd = math.max(structEnd - indexRange.endClock, 0)
100
- struct.write(encoder, clock - struct.id.clock, offsetEnd)
101
- clock = structEnd - offsetEnd
102
- }
103
- })
104
- }
23
+ import { getStateVector, StructStore } from './StructStore.js'
24
+ import { getItemCleanStart, getItemCleanEnd } from './transaction-helpers.js'
25
+ import { createIdSet, IdRange, readAndApplyDeleteSet, readIdSet, mergeIdSets, writeIdSet } from './ids.js'
26
+ import { createID, ID } from './ID.js'
27
+ import { UpdateDecoderV1, UpdateDecoderV2, IdSetDecoderV1 } from './UpdateDecoder.js'
28
+ import { UpdateEncoderV1, UpdateEncoderV2, IdSetEncoderV1, IdSetEncoderV2 } from './UpdateEncoder.js'
29
+ import { convertUpdateFormatV2ToV1, LazyStructReader, LazyStructWriter, writeStructToLazyStructWriter, finishLazyStructWriting } from './updates.js'
30
+ import { readBlockSet, writeBlockSet } from './BlockSet.js'
31
+ import { Skip } from '../structs/Skip.js'
32
+ import { Item } from '../structs/Item.js'
33
+ import { GC } from '../structs/GC.js'
34
+ import { Doc } from './Doc.js'
35
+ import { writeStructs } from './encoding-helpers.js'
105
36
 
106
37
  /**
107
38
  * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
@@ -116,7 +47,7 @@ export const writeClientsStructs = (encoder, store, _sm) => {
116
47
  const sm = new Map()
117
48
  _sm.forEach((clock, client) => {
118
49
  // only write if new structs are available
119
- if (getState(store, client) > clock) {
50
+ if (store.getClock(client) > clock) {
120
51
  sm.set(client, clock)
121
52
  }
122
53
  })
@@ -136,28 +67,6 @@ export const writeClientsStructs = (encoder, store, _sm) => {
136
67
  })
137
68
  }
138
69
 
139
- /**
140
- * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
141
- * @param {StructStore} store
142
- * @param {IdSet} idset
143
- *
144
- * @todo at the moment this writes the full deleteset range
145
- *
146
- * @private
147
- * @function
148
- */
149
- export const writeStructsFromIdSet = (encoder, store, idset) => {
150
- // write # states that were updated
151
- encoding.writeVarUint(encoder.restEncoder, idset.clients.size)
152
- // Write items with higher client ids first
153
- // This heavily improves the conflict algorithm.
154
- array.from(idset.clients.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, ids]) => {
155
- const idRanges = ids.getIds()
156
- const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
157
- writeStructs(encoder, structs, client, idRanges)
158
- })
159
- }
160
-
161
70
  /**
162
71
  * Resume computing structs generated by struct readers.
163
72
  *
@@ -187,7 +96,7 @@ export const writeStructsFromIdSet = (encoder, store, idset) => {
187
96
  */
188
97
  const integrateStructs = (transaction, store, clientsStructRefs) => {
189
98
  /**
190
- * @type {Array<Item | GC>}
99
+ * @type {Array<Item | GC | Skip>}
191
100
  */
192
101
  const stack = []
193
102
  // sort them so that we take the higher id first, in case of conflicts the lower id will probably not conflict with the id from the higher user.
@@ -231,7 +140,7 @@ const integrateStructs = (transaction, store, clientsStructRefs) => {
231
140
  }
232
141
  }
233
142
  /**
234
- * @type {GC|Item}
143
+ * @type {GC|Item|Skip}
235
144
  */
236
145
  let stackHead = /** @type {any} */ (curStructsTarget).refs[/** @type {any} */ (curStructsTarget).i++]
237
146
  // caching the state because it is used very often
@@ -267,19 +176,19 @@ const integrateStructs = (transaction, store, clientsStructRefs) => {
267
176
  // iterate over all struct readers until we are done
268
177
  while (true) {
269
178
  if (stackHead.constructor !== Skip) {
270
- const localClock = map.setIfUndefined(state, stackHead.id.client, () => getState(store, stackHead.id.client))
179
+ const localClock = map.setIfUndefined(state, stackHead.id.client, () => store.getClock(stackHead.id.client))
271
180
  const offset = localClock - stackHead.id.clock
272
- const missing = stackHead.getMissing(transaction, store)
181
+ const missing = getMissing(/** @type {any} */ (stackHead), transaction, store)
273
182
  if (missing !== null) {
274
183
  stack.push(stackHead)
275
184
  // get the struct reader that has the missing struct
276
185
  /**
277
- * @type {{ refs: Array<GC|Item>, i: number }}
186
+ * @type {{ refs: Array<GC|Item|Skip>, i: number }}
278
187
  */
279
188
  const structRefs = clientsStructRefs.clients.get(/** @type {number} */ (missing)) || { refs: [], i: 0 }
280
189
  if (structRefs.refs.length === structRefs.i || missing === stackHead.id.client || stack.some(s => s.id.client === missing)) { // @todo this could be optimized!
281
190
  // This update message causally depends on another update message that doesn't exist yet
282
- updateMissingSv(/** @type {number} */ (missing), getState(store, missing))
191
+ updateMissingSv(/** @type {number} */ (missing), store.getClock(missing))
283
192
  addStackToRestSS()
284
193
  } else {
285
194
  stackHead = structRefs.refs[structRefs.i++]
@@ -322,15 +231,6 @@ const integrateStructs = (transaction, store, clientsStructRefs) => {
322
231
  return null
323
232
  }
324
233
 
325
- /**
326
- * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
327
- * @param {Transaction} transaction
328
- *
329
- * @private
330
- * @function
331
- */
332
- export const writeStructsFromTransaction = (encoder, transaction) => writeStructsFromIdSet(encoder, transaction.doc.store, transaction.insertSet)
333
-
334
234
  /**
335
235
  * Read and apply a document update.
336
236
  *
@@ -344,7 +244,7 @@ export const writeStructsFromTransaction = (encoder, transaction) => writeStruct
344
244
  * @function
345
245
  */
346
246
  export const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = new UpdateDecoderV2(decoder)) =>
347
- transact(ydoc, transaction => {
247
+ ydoc.transact(transaction => {
348
248
  // force that transaction.local is set to non-local
349
249
  transaction.local = false
350
250
  let retry = false
@@ -375,7 +275,7 @@ export const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = n
375
275
  if (pending) {
376
276
  // check if we can apply something
377
277
  for (const [client, clock] of pending.missing) {
378
- if (ss.clients.has(client) || clock < getState(store, client)) {
278
+ if (ss.clients.has(client) || clock < store.getClock(client)) {
379
279
  retry = true
380
280
  break
381
281
  }
@@ -551,6 +451,94 @@ export const readStateVector = decoder => {
551
451
  return ss
552
452
  }
553
453
 
454
+ /**
455
+ *
456
+ * This function works similarly to `readUpdateV2`.
457
+ *
458
+ * @param {Array<Uint8Array<ArrayBuffer>>} updates
459
+ * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
460
+ * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
461
+ * @return {Uint8Array<ArrayBuffer>}
462
+ */
463
+ export const mergeUpdatesV2 = (updates, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
464
+ if (updates.length === 1) {
465
+ return updates[0]
466
+ } else if (updates.length === 0) {
467
+ return encodeStateAsUpdateV2(new Doc(), new Uint8Array([0]), new YEncoder())
468
+ }
469
+ const updateDecoders = updates.map(update => new YDecoder(decoding.createDecoder(update)))
470
+ const blocksets = updateDecoders.map(dec => readBlockSet(dec))
471
+
472
+ const mergedBlockset = blocksets[0]
473
+ for (let i = 1; i < blocksets.length; i++) {
474
+ mergedBlockset.insertInto(blocksets[i])
475
+ }
476
+ const updateEncoder = new YEncoder()
477
+ writeBlockSet(updateEncoder, mergedBlockset)
478
+ const dss = updateDecoders.map(decoder => readIdSet(decoder))
479
+ const ds = mergeIdSets(dss)
480
+ writeIdSet(updateEncoder, ds)
481
+ return updateEncoder.toUint8Array()
482
+ }
483
+
484
+ /**
485
+ * @param {Array<Uint8Array<ArrayBuffer>>} updates
486
+ * @return {Uint8Array<ArrayBuffer>}
487
+ */
488
+ export const mergeUpdates = updates => mergeUpdatesV2(updates, UpdateDecoderV1, UpdateEncoderV1)
489
+
490
+ /**
491
+ * @deprecated
492
+ * @param {Uint8Array} update
493
+ * @param {Uint8Array} sv
494
+ * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
495
+ * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
496
+ */
497
+ export const diffUpdateV2 = (update, sv, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
498
+ const state = decodeStateVector(sv)
499
+ const encoder = new YEncoder()
500
+ const lazyStructWriter = new LazyStructWriter(encoder)
501
+ const decoder = new YDecoder(decoding.createDecoder(update))
502
+ const reader = new LazyStructReader(decoder, false)
503
+ while (reader.curr) {
504
+ const curr = reader.curr
505
+ const currClient = curr.id.client
506
+ const svClock = state.get(currClient) || 0
507
+ if (reader.curr.constructor === Skip) {
508
+ // the first written struct shouldn't be a skip
509
+ reader.next()
510
+ continue
511
+ }
512
+ if (curr.id.clock + curr.length > svClock) {
513
+ writeStructToLazyStructWriter(lazyStructWriter, curr, math.max(svClock - curr.id.clock, 0), 0)
514
+ reader.next()
515
+ while (reader.curr && reader.curr.id.client === currClient) {
516
+ writeStructToLazyStructWriter(lazyStructWriter, reader.curr, 0, 0)
517
+ reader.next()
518
+ }
519
+ } else {
520
+ // read until something new comes up
521
+ while (reader.curr && reader.curr.id.client === currClient && reader.curr.id.clock + reader.curr.length <= svClock) {
522
+ reader.next()
523
+ }
524
+ }
525
+ }
526
+ finishLazyStructWriting(lazyStructWriter)
527
+ // write ds
528
+ const ds = readIdSet(decoder)
529
+ writeIdSet(encoder, ds)
530
+ return encoder.toUint8Array()
531
+ }
532
+
533
+ /**
534
+ * @deprecated
535
+ * @todo remove this in favor of intersectupdate
536
+ *
537
+ * @param {Uint8Array<ArrayBuffer>} update
538
+ * @param {Uint8Array<ArrayBuffer>} sv
539
+ */
540
+ export const diffUpdate = (update, sv) => diffUpdateV2(update, sv, UpdateDecoderV1, UpdateEncoderV1)
541
+
554
542
  /**
555
543
  * Read decodedState and return State as Map.
556
544
  *
@@ -620,3 +608,90 @@ export const encodeStateVectorV2 = (doc, encoder = new IdSetEncoderV2()) => {
620
608
  * @function
621
609
  */
622
610
  export const encodeStateVector = doc => encodeStateVectorV2(doc, new IdSetEncoderV1())
611
+
612
+ /**
613
+ * Return the creator clientID of the missing op or define missing items and return null.
614
+ *
615
+ * @param {Item} struct
616
+ * @param {Transaction} transaction
617
+ * @param {StructStore} store
618
+ * @return {null | number}
619
+ */
620
+ const getMissing = (struct, transaction, store) => {
621
+ if (struct.constructor !== Item) return null
622
+ // we may not access these variables anymore after they have been written!
623
+ const origin = struct.origin
624
+ const rightOrigin = struct.rightOrigin
625
+ const parent = struct.parent
626
+ if (origin && (origin.clock >= store.getClock(origin.client) || store.skips.hasId(origin))) {
627
+ return origin.client
628
+ }
629
+ if (rightOrigin && (rightOrigin.clock >= store.getClock(rightOrigin.client) || store.skips.hasId(rightOrigin))) {
630
+ return rightOrigin.client
631
+ }
632
+ if (parent && parent.constructor === ID && (parent.clock >= store.getClock(parent.client) || store.skips.hasId(parent))) {
633
+ return parent.client
634
+ }
635
+ // We have all missing ids, now find the items
636
+ if (origin) {
637
+ struct.left = getItemCleanEnd(transaction, store, origin)
638
+ // copy left id to so that the original id can be gc'd
639
+ struct.origin = struct.left.lastId
640
+ }
641
+ if (rightOrigin) {
642
+ struct.right = getItemCleanStart(transaction, rightOrigin)
643
+ struct.rightOrigin = struct.right.id
644
+ }
645
+ if ((struct.left && struct.left.constructor === GC) || (struct.right && struct.right.constructor === GC)) {
646
+ struct.parent = null
647
+ } else if (parent == null) {
648
+ // only set parent if this shouldn't be garbage collected
649
+ if (struct.left && struct.left.constructor === Item) {
650
+ struct.parent = struct.left.parent
651
+ struct.parentSub = struct.left.parentSub
652
+ } else if (struct.right && struct.right.constructor === Item) {
653
+ struct.parent = struct.right.parent
654
+ struct.parentSub = struct.right.parentSub
655
+ }
656
+ } else if (parent.constructor === ID) {
657
+ const parentItem = store.getItem(parent)
658
+ if (parentItem.constructor === GC) {
659
+ struct.parent = null
660
+ } else {
661
+ struct.parent = /** @type {ContentType} */ (parentItem.content).type
662
+ }
663
+ } else if (typeof parent === 'string') {
664
+ struct.parent = transaction.doc.get(parent)
665
+ }
666
+ return null
667
+ }
668
+
669
+ /**
670
+ * @param {Uint8Array} update
671
+ * @param {import('./Doc.js').DocOpts} opts
672
+ */
673
+ export const createDocFromUpdate = (update, opts = {}) => {
674
+ const ydoc = new Doc(opts)
675
+ applyUpdate(ydoc, update)
676
+ return ydoc
677
+ }
678
+
679
+ /**
680
+ * @param {Uint8Array} update
681
+ * @param {import('./Doc.js').DocOpts} opts
682
+ */
683
+ export const createDocFromUpdateV2 = (update, opts = {}) => {
684
+ const ydoc = new Doc(opts)
685
+ applyUpdateV2(ydoc, update)
686
+ return ydoc
687
+ }
688
+
689
+ /**
690
+ * @param {Doc} ydoc
691
+ * @param {import('./Doc.js').DocOpts} [opts]
692
+ */
693
+ export const cloneDoc = (ydoc, opts) => {
694
+ const clone = new Doc(opts)
695
+ applyUpdate(clone, encodeStateAsUpdate(ydoc))
696
+ return clone
697
+ }