@y/y 14.0.0-16 → 14.0.0-17

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 (68) hide show
  1. package/dist/{index-DyTeTfmj.js → index-BV-j5wdP.js} +2 -2
  2. package/dist/{index-R7GxO-36.js.map → index-BV-j5wdP.js.map} +1 -1
  3. package/dist/{internals.mjs → internals.js} +1 -1
  4. package/dist/internals.js.map +1 -0
  5. package/dist/{testHelper.mjs → testHelper.js} +2 -2
  6. package/dist/testHelper.js.map +1 -0
  7. package/dist/{yjs.mjs → yjs.js} +2 -2
  8. package/dist/yjs.js.map +1 -0
  9. package/package.json +8 -17
  10. package/dist/Skip-j0kX7pdq.js +0 -12173
  11. package/dist/Skip-j0kX7pdq.js.map +0 -1
  12. package/dist/index-DyTeTfmj.js.map +0 -1
  13. package/dist/index-R7GxO-36.js +0 -165
  14. package/dist/internals.cjs +0 -286
  15. package/dist/internals.cjs.map +0 -1
  16. package/dist/internals.mjs.map +0 -1
  17. package/dist/testHelper.cjs +0 -780
  18. package/dist/testHelper.cjs.map +0 -1
  19. package/dist/testHelper.mjs.map +0 -1
  20. package/dist/yjs.cjs +0 -151
  21. package/dist/yjs.cjs.map +0 -1
  22. package/dist/yjs.mjs.map +0 -1
  23. package/src/index.js +0 -153
  24. package/src/internals.js +0 -44
  25. package/src/structs/AbstractStruct.js +0 -59
  26. package/src/structs/ContentAny.js +0 -115
  27. package/src/structs/ContentBinary.js +0 -93
  28. package/src/structs/ContentDeleted.js +0 -101
  29. package/src/structs/ContentDoc.js +0 -141
  30. package/src/structs/ContentEmbed.js +0 -98
  31. package/src/structs/ContentFormat.js +0 -105
  32. package/src/structs/ContentJSON.js +0 -119
  33. package/src/structs/ContentString.js +0 -113
  34. package/src/structs/ContentType.js +0 -176
  35. package/src/structs/GC.js +0 -80
  36. package/src/structs/Item.js +0 -845
  37. package/src/structs/Skip.js +0 -75
  38. package/src/types/AbstractType.js +0 -1434
  39. package/src/types/YArray.js +0 -270
  40. package/src/types/YMap.js +0 -244
  41. package/src/types/YText.js +0 -934
  42. package/src/types/YXmlElement.js +0 -227
  43. package/src/types/YXmlFragment.js +0 -266
  44. package/src/types/YXmlHook.js +0 -68
  45. package/src/types/YXmlText.js +0 -66
  46. package/src/utils/AbstractConnector.js +0 -25
  47. package/src/utils/AttributionManager.js +0 -619
  48. package/src/utils/Doc.js +0 -372
  49. package/src/utils/EventHandler.js +0 -87
  50. package/src/utils/ID.js +0 -89
  51. package/src/utils/IdMap.js +0 -629
  52. package/src/utils/IdSet.js +0 -823
  53. package/src/utils/RelativePosition.js +0 -352
  54. package/src/utils/Snapshot.js +0 -220
  55. package/src/utils/StructSet.js +0 -137
  56. package/src/utils/StructStore.js +0 -289
  57. package/src/utils/Transaction.js +0 -489
  58. package/src/utils/UndoManager.js +0 -391
  59. package/src/utils/UpdateDecoder.js +0 -281
  60. package/src/utils/UpdateEncoder.js +0 -320
  61. package/src/utils/YEvent.js +0 -216
  62. package/src/utils/delta-helpers.js +0 -54
  63. package/src/utils/encoding.js +0 -623
  64. package/src/utils/isParentOf.js +0 -21
  65. package/src/utils/logging.js +0 -21
  66. package/src/utils/types.js +0 -28
  67. package/src/utils/updates.js +0 -715
  68. package/tests/testHelper.js +0 -600
@@ -1,715 +0,0 @@
1
- import * as binary from 'lib0/binary'
2
- import * as decoding from 'lib0/decoding'
3
- import * as encoding from 'lib0/encoding'
4
- import * as error from 'lib0/error'
5
- import * as f from 'lib0/function'
6
- import * as logging from 'lib0/logging'
7
- import * as map from 'lib0/map'
8
- import * as math from 'lib0/math'
9
- import * as string from 'lib0/string'
10
-
11
- import {
12
- ContentAny,
13
- ContentBinary,
14
- ContentDeleted,
15
- ContentDoc,
16
- ContentEmbed,
17
- ContentFormat,
18
- ContentJSON,
19
- ContentString,
20
- ContentType,
21
- createID,
22
- decodeStateVector,
23
- IdSetEncoderV1,
24
- IdSetEncoderV2,
25
- GC,
26
- Item,
27
- mergeIdSets,
28
- readIdSet,
29
- readItemContent,
30
- Skip,
31
- UpdateDecoderV1,
32
- UpdateDecoderV2,
33
- UpdateEncoderV1,
34
- UpdateEncoderV2,
35
- writeIdSet,
36
- YXmlElement,
37
- YXmlHook,
38
- createIdSet
39
- } from '../internals.js'
40
-
41
- /**
42
- * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
43
- */
44
- function * lazyStructReaderGenerator (decoder) {
45
- const numOfStateUpdates = decoding.readVarUint(decoder.restDecoder)
46
- for (let i = 0; i < numOfStateUpdates; i++) {
47
- const numberOfStructs = decoding.readVarUint(decoder.restDecoder)
48
- const client = decoder.readClient()
49
- let clock = decoding.readVarUint(decoder.restDecoder)
50
- for (let i = 0; i < numberOfStructs; i++) {
51
- const info = decoder.readInfo()
52
- // @todo use switch instead of ifs
53
- if (info === 10) {
54
- const len = decoding.readVarUint(decoder.restDecoder)
55
- yield new Skip(createID(client, clock), len)
56
- clock += len
57
- } else if ((binary.BITS5 & info) !== 0) {
58
- const cantCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
59
- // If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
60
- // and we read the next string as parentYKey.
61
- // It indicates how we store/retrieve parent from `y.share`
62
- // @type {string|null}
63
- const struct = new Item(
64
- createID(client, clock),
65
- null, // left
66
- (info & binary.BIT8) === binary.BIT8 ? decoder.readLeftID() : null, // origin
67
- null, // right
68
- (info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null, // right origin
69
- // @ts-ignore Force writing a string here.
70
- cantCopyParentInfo ? (decoder.readParentInfo() ? decoder.readString() : decoder.readLeftID()) : null, // parent
71
- cantCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
72
- readItemContent(decoder, info) // item content
73
- )
74
- yield struct
75
- clock += struct.length
76
- } else {
77
- const len = decoder.readLen()
78
- yield new GC(createID(client, clock), len)
79
- clock += len
80
- }
81
- }
82
- }
83
- }
84
-
85
- export class LazyStructReader {
86
- /**
87
- * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
88
- * @param {boolean} filterSkips
89
- */
90
- constructor (decoder, filterSkips) {
91
- this.gen = lazyStructReaderGenerator(decoder)
92
- /**
93
- * @type {null | Item | Skip | GC}
94
- */
95
- this.curr = null
96
- this.done = false
97
- this.filterSkips = filterSkips
98
- this.next()
99
- }
100
-
101
- /**
102
- * @return {Item | GC | Skip |null}
103
- */
104
- next () {
105
- // ignore "Skip" structs
106
- do {
107
- this.curr = this.gen.next().value || null
108
- } while (this.filterSkips && this.curr !== null && this.curr.constructor === Skip)
109
- return this.curr
110
- }
111
- }
112
-
113
- /**
114
- * @param {Uint8Array} update
115
- *
116
- */
117
- export const logUpdate = update => logUpdateV2(update, UpdateDecoderV1)
118
-
119
- /**
120
- * @param {Uint8Array} update
121
- * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
122
- */
123
- export const logUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
124
- const structs = []
125
- const updateDecoder = new YDecoder(decoding.createDecoder(update))
126
- const lazyDecoder = new LazyStructReader(updateDecoder, false)
127
- for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
128
- structs.push(curr)
129
- }
130
- logging.print('Structs: ', structs)
131
- const ds = readIdSet(updateDecoder)
132
- logging.print('DeleteSet: ', ds)
133
- }
134
-
135
- /**
136
- * @param {Uint8Array} update
137
- *
138
- */
139
- export const decodeUpdate = (update) => decodeUpdateV2(update, UpdateDecoderV1)
140
-
141
- /**
142
- * @param {Uint8Array} update
143
- * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
144
- *
145
- */
146
- export const decodeUpdateV2 = (update, YDecoder = UpdateDecoderV2) => {
147
- const structs = []
148
- const updateDecoder = new YDecoder(decoding.createDecoder(update))
149
- const lazyDecoder = new LazyStructReader(updateDecoder, false)
150
- for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
151
- structs.push(curr)
152
- }
153
- return {
154
- structs,
155
- ds: readIdSet(updateDecoder)
156
- }
157
- }
158
-
159
- export class LazyStructWriter {
160
- /**
161
- * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
162
- */
163
- constructor (encoder) {
164
- this.currClient = 0
165
- this.startClock = 0
166
- this.written = 0
167
- this.encoder = encoder
168
- /**
169
- * We want to write operations lazily, but also we need to know beforehand how many operations we want to write for each client.
170
- *
171
- * This kind of meta-information (#clients, #structs-per-client-written) is written to the restEncoder.
172
- *
173
- * We fragment the restEncoder and store a slice of it per-client until we know how many clients there are.
174
- * When we flush (toUint8Array) we write the restEncoder using the fragments and the meta-information.
175
- *
176
- * @type {Array<{ written: number, restEncoder: Uint8Array }>}
177
- */
178
- this.clientStructs = []
179
- }
180
- }
181
-
182
- /**
183
- * @param {Array<Uint8Array<ArrayBuffer>>} updates
184
- * @return {Uint8Array<ArrayBuffer>}
185
- */
186
- export const mergeUpdates = updates => mergeUpdatesV2(updates, UpdateDecoderV1, UpdateEncoderV1)
187
-
188
- /**
189
- * @param {Uint8Array} update
190
- * @param {typeof IdSetEncoderV1 | typeof IdSetEncoderV2} YEncoder
191
- * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} YDecoder
192
- * @return {Uint8Array}
193
- */
194
- export const encodeStateVectorFromUpdateV2 = (update, YEncoder = IdSetEncoderV2, YDecoder = UpdateDecoderV2) => {
195
- const encoder = new YEncoder()
196
- const updateDecoder = new LazyStructReader(new YDecoder(decoding.createDecoder(update)), false)
197
- let curr = updateDecoder.curr
198
- if (curr !== null) {
199
- let size = 0
200
- let currClient = curr.id.client
201
- let stopCounting = curr.id.clock !== 0 // must start at 0
202
- let currClock = stopCounting ? 0 : curr.id.clock + curr.length
203
- for (; curr !== null; curr = updateDecoder.next()) {
204
- if (currClient !== curr.id.client) {
205
- if (currClock !== 0) {
206
- size++
207
- // We found a new client
208
- // write what we have to the encoder
209
- encoding.writeVarUint(encoder.restEncoder, currClient)
210
- encoding.writeVarUint(encoder.restEncoder, currClock)
211
- }
212
- currClient = curr.id.client
213
- currClock = 0
214
- stopCounting = curr.id.clock !== 0
215
- }
216
- // we ignore skips
217
- if (curr.constructor === Skip) {
218
- stopCounting = true
219
- }
220
- if (!stopCounting) {
221
- currClock = curr.id.clock + curr.length
222
- }
223
- }
224
- // write what we have
225
- if (currClock !== 0) {
226
- size++
227
- encoding.writeVarUint(encoder.restEncoder, currClient)
228
- encoding.writeVarUint(encoder.restEncoder, currClock)
229
- }
230
- // prepend the size of the state vector
231
- const enc = encoding.createEncoder()
232
- encoding.writeVarUint(enc, size)
233
- encoding.writeBinaryEncoder(enc, encoder.restEncoder)
234
- encoder.restEncoder = enc
235
- return encoder.toUint8Array()
236
- } else {
237
- encoding.writeVarUint(encoder.restEncoder, 0)
238
- return encoder.toUint8Array()
239
- }
240
- }
241
-
242
- /**
243
- * @param {Uint8Array} update
244
- * @return {Uint8Array}
245
- */
246
- export const encodeStateVectorFromUpdate = update => encodeStateVectorFromUpdateV2(update, IdSetEncoderV1, UpdateDecoderV1)
247
-
248
- /**
249
- * @param {Uint8Array} update
250
- * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} [YDecoder]
251
- */
252
- export const readUpdateIdRangesV2 = (update, YDecoder = UpdateDecoderV2) => {
253
- const updateDecoder = new YDecoder(decoding.createDecoder(update))
254
- const lazyDecoder = new LazyStructReader(updateDecoder, true)
255
- const inserts = createIdSet()
256
- let lastClientId = -1
257
- let lastClock = 0
258
- let lastLen = 0
259
- for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
260
- const currId = curr.id
261
- if (lastClientId === currId.client && lastClock + lastLen === currId.clock) {
262
- // default case: extend prev entry
263
- lastLen += curr.length
264
- } else {
265
- if (lastClientId >= 0) {
266
- inserts.add(lastClientId, lastClock, lastLen)
267
- }
268
- lastClientId = currId.client
269
- lastClock = currId.clock
270
- lastLen = curr.length
271
- }
272
- }
273
- if (lastClientId >= 0) {
274
- inserts.add(lastClientId, lastClock, lastLen)
275
- }
276
- const deletes = readIdSet(updateDecoder)
277
- return { inserts, deletes }
278
- }
279
-
280
- /**
281
- * @param {Uint8Array} update
282
- */
283
- export const readUpdateIdRanges = update => readUpdateIdRangesV2(update, UpdateDecoderV1)
284
-
285
- /**
286
- * This method is intended to slice any kind of struct and retrieve the right part.
287
- * It does not handle side-effects, so it should only be used by the lazy-encoder.
288
- *
289
- * @param {Item | GC | Skip} left
290
- * @param {number} diff
291
- * @return {Item | GC}
292
- */
293
- const sliceStruct = (left, diff) => {
294
- if (left.constructor === GC) {
295
- const { client, clock } = left.id
296
- return new GC(createID(client, clock + diff), left.length - diff)
297
- } else if (left.constructor === Skip) {
298
- const { client, clock } = left.id
299
- return new Skip(createID(client, clock + diff), left.length - diff)
300
- } else {
301
- const leftItem = /** @type {Item} */ (left)
302
- const { client, clock } = leftItem.id
303
- return new Item(
304
- createID(client, clock + diff),
305
- null,
306
- createID(client, clock + diff - 1),
307
- null,
308
- leftItem.rightOrigin,
309
- leftItem.parent,
310
- leftItem.parentSub,
311
- leftItem.content.splice(diff)
312
- )
313
- }
314
- }
315
-
316
- /**
317
- *
318
- * This function works similarly to `readUpdateV2`.
319
- *
320
- * @param {Array<Uint8Array<ArrayBuffer>>} updates
321
- * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
322
- * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
323
- * @return {Uint8Array<ArrayBuffer>}
324
- */
325
- export const mergeUpdatesV2 = (updates, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
326
- if (updates.length === 1) {
327
- return updates[0]
328
- }
329
- const updateDecoders = updates.map(update => new YDecoder(decoding.createDecoder(update)))
330
- let lazyStructDecoders = updateDecoders.map(decoder => new LazyStructReader(decoder, true))
331
-
332
- /**
333
- * @todo we don't need offset because we always slice before
334
- * @type {null | { struct: Item | GC | Skip, offset: number }}
335
- */
336
- let currWrite = null
337
-
338
- const updateEncoder = new YEncoder()
339
- // write structs lazily
340
- const lazyStructEncoder = new LazyStructWriter(updateEncoder)
341
-
342
- // Note: We need to ensure that all lazyStructDecoders are fully consumed
343
- // Note: Should merge document updates whenever possible - even from different updates
344
- // Note: Should handle that some operations cannot be applied yet ()
345
-
346
- while (true) {
347
- // Write higher clients first ⇒ sort by clientID & clock and remove decoders without content
348
- lazyStructDecoders = lazyStructDecoders.filter(dec => dec.curr !== null)
349
- lazyStructDecoders.sort(
350
- /** @type {function(any,any):number} */ (dec1, dec2) => {
351
- if (dec1.curr.id.client === dec2.curr.id.client) {
352
- const clockDiff = dec1.curr.id.clock - dec2.curr.id.clock
353
- if (clockDiff === 0) {
354
- // @todo remove references to skip since the structDecoders must filter Skips.
355
- return dec1.curr.constructor === dec2.curr.constructor
356
- ? 0
357
- : dec1.curr.constructor === Skip ? 1 : -1 // we are filtering skips anyway.
358
- } else {
359
- return clockDiff
360
- }
361
- } else {
362
- return dec2.curr.id.client - dec1.curr.id.client
363
- }
364
- }
365
- )
366
- if (lazyStructDecoders.length === 0) {
367
- break
368
- }
369
- const currDecoder = lazyStructDecoders[0]
370
- // write from currDecoder until the next operation is from another client or if filler-struct
371
- // then we need to reorder the decoders and find the next operation to write
372
- const firstClient = /** @type {Item | GC} */ (currDecoder.curr).id.client
373
-
374
- if (currWrite !== null) {
375
- let curr = /** @type {Item | GC | null} */ (currDecoder.curr)
376
- let iterated = false
377
-
378
- // iterate until we find something that we haven't written already
379
- // remember: first the high client-ids are written
380
- while (curr !== null && curr.id.clock + curr.length <= currWrite.struct.id.clock + currWrite.struct.length && curr.id.client >= currWrite.struct.id.client) {
381
- curr = currDecoder.next()
382
- iterated = true
383
- }
384
- if (
385
- curr === null || // current decoder is empty
386
- curr.id.client !== firstClient || // check whether there is another decoder that has has updates from `firstClient`
387
- (iterated && curr.id.clock > currWrite.struct.id.clock + currWrite.struct.length) // the above while loop was used and we are potentially missing updates
388
- ) {
389
- continue
390
- }
391
-
392
- if (firstClient !== currWrite.struct.id.client) {
393
- writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset)
394
- currWrite = { struct: curr, offset: 0 }
395
- currDecoder.next()
396
- } else {
397
- if (currWrite.struct.id.clock + currWrite.struct.length < curr.id.clock) {
398
- // @todo write currStruct & set currStruct = Skip(clock = currStruct.id.clock + currStruct.length, length = curr.id.clock - self.clock)
399
- if (currWrite.struct.constructor === Skip) {
400
- // extend existing skip
401
- currWrite.struct.length = curr.id.clock + curr.length - currWrite.struct.id.clock
402
- } else {
403
- writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset)
404
- const diff = curr.id.clock - currWrite.struct.id.clock - currWrite.struct.length
405
- /**
406
- * @type {Skip}
407
- */
408
- const struct = new Skip(createID(firstClient, currWrite.struct.id.clock + currWrite.struct.length), diff)
409
- currWrite = { struct, offset: 0 }
410
- }
411
- } else { // if (currWrite.struct.id.clock + currWrite.struct.length >= curr.id.clock) {
412
- const diff = currWrite.struct.id.clock + currWrite.struct.length - curr.id.clock
413
- if (diff > 0) {
414
- if (currWrite.struct.constructor === Skip) {
415
- // prefer to slice Skip because the other struct might contain more information
416
- currWrite.struct.length -= diff
417
- } else {
418
- curr = sliceStruct(curr, diff)
419
- }
420
- }
421
- if (!currWrite.struct.mergeWith(/** @type {any} */ (curr))) {
422
- writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset)
423
- currWrite = { struct: curr, offset: 0 }
424
- currDecoder.next()
425
- }
426
- }
427
- }
428
- } else {
429
- currWrite = { struct: /** @type {Item | GC} */ (currDecoder.curr), offset: 0 }
430
- currDecoder.next()
431
- }
432
- for (
433
- let next = currDecoder.curr;
434
- next !== null && next.id.client === firstClient && next.id.clock === currWrite.struct.id.clock + currWrite.struct.length && next.constructor !== Skip;
435
- next = currDecoder.next()
436
- ) {
437
- writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset)
438
- currWrite = { struct: next, offset: 0 }
439
- }
440
- }
441
- if (currWrite !== null) {
442
- writeStructToLazyStructWriter(lazyStructEncoder, currWrite.struct, currWrite.offset)
443
- currWrite = null
444
- }
445
- finishLazyStructWriting(lazyStructEncoder)
446
-
447
- const dss = updateDecoders.map(decoder => readIdSet(decoder))
448
- const ds = mergeIdSets(dss)
449
- writeIdSet(updateEncoder, ds)
450
- return updateEncoder.toUint8Array()
451
- }
452
-
453
- /**
454
- * @param {Uint8Array} update
455
- * @param {Uint8Array} sv
456
- * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
457
- * @param {typeof UpdateEncoderV1 | typeof UpdateEncoderV2} [YEncoder]
458
- */
459
- export const diffUpdateV2 = (update, sv, YDecoder = UpdateDecoderV2, YEncoder = UpdateEncoderV2) => {
460
- const state = decodeStateVector(sv)
461
- const encoder = new YEncoder()
462
- const lazyStructWriter = new LazyStructWriter(encoder)
463
- const decoder = new YDecoder(decoding.createDecoder(update))
464
- const reader = new LazyStructReader(decoder, false)
465
- while (reader.curr) {
466
- const curr = reader.curr
467
- const currClient = curr.id.client
468
- const svClock = state.get(currClient) || 0
469
- if (reader.curr.constructor === Skip) {
470
- // the first written struct shouldn't be a skip
471
- reader.next()
472
- continue
473
- }
474
- if (curr.id.clock + curr.length > svClock) {
475
- writeStructToLazyStructWriter(lazyStructWriter, curr, math.max(svClock - curr.id.clock, 0))
476
- reader.next()
477
- while (reader.curr && reader.curr.id.client === currClient) {
478
- writeStructToLazyStructWriter(lazyStructWriter, reader.curr, 0)
479
- reader.next()
480
- }
481
- } else {
482
- // read until something new comes up
483
- while (reader.curr && reader.curr.id.client === currClient && reader.curr.id.clock + reader.curr.length <= svClock) {
484
- reader.next()
485
- }
486
- }
487
- }
488
- finishLazyStructWriting(lazyStructWriter)
489
- // write ds
490
- const ds = readIdSet(decoder)
491
- writeIdSet(encoder, ds)
492
- return encoder.toUint8Array()
493
- }
494
-
495
- /**
496
- * @param {Uint8Array} update
497
- * @param {Uint8Array} sv
498
- */
499
- export const diffUpdate = (update, sv) => diffUpdateV2(update, sv, UpdateDecoderV1, UpdateEncoderV1)
500
-
501
- /**
502
- * @param {LazyStructWriter} lazyWriter
503
- */
504
- const flushLazyStructWriter = lazyWriter => {
505
- if (lazyWriter.written > 0) {
506
- lazyWriter.clientStructs.push({ written: lazyWriter.written, restEncoder: encoding.toUint8Array(lazyWriter.encoder.restEncoder) })
507
- lazyWriter.encoder.restEncoder = encoding.createEncoder()
508
- lazyWriter.written = 0
509
- }
510
- }
511
-
512
- /**
513
- * @param {LazyStructWriter} lazyWriter
514
- * @param {Item | GC} struct
515
- * @param {number} offset
516
- */
517
- const writeStructToLazyStructWriter = (lazyWriter, struct, offset) => {
518
- // flush curr if we start another client
519
- if (lazyWriter.written > 0 && lazyWriter.currClient !== struct.id.client) {
520
- flushLazyStructWriter(lazyWriter)
521
- }
522
- if (lazyWriter.written === 0) {
523
- lazyWriter.currClient = struct.id.client
524
- // write next client
525
- lazyWriter.encoder.writeClient(struct.id.client)
526
- // write startClock
527
- encoding.writeVarUint(lazyWriter.encoder.restEncoder, struct.id.clock + offset)
528
- }
529
- struct.write(lazyWriter.encoder, offset, 0)
530
- lazyWriter.written++
531
- }
532
- /**
533
- * Call this function when we collected all parts and want to
534
- * put all the parts together. After calling this method,
535
- * you can continue using the UpdateEncoder.
536
- *
537
- * @param {LazyStructWriter} lazyWriter
538
- */
539
- const finishLazyStructWriting = (lazyWriter) => {
540
- flushLazyStructWriter(lazyWriter)
541
-
542
- // this is a fresh encoder because we called flushCurr
543
- const restEncoder = lazyWriter.encoder.restEncoder
544
-
545
- /**
546
- * Now we put all the fragments together.
547
- * This works similarly to `writeClientsStructs`
548
- */
549
-
550
- // write # states that were updated - i.e. the clients
551
- encoding.writeVarUint(restEncoder, lazyWriter.clientStructs.length)
552
-
553
- for (let i = 0; i < lazyWriter.clientStructs.length; i++) {
554
- const partStructs = lazyWriter.clientStructs[i]
555
- /**
556
- * Works similarly to `writeStructs`
557
- */
558
- // write # encoded structs
559
- encoding.writeVarUint(restEncoder, partStructs.written)
560
- // write the rest of the fragment
561
- encoding.writeUint8Array(restEncoder, partStructs.restEncoder)
562
- }
563
- }
564
-
565
- /**
566
- * @param {Uint8Array} update
567
- * @param {function(Item|GC|Skip):Item|GC|Skip} blockTransformer
568
- * @param {typeof UpdateDecoderV2 | typeof UpdateDecoderV1} YDecoder
569
- * @param {typeof UpdateEncoderV2 | typeof UpdateEncoderV1 } YEncoder
570
- */
571
- export const convertUpdateFormat = (update, blockTransformer, YDecoder, YEncoder) => {
572
- const updateDecoder = new YDecoder(decoding.createDecoder(update))
573
- const lazyDecoder = new LazyStructReader(updateDecoder, false)
574
- const updateEncoder = new YEncoder()
575
- const lazyWriter = new LazyStructWriter(updateEncoder)
576
- for (let curr = lazyDecoder.curr; curr !== null; curr = lazyDecoder.next()) {
577
- writeStructToLazyStructWriter(lazyWriter, blockTransformer(curr), 0)
578
- }
579
- finishLazyStructWriting(lazyWriter)
580
- const ds = readIdSet(updateDecoder)
581
- writeIdSet(updateEncoder, ds)
582
- return updateEncoder.toUint8Array()
583
- }
584
-
585
- /**
586
- * @typedef {Object} ObfuscatorOptions
587
- * @property {boolean} [ObfuscatorOptions.formatting=true]
588
- * @property {boolean} [ObfuscatorOptions.subdocs=true]
589
- * @property {boolean} [ObfuscatorOptions.yxml=true] Whether to obfuscate nodeName / hookName
590
- */
591
-
592
- /**
593
- * @param {ObfuscatorOptions} obfuscator
594
- */
595
- const createObfuscator = ({ formatting = true, subdocs = true, yxml = true } = {}) => {
596
- let i = 0
597
- const mapKeyCache = map.create()
598
- const nodeNameCache = map.create()
599
- const formattingKeyCache = map.create()
600
- const formattingValueCache = map.create()
601
- formattingValueCache.set(null, null) // end of a formatting range should always be the end of a formatting range
602
- /**
603
- * @param {Item|GC|Skip} block
604
- * @return {Item|GC|Skip}
605
- */
606
- return block => {
607
- switch (block.constructor) {
608
- case GC:
609
- case Skip:
610
- return block
611
- case Item: {
612
- const item = /** @type {Item} */ (block)
613
- const content = item.content
614
- switch (content.constructor) {
615
- case ContentDeleted:
616
- break
617
- case ContentType: {
618
- if (yxml) {
619
- const type = /** @type {ContentType} */ (content).type
620
- if (type instanceof YXmlElement) {
621
- type.nodeName = map.setIfUndefined(nodeNameCache, type.nodeName, () => 'node-' + i)
622
- }
623
- // @ts-ignore
624
- if (type instanceof YXmlHook) {
625
- type.hookName = map.setIfUndefined(nodeNameCache, type.hookName, () => 'hook-' + i)
626
- }
627
- }
628
- break
629
- }
630
- case ContentAny: {
631
- const c = /** @type {ContentAny} */ (content)
632
- c.arr = c.arr.map(() => i)
633
- break
634
- }
635
- case ContentBinary: {
636
- const c = /** @type {ContentBinary} */ (content)
637
- c.content = new Uint8Array([i])
638
- break
639
- }
640
- case ContentDoc: {
641
- const c = /** @type {ContentDoc} */ (content)
642
- if (subdocs) {
643
- c.opts = {}
644
- c.doc.guid = i + ''
645
- }
646
- break
647
- }
648
- case ContentEmbed: {
649
- const c = /** @type {ContentEmbed} */ (content)
650
- c.embed = {}
651
- break
652
- }
653
- case ContentFormat: {
654
- const c = /** @type {ContentFormat} */ (content)
655
- if (formatting) {
656
- c.key = map.setIfUndefined(formattingKeyCache, c.key, () => i + '')
657
- c.value = map.setIfUndefined(formattingValueCache, c.value, () => ({ i }))
658
- }
659
- break
660
- }
661
- case ContentJSON: {
662
- const c = /** @type {ContentJSON} */ (content)
663
- c.arr = c.arr.map(() => i)
664
- break
665
- }
666
- case ContentString: {
667
- const c = /** @type {ContentString} */ (content)
668
- c.str = string.repeat((i % 10) + '', c.str.length)
669
- break
670
- }
671
- default:
672
- // unknown content type
673
- error.unexpectedCase()
674
- }
675
- if (item.parentSub) {
676
- item.parentSub = map.setIfUndefined(mapKeyCache, item.parentSub, () => i + '')
677
- }
678
- i++
679
- return block
680
- }
681
- default:
682
- // unknown block-type
683
- error.unexpectedCase()
684
- }
685
- }
686
- }
687
-
688
- /**
689
- * This function obfuscates the content of a Yjs update. This is useful to share
690
- * buggy Yjs documents while significantly limiting the possibility that a
691
- * developer can on the user. Note that it might still be possible to deduce
692
- * some information by analyzing the "structure" of the document or by analyzing
693
- * the typing behavior using the CRDT-related metadata that is still kept fully
694
- * intact.
695
- *
696
- * @param {Uint8Array} update
697
- * @param {ObfuscatorOptions} [opts]
698
- */
699
- export const obfuscateUpdate = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV1, UpdateEncoderV1)
700
-
701
- /**
702
- * @param {Uint8Array} update
703
- * @param {ObfuscatorOptions} [opts]
704
- */
705
- export const obfuscateUpdateV2 = (update, opts) => convertUpdateFormat(update, createObfuscator(opts), UpdateDecoderV2, UpdateEncoderV2)
706
-
707
- /**
708
- * @param {Uint8Array} update
709
- */
710
- export const convertUpdateFormatV1ToV2 = update => convertUpdateFormat(update, f.id, UpdateDecoderV1, UpdateEncoderV2)
711
-
712
- /**
713
- * @param {Uint8Array} update
714
- */
715
- export const convertUpdateFormatV2ToV1 = update => convertUpdateFormat(update, f.id, UpdateDecoderV2, UpdateEncoderV1)