@fluid-experimental/tree 0.58.3000-61081 → 0.59.2000-61729

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 (98) hide show
  1. package/README.md +156 -43
  2. package/dist/ChangeTypes.d.ts +9 -14
  3. package/dist/ChangeTypes.d.ts.map +1 -1
  4. package/dist/ChangeTypes.js.map +1 -1
  5. package/dist/Checkout.d.ts.map +1 -1
  6. package/dist/Checkout.js +3 -2
  7. package/dist/Checkout.js.map +1 -1
  8. package/dist/LogViewer.d.ts +2 -3
  9. package/dist/LogViewer.d.ts.map +1 -1
  10. package/dist/LogViewer.js +5 -4
  11. package/dist/LogViewer.js.map +1 -1
  12. package/dist/NodeIdUtilities.d.ts +26 -11
  13. package/dist/NodeIdUtilities.d.ts.map +1 -1
  14. package/dist/NodeIdUtilities.js.map +1 -1
  15. package/dist/SharedTree.d.ts +61 -22
  16. package/dist/SharedTree.d.ts.map +1 -1
  17. package/dist/SharedTree.js +75 -30
  18. package/dist/SharedTree.js.map +1 -1
  19. package/dist/Transaction.d.ts +22 -4
  20. package/dist/Transaction.d.ts.map +1 -1
  21. package/dist/Transaction.js +27 -11
  22. package/dist/Transaction.js.map +1 -1
  23. package/dist/TransactionInternal.d.ts +3 -6
  24. package/dist/TransactionInternal.d.ts.map +1 -1
  25. package/dist/TransactionInternal.js +8 -4
  26. package/dist/TransactionInternal.js.map +1 -1
  27. package/dist/TreeCompressor.d.ts +0 -1
  28. package/dist/TreeCompressor.d.ts.map +1 -1
  29. package/dist/TreeCompressor.js +31 -26
  30. package/dist/TreeCompressor.js.map +1 -1
  31. package/dist/TreeView.d.ts.map +1 -1
  32. package/dist/TreeView.js +3 -2
  33. package/dist/TreeView.js.map +1 -1
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js.map +1 -1
  37. package/docs/Write-Format.md +19 -0
  38. package/lib/ChangeTypes.d.ts +9 -14
  39. package/lib/ChangeTypes.d.ts.map +1 -1
  40. package/lib/ChangeTypes.js.map +1 -1
  41. package/lib/Checkout.d.ts.map +1 -1
  42. package/lib/Checkout.js +3 -2
  43. package/lib/Checkout.js.map +1 -1
  44. package/lib/LogViewer.d.ts +2 -3
  45. package/lib/LogViewer.d.ts.map +1 -1
  46. package/lib/LogViewer.js +5 -4
  47. package/lib/LogViewer.js.map +1 -1
  48. package/lib/NodeIdUtilities.d.ts +26 -11
  49. package/lib/NodeIdUtilities.d.ts.map +1 -1
  50. package/lib/NodeIdUtilities.js.map +1 -1
  51. package/lib/SharedTree.d.ts +61 -22
  52. package/lib/SharedTree.d.ts.map +1 -1
  53. package/lib/SharedTree.js +75 -30
  54. package/lib/SharedTree.js.map +1 -1
  55. package/lib/Transaction.d.ts +22 -4
  56. package/lib/Transaction.d.ts.map +1 -1
  57. package/lib/Transaction.js +26 -10
  58. package/lib/Transaction.js.map +1 -1
  59. package/lib/TransactionInternal.d.ts +3 -6
  60. package/lib/TransactionInternal.d.ts.map +1 -1
  61. package/lib/TransactionInternal.js +8 -4
  62. package/lib/TransactionInternal.js.map +1 -1
  63. package/lib/TreeCompressor.d.ts +0 -1
  64. package/lib/TreeCompressor.d.ts.map +1 -1
  65. package/lib/TreeCompressor.js +31 -26
  66. package/lib/TreeCompressor.js.map +1 -1
  67. package/lib/TreeView.d.ts.map +1 -1
  68. package/lib/TreeView.js +3 -2
  69. package/lib/TreeView.js.map +1 -1
  70. package/lib/index.d.ts +1 -1
  71. package/lib/index.d.ts.map +1 -1
  72. package/lib/index.js.map +1 -1
  73. package/lib/test/LogViewer.tests.js +13 -10
  74. package/lib/test/LogViewer.tests.js.map +1 -1
  75. package/lib/test/Transaction.tests.js +36 -2
  76. package/lib/test/Transaction.tests.js.map +1 -1
  77. package/lib/test/TreeView.tests.js +29 -0
  78. package/lib/test/TreeView.tests.js.map +1 -1
  79. package/lib/test/Virtualization.tests.js +1 -2
  80. package/lib/test/Virtualization.tests.js.map +1 -1
  81. package/lib/test/fuzz/SharedTreeFuzzTests.d.ts.map +1 -1
  82. package/lib/test/fuzz/SharedTreeFuzzTests.js +19 -2
  83. package/lib/test/fuzz/SharedTreeFuzzTests.js.map +1 -1
  84. package/lib/test/utilities/SharedTreeVersioningTests.d.ts.map +1 -1
  85. package/lib/test/utilities/SharedTreeVersioningTests.js +26 -1
  86. package/lib/test/utilities/SharedTreeVersioningTests.js.map +1 -1
  87. package/package.json +18 -18
  88. package/src/ChangeTypes.ts +9 -14
  89. package/src/Checkout.ts +3 -3
  90. package/src/LogViewer.ts +4 -4
  91. package/src/NodeIdUtilities.ts +26 -11
  92. package/src/SharedTree.ts +81 -28
  93. package/src/Transaction.ts +39 -13
  94. package/src/TransactionInternal.ts +9 -10
  95. package/src/TreeCompressor.ts +31 -40
  96. package/src/TreeView.ts +3 -2
  97. package/src/index.ts +0 -1
  98. package/docs/Future.md +0 -155
@@ -24,7 +24,6 @@ const RevisionView_1 = require("./RevisionView");
24
24
  const SharedTreeEncoder_1 = require("./SharedTreeEncoder");
25
25
  const HistoryEditFactory_1 = require("./HistoryEditFactory");
26
26
  const ChangeTypes_1 = require("./ChangeTypes");
27
- const TransactionInternal_1 = require("./TransactionInternal");
28
27
  const id_compressor_1 = require("./id-compressor");
29
28
  const IdConversion_1 = require("./IdConversion");
30
29
  const StringInterner_1 = require("./StringInterner");
@@ -36,13 +35,10 @@ const StringInterner_1 = require("./StringInterner");
36
35
  class SharedTreeFactory {
37
36
  /**
38
37
  * Get a factory for SharedTree to register with the data store.
39
- * @param writeFormat - Determines the format version the SharedTree will write summaries in.
40
- * This format may be updated to a newer (supported) version at runtime if a collaborating shared-tree
41
- * that was initialized with a newer write version connects to the session. Care must be taken when changing this value,
42
- * as a staged rollout must have occurred such that all collaborating clients must have the code to read at least the version
43
- * written.
38
+ * @param writeFormat - Determines the format version the SharedTree will write ops and summaries in. See [the write format
39
+ * documentation](../docs/Write-Format.md) for more information.
44
40
  * @param summarizeHistory - Determines if the history is included in summaries and if edit chunks are uploaded when they are full.
45
- * See docs/Breaking-Change-Migration for more details on this scheme.
41
+ * See the [breaking change migration documentation](docs/Breaking-Change-Migration) for more details on this scheme.
46
42
  * @param expensiveValidation - Enables expensive asserts on SharedTree.
47
43
  * @returns A factory that creates `SharedTree`s and loads them from storage.
48
44
  */
@@ -110,7 +106,7 @@ const snapshotFileName = 'header';
110
106
  const sortedWriteVersions = [persisted_types_1.WriteFormat.v0_0_2, persisted_types_1.WriteFormat.v0_1_1];
111
107
  const sharedTreeTelemetryProperties = { all: { isSharedTreeEvent: true } };
112
108
  /**
113
- * A distributed tree.
109
+ * A [distributed tree](../Readme.md).
114
110
  * @public
115
111
  */
116
112
  class SharedTree extends shared_object_base_1.SharedObject {
@@ -118,7 +114,8 @@ class SharedTree extends shared_object_base_1.SharedObject {
118
114
  * Create a new SharedTreeFactory.
119
115
  * @param runtime - The runtime the SharedTree will be associated with
120
116
  * @param id - Unique ID for the SharedTree
121
- * @param writeFormat - Determines the format version the SharedTree will write summaries in.
117
+ * @param writeFormat - Determines the format version the SharedTree will write ops and summaries in. See [the write format
118
+ * documentation](../docs/Write-Format.md) for more information.
122
119
  * @param summarizeHistory - Determines if the history is included in summaries and if edit chunks are uploaded when they are full.
123
120
  * @param expensiveValidation - Enable expensive asserts.
124
121
  */
@@ -152,7 +149,6 @@ class SharedTree extends shared_object_base_1.SharedObject {
152
149
  };
153
150
  this.emit(EventTypes_1.SharedTreeEvent.SequencedEditApplied, eventArguments);
154
151
  };
155
- this.transactionFactory = TransactionInternal_1.TransactionInternal.factory;
156
152
  /**
157
153
  * Re-computes currentIsOldest and emits an event if it has changed.
158
154
  * TODO:#55900: Get rid of copy-pasted OldestClientObserver code
@@ -202,6 +198,7 @@ class SharedTree extends shared_object_base_1.SharedObject {
202
198
  /**
203
199
  * Get a factory for SharedTree to register with the data store.
204
200
  * @param summarizeHistory - Determines if the history is included in summaries and if edit chunks are uploaded when they are full.
201
+ *
205
202
  * On 0.1.1 documents, due to current code limitations, this parameter is only impactful for newly created documents.
206
203
  * `SharedTree`s which load existing documents will summarize history if and only if the loaded summary included history.
207
204
  *
@@ -209,14 +206,19 @@ class SharedTree extends shared_object_base_1.SharedObject {
209
206
  * In the future we may allow modification of whether or not a particular document saves history, but only via a consensus mechanism.
210
207
  * See the skipped test in SharedTreeFuzzTests.ts for more details on this issue.
211
208
  * See docs/Breaking-Change-Migration for more details on the consensus scheme.
212
- * @param writeFormat - Determines the format version the SharedTree will write summaries in.
209
+ * @param writeFormat - Determines the format version the SharedTree will write ops and summaries in.
213
210
  * This format may be updated to a newer (supported) version at runtime if a collaborating shared-tree
214
211
  * that was initialized with a newer write version connects to the session. Care must be taken when changing this value,
215
212
  * as a staged rollout must of occurred such that all collaborating clients must have the code to read at least the version
216
213
  * written.
214
+ * See [the write format documentation](../docs/Write-Format.md) for more information.
217
215
  * @returns A factory that creates `SharedTree`s and loads them from storage.
218
216
  */
219
217
  static getFactory(writeFormat, summarizeHistory = false) {
218
+ // On 0.1.1 documents, due to current code limitations, all clients MUST agree on the value of `summarizeHistory`.
219
+ // Note that this means staged rollout changing this value should not be attempted.
220
+ // It is possible to update shared-tree to correctly handle such a staged rollout, but that hasn't been implemented.
221
+ // See the skipped test in SharedTreeFuzzTests.ts for more details on this issue.
220
222
  return new SharedTreeFactory(writeFormat, summarizeHistory);
221
223
  }
222
224
  /**
@@ -264,27 +266,60 @@ class SharedTree extends shared_object_base_1.SharedObject {
264
266
  return this.logViewer.getRevisionViewInSession(Number.POSITIVE_INFINITY);
265
267
  }
266
268
  /**
267
- * {@inheritdoc NodeIdGenerator.generateNodeId}
269
+ * Generates a node identifier.
270
+ * The returned IDs may be used as the identifier of a node in the SharedTree.
271
+ * `NodeId`s are *always* unique and stable within the scope of the tree and session that generated them. They are *not* unique within
272
+ * a Fluid container, and *cannot* be compared across instances of a SharedTree. They are *not* stable across sessions/lifetimes of a
273
+ * SharedTree, and *cannot* be persisted (e.g. stored in payloads, uploaded in blobs, etc.). If stable persistence is needed,
274
+ * NodeIdConverter.convertToStableNodeId may be used to return a corresponding UUID that is globally unique and stable.
275
+ * @param override - if supplied, calls to `convertToStableNodeId` using the returned node ID will return the override instead of
276
+ * the UUID. Calls to `generateNodeId` with the same override always return the same ID. Performance note: passing an override string
277
+ * incurs a storage cost that is significantly higher that a node ID without one, and should be avoided if possible.
268
278
  * @public
269
279
  */
270
280
  generateNodeId(override) {
271
281
  return this.idCompressor.generateCompressedId(override);
272
282
  }
273
- /** {@inheritdoc NodeIdConverter.convertToStableNodeId} */
283
+ /**
284
+ * Given a NodeId, returns the corresponding stable ID or throws if the supplied node ID was not generated with this tree (`NodeId`s
285
+ * may not be used across SharedTree instances, see `generateNodeId` for more).
286
+ * The returned value will be a UUID, unless the creation of `id` used an override string (see `generateNodeId` for more).
287
+ * The result is safe to persist and re-use across `SharedTree` instances, unlike `NodeId`.
288
+ * @public
289
+ */
274
290
  convertToStableNodeId(id) {
275
291
  var _a;
276
292
  return (_a = this.idCompressor.tryDecompress(id)) !== null && _a !== void 0 ? _a : Common_1.fail('Node id is not known to this SharedTree');
277
293
  }
278
- /** {@inheritdoc NodeIdConverter.tryConvertToStableNodeId} */
294
+ /**
295
+ * Given a NodeId, attempt to return the corresponding stable ID.
296
+ * The returned value will be a UUID, unless the creation of `id` used an override string (see `generateNodeId` for more).
297
+ * The returned stable ID is undefined if `id` was never created with this SharedTree. If a stable ID is returned, this does not imply
298
+ * that there is a node with `id` in the current revision of the tree, only that `id` was at some point generated by some instance of
299
+ * this tree.
300
+ * @public
301
+ */
279
302
  tryConvertToStableNodeId(id) {
280
303
  return this.idCompressor.tryDecompress(id);
281
304
  }
282
- /** {@inheritdoc NodeIdConverter.convertToNodeId} */
305
+ /**
306
+ * Given a stable ID, return the corresponding NodeId or throws if the supplied stable ID was never generated with this tree, either
307
+ * as a UUID corresponding to a `NodeId` or as an override passed to `generateNodeId`.
308
+ * If a stable ID is returned, this does not imply that there is a node with `id` in the current revision of the tree, only that
309
+ * `id` was at some point generated by an instance of this SharedTree.
310
+ * @public
311
+ */
283
312
  convertToNodeId(id) {
284
313
  var _a;
285
314
  return ((_a = this.idCompressor.tryRecompress(id)) !== null && _a !== void 0 ? _a : Common_1.fail('Stable node id is not known to this SharedTree'));
286
315
  }
287
- /** {@inheritdoc NodeIdConverter.tryConvertToNodeId} */
316
+ /**
317
+ * Given a stable ID, return the corresponding NodeId or return undefined if the supplied stable ID was never generated with this tree,
318
+ * either as a UUID corresponding to a `NodeId` or as an override passed to `generateNodeId`.
319
+ * If a stable ID is returned, this does not imply that there is a node with `id` in the current revision of the tree, only that
320
+ * `id` was at some point generated by an instance of this SharedTree.
321
+ * @public
322
+ */
288
323
  tryConvertToNodeId(id) {
289
324
  return this.idCompressor.tryRecompress(id);
290
325
  }
@@ -528,7 +563,7 @@ class SharedTree extends shared_object_base_1.SharedObject {
528
563
  // TODO:#47830: Store multiple checkpoints in summary.
529
564
  knownRevisions = [[editLog.length, { view: currentView }]];
530
565
  }
531
- const logViewer = new LogViewer_1.CachingLogViewer(editLog, RevisionView_1.RevisionView.fromTree(InitialTree_1.initialTree, this), knownRevisions, this.expensiveValidation, editStatusCallback, sequencedEditResultCallback, this.transactionFactory, 0);
566
+ const logViewer = new LogViewer_1.CachingLogViewer(editLog, RevisionView_1.RevisionView.fromTree(InitialTree_1.initialTree, this), knownRevisions, this.expensiveValidation, editStatusCallback, sequencedEditResultCallback, 0);
532
567
  this.editLog = editLog;
533
568
  this.cachingLogViewer = logViewer;
534
569
  return { editLog, cachingLogViewer: logViewer };
@@ -551,7 +586,7 @@ class SharedTree extends shared_object_base_1.SharedObject {
551
586
  }
552
587
  }
553
588
  /**
554
- * Compares this shared tree to another for equality. Should only be used for correctness testing.
589
+ * Compares this shared tree to another for equality. Should only be used for internal correctness testing.
555
590
  *
556
591
  * Equality means that the histories as captured by the EditLogs are equivalent.
557
592
  *
@@ -619,7 +654,9 @@ class SharedTree extends shared_object_base_1.SharedObject {
619
654
  }
620
655
  // TODO: This cast can be removed on typescript 4.6
621
656
  const edit = this.parseSequencedEdit(op);
622
- this.internStringsFromEdit(edit);
657
+ if (op.version === persisted_types_1.WriteFormat.v0_1_1) {
658
+ this.internStringsFromEdit(edit);
659
+ }
623
660
  this.processSequencedEdit(edit, typedMessage);
624
661
  }
625
662
  }
@@ -739,9 +776,8 @@ class SharedTree extends shared_object_base_1.SharedObject {
739
776
  }
740
777
  }
741
778
  upgradeFrom_0_0_2_to_0_1_1() {
742
- for (let i = 0; i < this.editLog.numberOfSequencedEdits; i++) {
743
- this.internStringsFromEdit(this.editsInternal.getEditInSessionAtIndex(i));
744
- }
779
+ // Reset the string interner, re-populate only with information that there is consensus on
780
+ this.interner = new StringInterner_1.MutableStringInterner([InitialTree_1.initialTree.definition]);
745
781
  const oldIdCompressor = this.idCompressor;
746
782
  // Create the IdCompressor that will be used after the upgrade
747
783
  const newIdCompressor = new id_compressor_1.IdCompressor(id_compressor_1.createSessionId(), persisted_types_1.reservedIdCount); // TODO: attribution info
@@ -764,12 +800,21 @@ class SharedTree extends shared_object_base_1.SharedObject {
764
800
  // All clients have the full history, and can therefore all "generate" the same final IDs for every ID in the history
765
801
  // via the ghost compressor.
766
802
  unifyHistoricalIds(ghostContext);
803
+ // The same logic applies to string interning, so intern all the strings in the history (superset of those in the current view)
804
+ for (let i = 0; i < this.editLog.numberOfSequencedEdits; i++) {
805
+ this.internStringsFromEdit(this.editsInternal.getEditInSessionAtIndex(i));
806
+ }
767
807
  }
768
808
  else {
769
809
  // Clients do not have the full history, but all share the same current view (sequenced). They can all finalize the same final
770
810
  // IDs for every ID in the view via the ghost compressor.
811
+ // The same logic applies for the string interner.
771
812
  for (const node of this.logViewer.getRevisionViewInSession(this.editLog.numberOfSequencedEdits)) {
772
813
  ghostContext.generateNodeId(this.convertToStableNodeId(node.identifier));
814
+ this.interner.getOrCreateInternedId(node.definition);
815
+ for (const label of [...node.traits.keys()].sort()) {
816
+ this.interner.getOrCreateInternedId(label);
817
+ }
773
818
  }
774
819
  // Every node in this client's history can simply be generated in the new compressor as well, preserving the UUID
775
820
  unifyHistoricalIds(newContext);
@@ -778,13 +823,8 @@ class SharedTree extends shared_object_base_1.SharedObject {
778
823
  newIdCompressor.finalizeCreationRange(ghostIdCompressor.takeNextCreationRange());
779
824
  this.idCompressor = newIdCompressor;
780
825
  }
781
- /**
782
- * Add an `Edit` directly.
783
- * External users should use one of the more specialized functions, like applyEdit which handles constructing the actual `Edit` object.
784
- * This is exposed as it is useful for testing, particularly with invalid and malformed Edits.
785
- * @internal
786
- */
787
- applyEdit(...changes) {
826
+ applyEdit(headOrChanges, ...tail) {
827
+ const changes = Array.isArray(headOrChanges) ? headOrChanges : [headOrChanges, ...tail];
788
828
  const id = EditUtilities_1.newEditId();
789
829
  const internalEdit = {
790
830
  id,
@@ -795,6 +835,10 @@ class SharedTree extends shared_object_base_1.SharedObject {
795
835
  return internalEdit;
796
836
  }
797
837
  /**
838
+ * Applies a set of internal changes to this tree. The result will be reflected in `SharedTree.currentView`.
839
+ * External users should use one of the more specialized functions, like `applyEdit` which handles constructing the actual `Edit`
840
+ * and uses public Change types.
841
+ * This is exposed for internal use only.
798
842
  * @internal
799
843
  */
800
844
  applyEditInternal(editOrChanges) {
@@ -811,7 +855,8 @@ class SharedTree extends shared_object_base_1.SharedObject {
811
855
  return edit;
812
856
  }
813
857
  /**
814
- * Given a newly constructed edit, add any necessary metadata
858
+ * Converts a public Change type to an internal representation.
859
+ * This is exposed for internal use only.
815
860
  * @internal
816
861
  */
817
862
  internalizeChange(change) {