@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.
- package/README.md +36 -12
- package/dist/src/index.d.ts +24 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/structs/AbstractStruct.d.ts +14 -17
- package/dist/src/structs/AbstractStruct.d.ts.map +1 -1
- package/dist/src/structs/GC.d.ts +9 -14
- package/dist/src/structs/GC.d.ts.map +1 -1
- package/dist/src/structs/Item.d.ts +569 -31
- package/dist/src/structs/Item.d.ts.map +1 -1
- package/dist/src/structs/Skip.d.ts +9 -11
- package/dist/src/structs/Skip.d.ts.map +1 -1
- package/dist/src/utils/BlockSet.d.ts +8 -7
- package/dist/src/utils/BlockSet.d.ts.map +1 -1
- package/dist/src/utils/Doc.d.ts +4 -9
- package/dist/src/utils/Doc.d.ts.map +1 -1
- package/dist/src/utils/ID.d.ts +0 -1
- package/dist/src/utils/ID.d.ts.map +1 -1
- package/dist/src/utils/RelativePosition.d.ts +2 -5
- package/dist/src/utils/RelativePosition.d.ts.map +1 -1
- package/dist/src/utils/Renderer.d.ts +144 -0
- package/dist/src/utils/Renderer.d.ts.map +1 -0
- package/dist/src/utils/Snapshot.d.ts +7 -11
- package/dist/src/utils/Snapshot.d.ts.map +1 -1
- package/dist/src/utils/StructStore.d.ts +45 -23
- package/dist/src/utils/StructStore.d.ts.map +1 -1
- package/dist/src/utils/Transaction.d.ts +11 -21
- package/dist/src/utils/Transaction.d.ts.map +1 -1
- package/dist/src/utils/UndoManager.d.ts +13 -14
- package/dist/src/utils/UndoManager.d.ts.map +1 -1
- package/dist/src/utils/UpdateDecoder.d.ts +1 -1
- package/dist/src/utils/UpdateDecoder.d.ts.map +1 -1
- package/dist/src/utils/UpdateEncoder.d.ts +0 -1
- package/dist/src/utils/UpdateEncoder.d.ts.map +1 -1
- package/dist/src/utils/YEvent.d.ts +22 -26
- package/dist/src/utils/YEvent.d.ts.map +1 -1
- package/dist/src/utils/content-helper.d.ts +2 -0
- package/dist/src/utils/content-helper.d.ts.map +1 -0
- package/dist/src/utils/delta-helpers.d.ts +2 -3
- package/dist/src/utils/delta-helpers.d.ts.map +1 -1
- package/dist/src/utils/encoding-helpers.d.ts +6 -0
- package/dist/src/utils/encoding-helpers.d.ts.map +1 -0
- package/dist/src/utils/encoding.d.ts +16 -18
- package/dist/src/utils/encoding.d.ts.map +1 -1
- package/dist/src/utils/ids.d.ts +331 -0
- package/dist/src/utils/ids.d.ts.map +1 -0
- package/dist/src/utils/isParentOf.d.ts +1 -2
- package/dist/src/utils/isParentOf.d.ts.map +1 -1
- package/dist/src/utils/logging.d.ts +0 -1
- package/dist/src/utils/logging.d.ts.map +1 -1
- package/dist/src/utils/meta.d.ts +15 -64
- package/dist/src/utils/meta.d.ts.map +1 -1
- package/dist/src/utils/renderer-helpers.d.ts +99 -0
- package/dist/src/utils/renderer-helpers.d.ts.map +1 -0
- package/dist/src/utils/schemas.d.ts +3 -0
- package/dist/src/utils/schemas.d.ts.map +1 -0
- package/dist/src/utils/transaction-helpers.d.ts +18 -0
- package/dist/src/utils/transaction-helpers.d.ts.map +1 -0
- package/dist/src/utils/updates.d.ts +19 -25
- package/dist/src/utils/updates.d.ts.map +1 -1
- package/dist/src/ytype.d.ts +144 -41
- package/dist/src/ytype.d.ts.map +1 -1
- package/global.d.ts +53 -0
- package/package.json +12 -16
- package/src/index.js +32 -124
- package/src/structs/AbstractStruct.js +21 -16
- package/src/structs/GC.js +15 -20
- package/src/structs/Item.js +992 -318
- package/src/structs/Skip.js +16 -19
- package/src/utils/BlockSet.js +20 -20
- package/src/utils/Doc.js +18 -29
- package/src/utils/ID.js +0 -2
- package/src/utils/RelativePosition.js +15 -25
- package/src/utils/{AttributionManager.js → Renderer.js} +42 -197
- package/src/utils/Snapshot.js +15 -37
- package/src/utils/StructStore.js +89 -227
- package/src/utils/Transaction.js +89 -321
- package/src/utils/UndoManager.js +157 -19
- package/src/utils/UpdateDecoder.js +2 -3
- package/src/utils/UpdateEncoder.js +0 -4
- package/src/utils/YEvent.js +20 -26
- package/src/utils/content-helper.js +0 -0
- package/src/utils/delta-helpers.js +21 -42
- package/src/utils/encoding-helpers.js +110 -0
- package/src/utils/encoding.js +197 -122
- package/src/utils/ids.js +1527 -0
- package/src/utils/isParentOf.js +2 -4
- package/src/utils/logging.js +0 -4
- package/src/utils/meta.js +57 -46
- package/src/utils/renderer-helpers.js +110 -0
- package/src/utils/schemas.js +3 -0
- package/src/utils/transaction-helpers.js +413 -0
- package/src/utils/updates.js +24 -146
- package/src/ytype.js +626 -255
- package/tests/testHelper.js +10 -12
- package/dist/src/internals.d.ts +0 -36
- package/dist/src/internals.d.ts.map +0 -1
- package/dist/src/structs/ContentAny.d.ts +0 -67
- package/dist/src/structs/ContentAny.d.ts.map +0 -1
- package/dist/src/structs/ContentBinary.d.ts +0 -64
- package/dist/src/structs/ContentBinary.d.ts.map +0 -1
- package/dist/src/structs/ContentDeleted.d.ts +0 -64
- package/dist/src/structs/ContentDeleted.d.ts.map +0 -1
- package/dist/src/structs/ContentDoc.d.ts +0 -72
- package/dist/src/structs/ContentDoc.d.ts.map +0 -1
- package/dist/src/structs/ContentEmbed.d.ts +0 -67
- package/dist/src/structs/ContentEmbed.d.ts.map +0 -1
- package/dist/src/structs/ContentFormat.d.ts +0 -69
- package/dist/src/structs/ContentFormat.d.ts.map +0 -1
- package/dist/src/structs/ContentJSON.d.ts +0 -70
- package/dist/src/structs/ContentJSON.d.ts.map +0 -1
- package/dist/src/structs/ContentString.d.ts +0 -70
- package/dist/src/structs/ContentString.d.ts.map +0 -1
- package/dist/src/structs/ContentType.d.ts +0 -77
- package/dist/src/structs/ContentType.d.ts.map +0 -1
- package/dist/src/utils/AttributionManager.d.ts +0 -238
- package/dist/src/utils/AttributionManager.d.ts.map +0 -1
- package/dist/src/utils/IdMap.d.ts +0 -164
- package/dist/src/utils/IdMap.d.ts.map +0 -1
- package/dist/src/utils/IdSet.d.ts +0 -163
- package/dist/src/utils/IdSet.d.ts.map +0 -1
- package/dist/tests/IdMap.tests.d.ts +0 -9
- package/dist/tests/IdMap.tests.d.ts.map +0 -1
- package/dist/tests/IdSet.tests.d.ts +0 -9
- package/dist/tests/IdSet.tests.d.ts.map +0 -1
- package/dist/tests/attribution.tests.d.ts +0 -9
- package/dist/tests/attribution.tests.d.ts.map +0 -1
- package/dist/tests/compatibility.tests.d.ts +0 -5
- package/dist/tests/compatibility.tests.d.ts.map +0 -1
- package/dist/tests/delta.tests.d.ts +0 -7
- package/dist/tests/delta.tests.d.ts.map +0 -1
- package/dist/tests/doc.tests.d.ts +0 -13
- package/dist/tests/doc.tests.d.ts.map +0 -1
- package/dist/tests/encoding.tests.d.ts +0 -5
- package/dist/tests/encoding.tests.d.ts.map +0 -1
- package/dist/tests/index.d.ts +0 -2
- package/dist/tests/index.d.ts.map +0 -1
- package/dist/tests/relativePositions.tests.d.ts +0 -11
- package/dist/tests/relativePositions.tests.d.ts.map +0 -1
- package/dist/tests/snapshot.tests.d.ts +0 -14
- package/dist/tests/snapshot.tests.d.ts.map +0 -1
- package/dist/tests/testHelper.d.ts +0 -171
- package/dist/tests/testHelper.d.ts.map +0 -1
- package/dist/tests/undo-redo.tests.d.ts +0 -27
- package/dist/tests/undo-redo.tests.d.ts.map +0 -1
- package/dist/tests/updates.tests.d.ts +0 -26
- package/dist/tests/updates.tests.d.ts.map +0 -1
- package/dist/tests/y-array.tests.d.ts +0 -43
- package/dist/tests/y-array.tests.d.ts.map +0 -1
- package/dist/tests/y-map.tests.d.ts +0 -42
- package/dist/tests/y-map.tests.d.ts.map +0 -1
- package/dist/tests/y-text.tests.d.ts +0 -49
- package/dist/tests/y-text.tests.d.ts.map +0 -1
- package/dist/tests/y-xml.tests.d.ts +0 -14
- package/dist/tests/y-xml.tests.d.ts.map +0 -1
- package/src/internals.js +0 -35
- package/src/structs/ContentAny.js +0 -115
- package/src/structs/ContentBinary.js +0 -93
- package/src/structs/ContentDeleted.js +0 -101
- package/src/structs/ContentDoc.js +0 -141
- package/src/structs/ContentEmbed.js +0 -98
- package/src/structs/ContentFormat.js +0 -105
- package/src/structs/ContentJSON.js +0 -119
- package/src/structs/ContentString.js +0 -113
- package/src/structs/ContentType.js +0 -152
- package/src/utils/IdMap.js +0 -673
- package/src/utils/IdSet.js +0 -825
package/src/utils/encoding.js
CHANGED
|
@@ -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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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 (
|
|
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, () =>
|
|
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 =
|
|
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),
|
|
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(
|
|
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 <
|
|
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
|
+
}
|