@fluidframework/tree 2.61.0-356312 → 2.62.0-356644

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 (246) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/tree.alpha.api.md +3 -0
  3. package/dist/core/index.d.ts +1 -1
  4. package/dist/core/index.d.ts.map +1 -1
  5. package/dist/core/index.js +2 -1
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/core/rebase/index.d.ts +1 -1
  8. package/dist/core/rebase/index.d.ts.map +1 -1
  9. package/dist/core/rebase/index.js +2 -1
  10. package/dist/core/rebase/index.js.map +1 -1
  11. package/dist/core/rebase/utils.d.ts +10 -0
  12. package/dist/core/rebase/utils.d.ts.map +1 -1
  13. package/dist/core/rebase/utils.js +20 -1
  14. package/dist/core/rebase/utils.js.map +1 -1
  15. package/dist/packageVersion.d.ts +1 -1
  16. package/dist/packageVersion.js +1 -1
  17. package/dist/packageVersion.js.map +1 -1
  18. package/dist/shared-tree/schematizingTreeView.js +2 -2
  19. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  20. package/dist/shared-tree/sharedTree.d.ts +12 -2
  21. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  22. package/dist/shared-tree/sharedTree.js +71 -33
  23. package/dist/shared-tree/sharedTree.js.map +1 -1
  24. package/dist/shared-tree/treeCheckout.d.ts +13 -7
  25. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  26. package/dist/shared-tree/treeCheckout.js +114 -84
  27. package/dist/shared-tree/treeCheckout.js.map +1 -1
  28. package/dist/shared-tree-core/branch.d.ts +3 -0
  29. package/dist/shared-tree-core/branch.d.ts.map +1 -1
  30. package/dist/shared-tree-core/branch.js.map +1 -1
  31. package/dist/shared-tree-core/branchIdCodec.d.ts +11 -0
  32. package/dist/shared-tree-core/branchIdCodec.d.ts.map +1 -0
  33. package/dist/shared-tree-core/branchIdCodec.js +18 -0
  34. package/dist/shared-tree-core/branchIdCodec.js.map +1 -0
  35. package/dist/shared-tree-core/editManager.d.ts +33 -63
  36. package/dist/shared-tree-core/editManager.d.ts.map +1 -1
  37. package/dist/shared-tree-core/editManager.js +437 -290
  38. package/dist/shared-tree-core/editManager.js.map +1 -1
  39. package/dist/shared-tree-core/editManagerCodecs.d.ts +1 -1
  40. package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  41. package/dist/shared-tree-core/editManagerCodecs.js +7 -96
  42. package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
  43. package/dist/shared-tree-core/editManagerCodecsCommons.d.ts +17 -0
  44. package/dist/shared-tree-core/editManagerCodecsCommons.d.ts.map +1 -0
  45. package/dist/shared-tree-core/editManagerCodecsCommons.js +139 -0
  46. package/dist/shared-tree-core/editManagerCodecsCommons.js.map +1 -0
  47. package/dist/shared-tree-core/editManagerCodecsV1toV4.d.ts +16 -0
  48. package/dist/shared-tree-core/editManagerCodecsV1toV4.d.ts.map +1 -0
  49. package/dist/shared-tree-core/editManagerCodecsV1toV4.js +39 -0
  50. package/dist/shared-tree-core/editManagerCodecsV1toV4.js.map +1 -0
  51. package/dist/shared-tree-core/editManagerCodecsV5.d.ts +16 -0
  52. package/dist/shared-tree-core/editManagerCodecsV5.d.ts.map +1 -0
  53. package/dist/shared-tree-core/editManagerCodecsV5.js +58 -0
  54. package/dist/shared-tree-core/editManagerCodecsV5.js.map +1 -0
  55. package/dist/shared-tree-core/{editManagerFormat.d.ts → editManagerFormatCommons.d.ts} +31 -7
  56. package/dist/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -0
  57. package/dist/shared-tree-core/{editManagerFormat.js → editManagerFormatCommons.js} +13 -12
  58. package/dist/shared-tree-core/editManagerFormatCommons.js.map +1 -0
  59. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts +31 -0
  60. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -0
  61. package/dist/shared-tree-core/editManagerFormatV1toV4.js +24 -0
  62. package/dist/shared-tree-core/editManagerFormatV1toV4.js.map +1 -0
  63. package/dist/shared-tree-core/editManagerFormatV5.d.ts +62 -0
  64. package/dist/shared-tree-core/editManagerFormatV5.d.ts.map +1 -0
  65. package/dist/shared-tree-core/editManagerFormatV5.js +20 -0
  66. package/dist/shared-tree-core/editManagerFormatV5.js.map +1 -0
  67. package/dist/shared-tree-core/index.d.ts +3 -3
  68. package/dist/shared-tree-core/index.d.ts.map +1 -1
  69. package/dist/shared-tree-core/index.js.map +1 -1
  70. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts +11 -0
  71. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -0
  72. package/dist/shared-tree-core/messageCodecV1ToV4.js +59 -0
  73. package/dist/shared-tree-core/messageCodecV1ToV4.js.map +1 -0
  74. package/dist/shared-tree-core/messageCodecV5.d.ts +11 -0
  75. package/dist/shared-tree-core/messageCodecV5.d.ts.map +1 -0
  76. package/dist/shared-tree-core/messageCodecV5.js +78 -0
  77. package/dist/shared-tree-core/messageCodecV5.js.map +1 -0
  78. package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
  79. package/dist/shared-tree-core/messageCodecs.js +16 -47
  80. package/dist/shared-tree-core/messageCodecs.js.map +1 -1
  81. package/dist/shared-tree-core/{messageFormat.d.ts → messageFormatV1ToV4.d.ts} +1 -1
  82. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -0
  83. package/dist/shared-tree-core/{messageFormat.js → messageFormatV1ToV4.js} +1 -1
  84. package/dist/shared-tree-core/messageFormatV1ToV4.js.map +1 -0
  85. package/dist/shared-tree-core/messageFormatV5.d.ts +42 -0
  86. package/dist/shared-tree-core/messageFormatV5.d.ts.map +1 -0
  87. package/dist/shared-tree-core/messageFormatV5.js +20 -0
  88. package/dist/shared-tree-core/messageFormatV5.js.map +1 -0
  89. package/dist/shared-tree-core/messageTypes.d.ts +12 -2
  90. package/dist/shared-tree-core/messageTypes.d.ts.map +1 -1
  91. package/dist/shared-tree-core/messageTypes.js.map +1 -1
  92. package/dist/shared-tree-core/sequenceIdUtils.d.ts +1 -1
  93. package/dist/shared-tree-core/sequenceIdUtils.d.ts.map +1 -1
  94. package/dist/shared-tree-core/sequenceIdUtils.js.map +1 -1
  95. package/dist/shared-tree-core/sharedTreeCore.d.ts +18 -5
  96. package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  97. package/dist/shared-tree-core/sharedTreeCore.js +175 -56
  98. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  99. package/dist/simple-tree/api/dirtyIndex.js +7 -7
  100. package/dist/simple-tree/api/dirtyIndex.js.map +1 -1
  101. package/dist/simple-tree/api/tree.d.ts +10 -0
  102. package/dist/simple-tree/api/tree.d.ts.map +1 -1
  103. package/dist/simple-tree/api/tree.js.map +1 -1
  104. package/dist/simple-tree/core/treeNodeKernel.js +4 -4
  105. package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
  106. package/lib/core/index.d.ts +1 -1
  107. package/lib/core/index.d.ts.map +1 -1
  108. package/lib/core/index.js +1 -1
  109. package/lib/core/index.js.map +1 -1
  110. package/lib/core/rebase/index.d.ts +1 -1
  111. package/lib/core/rebase/index.d.ts.map +1 -1
  112. package/lib/core/rebase/index.js +1 -1
  113. package/lib/core/rebase/index.js.map +1 -1
  114. package/lib/core/rebase/utils.d.ts +10 -0
  115. package/lib/core/rebase/utils.d.ts.map +1 -1
  116. package/lib/core/rebase/utils.js +18 -0
  117. package/lib/core/rebase/utils.js.map +1 -1
  118. package/lib/packageVersion.d.ts +1 -1
  119. package/lib/packageVersion.js +1 -1
  120. package/lib/packageVersion.js.map +1 -1
  121. package/lib/shared-tree/schematizingTreeView.js +2 -2
  122. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  123. package/lib/shared-tree/sharedTree.d.ts +12 -2
  124. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  125. package/lib/shared-tree/sharedTree.js +72 -34
  126. package/lib/shared-tree/sharedTree.js.map +1 -1
  127. package/lib/shared-tree/treeCheckout.d.ts +13 -7
  128. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  129. package/lib/shared-tree/treeCheckout.js +115 -85
  130. package/lib/shared-tree/treeCheckout.js.map +1 -1
  131. package/lib/shared-tree-core/branch.d.ts +3 -0
  132. package/lib/shared-tree-core/branch.d.ts.map +1 -1
  133. package/lib/shared-tree-core/branch.js.map +1 -1
  134. package/lib/shared-tree-core/branchIdCodec.d.ts +11 -0
  135. package/lib/shared-tree-core/branchIdCodec.d.ts.map +1 -0
  136. package/lib/shared-tree-core/branchIdCodec.js +13 -0
  137. package/lib/shared-tree-core/branchIdCodec.js.map +1 -0
  138. package/lib/shared-tree-core/editManager.d.ts +33 -63
  139. package/lib/shared-tree-core/editManager.d.ts.map +1 -1
  140. package/lib/shared-tree-core/editManager.js +437 -290
  141. package/lib/shared-tree-core/editManager.js.map +1 -1
  142. package/lib/shared-tree-core/editManagerCodecs.d.ts +1 -1
  143. package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  144. package/lib/shared-tree-core/editManagerCodecs.js +4 -93
  145. package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
  146. package/lib/shared-tree-core/editManagerCodecsCommons.d.ts +17 -0
  147. package/lib/shared-tree-core/editManagerCodecsCommons.d.ts.map +1 -0
  148. package/lib/shared-tree-core/editManagerCodecsCommons.js +134 -0
  149. package/lib/shared-tree-core/editManagerCodecsCommons.js.map +1 -0
  150. package/lib/shared-tree-core/editManagerCodecsV1toV4.d.ts +16 -0
  151. package/lib/shared-tree-core/editManagerCodecsV1toV4.d.ts.map +1 -0
  152. package/lib/shared-tree-core/editManagerCodecsV1toV4.js +35 -0
  153. package/lib/shared-tree-core/editManagerCodecsV1toV4.js.map +1 -0
  154. package/lib/shared-tree-core/editManagerCodecsV5.d.ts +16 -0
  155. package/lib/shared-tree-core/editManagerCodecsV5.d.ts.map +1 -0
  156. package/lib/shared-tree-core/editManagerCodecsV5.js +54 -0
  157. package/lib/shared-tree-core/editManagerCodecsV5.js.map +1 -0
  158. package/lib/shared-tree-core/{editManagerFormat.d.ts → editManagerFormatCommons.d.ts} +31 -7
  159. package/lib/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -0
  160. package/lib/shared-tree-core/{editManagerFormat.js → editManagerFormatCommons.js} +10 -11
  161. package/lib/shared-tree-core/editManagerFormatCommons.js.map +1 -0
  162. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts +31 -0
  163. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -0
  164. package/lib/shared-tree-core/editManagerFormatV1toV4.js +20 -0
  165. package/lib/shared-tree-core/editManagerFormatV1toV4.js.map +1 -0
  166. package/lib/shared-tree-core/editManagerFormatV5.d.ts +62 -0
  167. package/lib/shared-tree-core/editManagerFormatV5.d.ts.map +1 -0
  168. package/lib/shared-tree-core/editManagerFormatV5.js +16 -0
  169. package/lib/shared-tree-core/editManagerFormatV5.js.map +1 -0
  170. package/lib/shared-tree-core/index.d.ts +3 -3
  171. package/lib/shared-tree-core/index.d.ts.map +1 -1
  172. package/lib/shared-tree-core/index.js.map +1 -1
  173. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts +11 -0
  174. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -0
  175. package/lib/shared-tree-core/messageCodecV1ToV4.js +55 -0
  176. package/lib/shared-tree-core/messageCodecV1ToV4.js.map +1 -0
  177. package/lib/shared-tree-core/messageCodecV5.d.ts +11 -0
  178. package/lib/shared-tree-core/messageCodecV5.d.ts.map +1 -0
  179. package/lib/shared-tree-core/messageCodecV5.js +74 -0
  180. package/lib/shared-tree-core/messageCodecV5.js.map +1 -0
  181. package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
  182. package/lib/shared-tree-core/messageCodecs.js +17 -48
  183. package/lib/shared-tree-core/messageCodecs.js.map +1 -1
  184. package/lib/shared-tree-core/{messageFormat.d.ts → messageFormatV1ToV4.d.ts} +1 -1
  185. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -0
  186. package/lib/shared-tree-core/{messageFormat.js → messageFormatV1ToV4.js} +1 -1
  187. package/lib/shared-tree-core/messageFormatV1ToV4.js.map +1 -0
  188. package/lib/shared-tree-core/messageFormatV5.d.ts +42 -0
  189. package/lib/shared-tree-core/messageFormatV5.d.ts.map +1 -0
  190. package/lib/shared-tree-core/messageFormatV5.js +16 -0
  191. package/lib/shared-tree-core/messageFormatV5.js.map +1 -0
  192. package/lib/shared-tree-core/messageTypes.d.ts +12 -2
  193. package/lib/shared-tree-core/messageTypes.d.ts.map +1 -1
  194. package/lib/shared-tree-core/messageTypes.js.map +1 -1
  195. package/lib/shared-tree-core/sequenceIdUtils.d.ts +1 -1
  196. package/lib/shared-tree-core/sequenceIdUtils.d.ts.map +1 -1
  197. package/lib/shared-tree-core/sequenceIdUtils.js.map +1 -1
  198. package/lib/shared-tree-core/sharedTreeCore.d.ts +18 -5
  199. package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  200. package/lib/shared-tree-core/sharedTreeCore.js +176 -57
  201. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  202. package/lib/simple-tree/api/dirtyIndex.js +7 -7
  203. package/lib/simple-tree/api/dirtyIndex.js.map +1 -1
  204. package/lib/simple-tree/api/tree.d.ts +10 -0
  205. package/lib/simple-tree/api/tree.d.ts.map +1 -1
  206. package/lib/simple-tree/api/tree.js.map +1 -1
  207. package/lib/simple-tree/core/treeNodeKernel.js +4 -4
  208. package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
  209. package/package.json +20 -20
  210. package/src/core/index.ts +1 -0
  211. package/src/core/rebase/index.ts +1 -0
  212. package/src/core/rebase/utils.ts +27 -0
  213. package/src/packageVersion.ts +1 -1
  214. package/src/shared-tree/schematizingTreeView.ts +2 -2
  215. package/src/shared-tree/sharedTree.ts +103 -46
  216. package/src/shared-tree/treeCheckout.ts +147 -98
  217. package/src/shared-tree-core/branch.ts +7 -0
  218. package/src/shared-tree-core/branchIdCodec.ts +28 -0
  219. package/src/shared-tree-core/editManager.ts +709 -437
  220. package/src/shared-tree-core/editManagerCodecs.ts +4 -164
  221. package/src/shared-tree-core/editManagerCodecsCommons.ts +236 -0
  222. package/src/shared-tree-core/editManagerCodecsV1toV4.ts +108 -0
  223. package/src/shared-tree-core/editManagerCodecsV5.ts +150 -0
  224. package/src/shared-tree-core/{editManagerFormat.ts → editManagerFormatCommons.ts} +17 -13
  225. package/src/shared-tree-core/editManagerFormatV1toV4.ts +42 -0
  226. package/src/shared-tree-core/editManagerFormatV5.ts +35 -0
  227. package/src/shared-tree-core/index.ts +3 -1
  228. package/src/shared-tree-core/messageCodecV1ToV4.ts +101 -0
  229. package/src/shared-tree-core/messageCodecV5.ts +128 -0
  230. package/src/shared-tree-core/messageCodecs.ts +16 -85
  231. package/src/shared-tree-core/messageFormatV5.ts +50 -0
  232. package/src/shared-tree-core/messageTypes.ts +15 -2
  233. package/src/shared-tree-core/sequenceIdUtils.ts +1 -1
  234. package/src/shared-tree-core/sharedTreeCore.ts +270 -84
  235. package/src/simple-tree/api/dirtyIndex.ts +7 -7
  236. package/src/simple-tree/api/tree.ts +15 -0
  237. package/src/simple-tree/core/treeNodeKernel.ts +4 -4
  238. package/dist/shared-tree-core/editManagerFormat.d.ts.map +0 -1
  239. package/dist/shared-tree-core/editManagerFormat.js.map +0 -1
  240. package/dist/shared-tree-core/messageFormat.d.ts.map +0 -1
  241. package/dist/shared-tree-core/messageFormat.js.map +0 -1
  242. package/lib/shared-tree-core/editManagerFormat.d.ts.map +0 -1
  243. package/lib/shared-tree-core/editManagerFormat.js.map +0 -1
  244. package/lib/shared-tree-core/messageFormat.d.ts.map +0 -1
  245. package/lib/shared-tree-core/messageFormat.js.map +0 -1
  246. /package/src/shared-tree-core/{messageFormat.ts → messageFormatV1ToV4.ts} +0 -0
@@ -6,7 +6,7 @@
6
6
  import type { ErasedType, IFluidLoadable } from "@fluidframework/core-interfaces/internal";
7
7
  import { assert, fail } from "@fluidframework/core-utils/internal";
8
8
  import type { IChannelStorageService } from "@fluidframework/datastore-definitions/internal";
9
- import type { IIdCompressor } from "@fluidframework/id-compressor";
9
+ import type { IIdCompressor, StableId } from "@fluidframework/id-compressor";
10
10
  import type {
11
11
  IChannelView,
12
12
  IFluidSerializer,
@@ -33,7 +33,6 @@ import {
33
33
  ObjectNodeStoredSchema,
34
34
  RevisionTagCodec,
35
35
  SchemaVersion,
36
- type TaggedChange,
37
36
  type TreeFieldStoredSchema,
38
37
  type TreeNodeSchemaIdentifier,
39
38
  type TreeNodeStoredSchema,
@@ -62,8 +61,8 @@ import {
62
61
  // eslint-disable-next-line import/no-internal-modules
63
62
  import type { FormatV1 } from "../feature-libraries/schema-index/index.js";
64
63
  import {
64
+ type BranchId,
65
65
  type ClonableSchemaAndPolicy,
66
- DefaultResubmitMachine,
67
66
  type ExplicitCoreCodecVersions,
68
67
  SharedTreeCore,
69
68
  } from "../shared-tree-core/index.js";
@@ -189,6 +188,10 @@ const formatVersionToTopLevelCodecVersions = new Map<number, ExplicitCodecVersio
189
188
  5,
190
189
  { forest: 1, schema: 2, detachedFieldIndex: 1, editManager: 4, message: 4, fieldBatch: 1 },
191
190
  ],
191
+ [
192
+ 100, // SharedTreeFormatVersion.vSharedBranches
193
+ { forest: 1, schema: 2, detachedFieldIndex: 1, editManager: 5, message: 5, fieldBatch: 1 },
194
+ ],
192
195
  ]);
193
196
 
194
197
  function getCodecVersions(formatVersion: number): ExplicitCodecVersions {
@@ -217,6 +220,8 @@ export class SharedTreeKernel
217
220
  return this.checkout.storedSchema;
218
221
  }
219
222
 
223
+ private readonly checkouts: Map<BranchId, TreeCheckout> = new Map();
224
+
220
225
  /**
221
226
  * The app-facing API for SharedTree implemented by this Kernel.
222
227
  * @remarks
@@ -232,7 +237,7 @@ export class SharedTreeKernel
232
237
  serializer: IFluidSerializer,
233
238
  submitLocalMessage: (content: unknown, localOpMetadata?: unknown) => void,
234
239
  lastSequenceNumber: () => number | undefined,
235
- logger: ITelemetryLoggerExt | undefined,
240
+ private readonly logger: ITelemetryLoggerExt | undefined,
236
241
  idCompressor: IIdCompressor,
237
242
  optionsParam: SharedTreeOptionsInternal,
238
243
  ) {
@@ -319,16 +324,12 @@ export class SharedTreeKernel
319
324
  idCompressor,
320
325
  schema,
321
326
  defaultSchemaPolicy,
322
- new DefaultResubmitMachine(
323
- (change: TaggedChange<SharedTreeChange>) =>
324
- changeFamily.rebaser.invert(change, true, this.mintRevisionTag()),
325
- changeEnricher,
326
- ),
327
+ undefined,
327
328
  changeEnricher,
328
329
  );
329
- const localBranch = this.getLocalBranch();
330
+
330
331
  this.checkout = createTreeCheckout(idCompressor, this.mintRevisionTag, revisionTagCodec, {
331
- branch: localBranch,
332
+ branch: this.getLocalBranch(),
332
333
  changeFamily,
333
334
  schema,
334
335
  forest,
@@ -340,39 +341,48 @@ export class SharedTreeKernel
340
341
  disposeForksAfterTransaction: options.disposeForksAfterTransaction,
341
342
  });
342
343
 
343
- this.checkout.transaction.events.on("started", () => {
344
- if (sharedObject.isAttached()) {
344
+ this.registerCheckout("main", this.checkout);
345
+
346
+ this.view = {
347
+ contentSnapshot: () => this.contentSnapshot(),
348
+ exportSimpleSchema: () => this.exportSimpleSchema(),
349
+ exportVerbose: () => this.exportVerbose(),
350
+ viewWith: this.viewWith.bind(this),
351
+ viewSharedBranchWith: this.viewBranchWith.bind(this),
352
+ createSharedBranch: this.createSharedBranch.bind(this),
353
+ kernel: this,
354
+ };
355
+ }
356
+
357
+ private registerCheckout(branchId: BranchId, checkout: TreeCheckout): void {
358
+ this.checkouts.set(branchId, checkout);
359
+ const enricher = this.getCommitEnricher(branchId);
360
+ checkout.transaction.events.on("started", () => {
361
+ if (this.sharedObject.isAttached()) {
345
362
  // It is currently forbidden to attach during a transaction, so transaction state changes can be ignored until after attaching.
346
- this.commitEnricher.startTransaction();
363
+ enricher.startTransaction();
347
364
  }
348
365
  });
349
- this.checkout.transaction.events.on("aborting", () => {
350
- if (sharedObject.isAttached()) {
366
+
367
+ checkout.transaction.events.on("aborting", () => {
368
+ if (this.sharedObject.isAttached()) {
351
369
  // It is currently forbidden to attach during a transaction, so transaction state changes can be ignored until after attaching.
352
- this.commitEnricher.abortTransaction();
370
+ enricher.abortTransaction();
353
371
  }
354
372
  });
355
- this.checkout.transaction.events.on("committing", () => {
356
- if (sharedObject.isAttached()) {
373
+ checkout.transaction.events.on("committing", () => {
374
+ if (this.sharedObject.isAttached()) {
357
375
  // It is currently forbidden to attach during a transaction, so transaction state changes can be ignored until after attaching.
358
- this.commitEnricher.commitTransaction();
376
+ enricher.commitTransaction();
359
377
  }
360
378
  });
361
- this.checkout.events.on("beforeBatch", (event) => {
362
- if (event.type === "append" && sharedObject.isAttached()) {
363
- if (this.checkout.transaction.isInProgress()) {
364
- this.commitEnricher.addTransactionCommits(event.newCommits);
379
+ checkout.events.on("beforeBatch", (event) => {
380
+ if (event.type === "append" && this.sharedObject.isAttached()) {
381
+ if (checkout.transaction.isInProgress()) {
382
+ enricher.addTransactionCommits(event.newCommits);
365
383
  }
366
384
  }
367
385
  });
368
-
369
- this.view = {
370
- contentSnapshot: () => this.contentSnapshot(),
371
- exportSimpleSchema: () => this.exportSimpleSchema(),
372
- exportVerbose: () => this.exportVerbose(),
373
- viewWith: this.viewWith.bind(this),
374
- kernel: this,
375
- };
376
386
  }
377
387
 
378
388
  public exportVerbose(): VerboseTree | undefined {
@@ -415,18 +425,56 @@ export class SharedTreeKernel
415
425
  TreeView<ReadSchema<TRoot>>;
416
426
  }
417
427
 
428
+ public viewBranchWith<TRoot extends ImplicitFieldSchema>(
429
+ branchId: string,
430
+ config: TreeViewConfiguration<TRoot>,
431
+ ): TreeView<TRoot>;
432
+
433
+ public viewBranchWith<TRoot extends ImplicitFieldSchema | UnsafeUnknownSchema>(
434
+ branchId: string,
435
+ config: TreeViewConfiguration<ReadSchema<TRoot>>,
436
+ ): SchematizingSimpleTreeView<TRoot> & TreeView<ReadSchema<TRoot>> {
437
+ const compressedId = this.idCompressor.tryRecompress(branchId as StableId);
438
+ if (compressedId === undefined) {
439
+ throw new UsageError(`No branch found with id: ${branchId}`);
440
+ }
441
+ return this.getCheckout(compressedId).viewWith(
442
+ config,
443
+ ) as SchematizingSimpleTreeView<TRoot> & TreeView<ReadSchema<TRoot>>;
444
+ }
445
+
446
+ private getCheckout(branchId: BranchId): TreeCheckout {
447
+ return this.checkouts.get(branchId) ?? this.checkoutBranch(branchId);
448
+ }
449
+
450
+ private checkoutBranch(branchId: BranchId): TreeCheckout {
451
+ const checkout = this.checkout.branch();
452
+ checkout.switchBranch(this.getSharedBranch(branchId));
453
+ const enricher = new SharedTreeReadonlyChangeEnricher(
454
+ checkout.forest,
455
+ checkout.storedSchema,
456
+ checkout.removedRoots,
457
+ );
458
+
459
+ this.registerSharedBranchForEditing(branchId, enricher);
460
+ this.registerCheckout(branchId, checkout);
461
+ return checkout;
462
+ }
463
+
418
464
  public override async loadCore(services: IChannelStorageService): Promise<void> {
419
465
  await super.loadCore(services);
420
466
  this.checkout.load();
421
467
  }
422
468
 
423
469
  public override didAttach(): void {
424
- if (this.checkout.transaction.isInProgress()) {
425
- // Attaching during a transaction is not currently supported.
426
- // At least part of of the system is known to not handle this case correctly - commit enrichment - and there may be others.
427
- throw new UsageError(
428
- "Cannot attach while a transaction is in progress. Commit or abort the transaction before attaching.",
429
- );
470
+ for (const checkout of this.checkouts.values()) {
471
+ if (checkout.transaction.isInProgress()) {
472
+ // Attaching during a transaction is not currently supported.
473
+ // At least part of of the system is known to not handle this case correctly - commit enrichment - and there may be others.
474
+ throw new UsageError(
475
+ "Cannot attach while a transaction is in progress. Commit or abort the transaction before attaching.",
476
+ );
477
+ }
430
478
  }
431
479
  super.didAttach();
432
480
  }
@@ -436,31 +484,35 @@ export class SharedTreeKernel
436
484
  SharedTreeCore<SharedTreeEditBuilder, SharedTreeChange>["applyStashedOp"]
437
485
  >
438
486
  ): void {
439
- assert(
440
- !this.checkout.transaction.isInProgress(),
441
- 0x674 /* Unexpected transaction is open while applying stashed ops */,
442
- );
487
+ for (const checkout of this.checkouts.values()) {
488
+ assert(
489
+ !checkout.transaction.isInProgress(),
490
+ 0x674 /* Unexpected transaction is open while applying stashed ops */,
491
+ );
492
+ }
443
493
  super.applyStashedOp(...args);
444
494
  }
445
495
 
446
496
  protected override submitCommit(
497
+ branchId: BranchId,
447
498
  commit: GraphCommit<SharedTreeChange>,
448
499
  schemaAndPolicy: ClonableSchemaAndPolicy,
449
500
  isResubmit: boolean,
450
501
  ): void {
502
+ const checkout = this.getCheckout(branchId);
451
503
  assert(
452
- !this.checkout.transaction.isInProgress(),
504
+ !checkout.transaction.isInProgress(),
453
505
  0xaa6 /* Cannot submit a commit while a transaction is in progress */,
454
506
  );
455
507
  if (isResubmit) {
456
- return super.submitCommit(commit, schemaAndPolicy, isResubmit);
508
+ return super.submitCommit(branchId, commit, schemaAndPolicy, isResubmit);
457
509
  }
458
510
 
459
511
  // Refrain from submitting new commits until they are validated by the checkout.
460
512
  // This is not a strict requirement for correctness in our system, but in the event that there is a bug when applying commits to the checkout
461
513
  // that causes a crash (e.g. in the forest), this will at least prevent this client from sending the problematic commit to any other clients.
462
- this.checkout.onCommitValid(commit, () =>
463
- super.submitCommit(commit, schemaAndPolicy, isResubmit),
514
+ checkout.onCommitValid(commit, () =>
515
+ super.submitCommit(branchId, commit, schemaAndPolicy, isResubmit),
464
516
  );
465
517
  }
466
518
 
@@ -561,6 +613,11 @@ export const SharedTreeFormatVersion = {
561
613
  * Requires \@fluidframework/tree \>= 2.0.0.
562
614
  */
563
615
  v5: 5,
616
+
617
+ /**
618
+ * For testing purposes only.
619
+ */
620
+ vSharedBranches: 100,
564
621
  } as const;
565
622
 
566
623
  /**
@@ -47,6 +47,7 @@ import {
47
47
  type TreeNodeSchemaIdentifier,
48
48
  type TreeNodeStoredSchema,
49
49
  LeafNodeStoredSchema,
50
+ diffHistories,
50
51
  } from "../core/index.js";
51
52
  import {
52
53
  type FieldBatchCodec,
@@ -310,6 +311,9 @@ export function createTreeCheckout(
310
311
  args?.chunkCompressionStrategy,
311
312
  idCompressor,
312
313
  );
314
+
315
+ // TODO: If a branch is passed in, is it supposed to be local main?
316
+ // Otherwise shouldn't we set `isSharedBranch` to false?
313
317
  const branch =
314
318
  args?.branch ??
315
319
  new SharedTreeBranch(
@@ -323,7 +327,7 @@ export function createTreeCheckout(
323
327
 
324
328
  return new TreeCheckout(
325
329
  branch,
326
- false,
330
+ true,
327
331
  changeFamily,
328
332
  schema,
329
333
  forest,
@@ -366,7 +370,7 @@ export interface RevertMetrics {
366
370
  export class TreeCheckout implements ITreeCheckoutFork {
367
371
  public disposed = false;
368
372
 
369
- private readonly editLock: EditLock;
373
+ private editLock: EditLock;
370
374
 
371
375
  private readonly views = new Set<TreeView<ImplicitFieldSchema>>();
372
376
 
@@ -396,15 +400,15 @@ export class TreeCheckout implements ITreeCheckoutFork {
396
400
 
397
401
  public constructor(
398
402
  branch: SharedTreeBranch<SharedTreeEditBuilder, SharedTreeChange>,
399
- /** True if and only if this checkout is for a forked branch and not the "main branch" of the tree. */
400
- public readonly isBranch: boolean,
403
+ /** True if and only if this checkout is for a branch which is persisted and shared with other clients. */
404
+ public readonly isSharedBranch: boolean,
401
405
  private readonly changeFamily: ChangeFamily<SharedTreeEditBuilder, SharedTreeChange>,
402
406
  public readonly storedSchema: TreeStoredSchemaRepository,
403
407
  public readonly forest: IEditableForest,
404
408
  private readonly mintRevisionTag: () => RevisionTag,
405
409
  private readonly revisionTagCodec: RevisionTagCodec,
406
410
  private readonly idCompressor: IIdCompressor,
407
- private removedRoots: DetachedFieldIndex = makeDetachedFieldIndex(
411
+ public removedRoots: DetachedFieldIndex = makeDetachedFieldIndex(
408
412
  "repair",
409
413
  revisionTagCodec,
410
414
  idCompressor,
@@ -412,9 +416,29 @@ export class TreeCheckout implements ITreeCheckoutFork {
412
416
  /** Optional logger for telemetry. */
413
417
  private readonly logger?: ITelemetryLoggerExt,
414
418
  public readonly breaker: Breakable = new Breakable("TreeCheckout"),
415
- private readonly disposeForksAfterTransaction = true,
419
+ public readonly disposeForksAfterTransaction = true,
416
420
  ) {
417
- this.#transaction = new SquashingTransactionStack(
421
+ this.#transaction = this.createTransactionStack(branch);
422
+ this.editLock = new EditLock(this.#transaction.activeBranchEditor);
423
+ this.registerForBranchEvents();
424
+ }
425
+
426
+ private registerForBranchEvents(): void {
427
+ this.#transaction.branch.events.on("afterChange", this.onAfterBranchChange);
428
+ this.#transaction.activeBranchEvents.on("afterChange", this.onAfterChange);
429
+ this.#transaction.activeBranchEvents.on("ancestryTrimmed", this.onAncestryTrimmed);
430
+ }
431
+
432
+ private unregisterFromBranchEvents(): void {
433
+ this.#transaction.branch.events.off("afterChange", this.onAfterBranchChange);
434
+ this.#transaction.activeBranchEvents.off("afterChange", this.onAfterChange);
435
+ this.#transaction.activeBranchEvents.off("ancestryTrimmed", this.onAncestryTrimmed);
436
+ }
437
+
438
+ private createTransactionStack(
439
+ branch: SharedTreeBranch<SharedTreeEditBuilder, SharedTreeChange>,
440
+ ): SquashingTransactionStack<SharedTreeEditBuilder, SharedTreeChange> {
441
+ return new SquashingTransactionStack(
418
442
  branch,
419
443
  (commits) => {
420
444
  const revision = this.mintRevisionTag();
@@ -450,58 +474,6 @@ export class TreeCheckout implements ITreeCheckoutFork {
450
474
  };
451
475
  },
452
476
  );
453
-
454
- this.editLock = new EditLock(this.#transaction.activeBranchEditor);
455
-
456
- branch.events.on("afterChange", (event) => {
457
- // The following logic allows revertibles to be generated for the change.
458
- // Currently only appends (including merges and transaction commits) are supported.
459
- if (event.type === "append") {
460
- // TODO:#20949: When the SharedTree is detached, these commits will already have been garbage collected.
461
- // Figure out a way to generate revertibles before the commits are garbage collected.
462
- for (const commit of event.newCommits) {
463
- const kind = event.type === "append" ? event.kind : CommitKind.Default;
464
- const { change, revision } = commit;
465
-
466
- const getRevertible = hasSchemaChange(change)
467
- ? undefined
468
- : (onRevertibleDisposed?: (revertible: RevertibleAlpha) => void) => {
469
- if (!withinEventContext) {
470
- throw new UsageError(
471
- "Cannot get a revertible outside of the context of a changed event.",
472
- );
473
- }
474
- if (this.revertibleCommitBranches.get(revision) !== undefined) {
475
- throw new UsageError(
476
- "Cannot generate the same revertible more than once. Note that this can happen when multiple changed event listeners are registered.",
477
- );
478
- }
479
- const revertible = this.createRevertible(
480
- revision,
481
- kind,
482
- this,
483
- onRevertibleDisposed,
484
- );
485
- this.revertibleCommitBranches.set(
486
- revision,
487
- this.#transaction.activeBranch.fork(commit),
488
- );
489
- this.revertibles.add(revertible);
490
- return revertible;
491
- };
492
-
493
- let withinEventContext = true;
494
- this.#events.emit("changed", { isLocal: true, kind }, getRevertible);
495
- withinEventContext = false;
496
- }
497
- } else if (this.isRemoteChangeEvent(event)) {
498
- // TODO: figure out how to plumb through commit kind info for remote changes
499
- this.#events.emit("changed", { isLocal: false, kind: CommitKind.Default });
500
- }
501
- });
502
-
503
- this.#transaction.activeBranchEvents.on("afterChange", this.onAfterChange);
504
- this.#transaction.activeBranchEvents.on("ancestryTrimmed", this.onAncestryTrimmed);
505
477
  }
506
478
 
507
479
  public exportVerbose(): VerboseTree | undefined {
@@ -522,6 +494,55 @@ export class TreeCheckout implements ITreeCheckoutFork {
522
494
  }
523
495
  }
524
496
 
497
+ private readonly onAfterBranchChange = (
498
+ event: SharedTreeBranchChange<SharedTreeChange>,
499
+ ): void => {
500
+ // The following logic allows revertibles to be generated for the change.
501
+ // Currently only appends (including merges and transaction commits) are supported.
502
+ if (event.type === "append") {
503
+ // TODO:#20949: When the SharedTree is detached, these commits will already have been garbage collected.
504
+ // Figure out a way to generate revertibles before the commits are garbage collected.
505
+ for (const commit of event.newCommits) {
506
+ const kind = event.type === "append" ? event.kind : CommitKind.Default;
507
+ const { change, revision } = commit;
508
+
509
+ const getRevertible = hasSchemaChange(change)
510
+ ? undefined
511
+ : (onRevertibleDisposed?: (revertible: RevertibleAlpha) => void) => {
512
+ if (!withinEventContext) {
513
+ throw new UsageError(
514
+ "Cannot get a revertible outside of the context of a changed event.",
515
+ );
516
+ }
517
+ if (this.revertibleCommitBranches.get(revision) !== undefined) {
518
+ throw new UsageError(
519
+ "Cannot generate the same revertible more than once. Note that this can happen when multiple changed event listeners are registered.",
520
+ );
521
+ }
522
+ const revertible = this.createRevertible(
523
+ revision,
524
+ kind,
525
+ this,
526
+ onRevertibleDisposed,
527
+ );
528
+ this.revertibleCommitBranches.set(
529
+ revision,
530
+ this.#transaction.activeBranch.fork(commit),
531
+ );
532
+ this.revertibles.add(revertible);
533
+ return revertible;
534
+ };
535
+
536
+ let withinEventContext = true;
537
+ this.#events.emit("changed", { isLocal: true, kind }, getRevertible);
538
+ withinEventContext = false;
539
+ }
540
+ } else if (this.isRemoteChangeEvent(event)) {
541
+ // TODO: figure out how to plumb through commit kind info for remote changes
542
+ this.#events.emit("changed", { isLocal: false, kind: CommitKind.Default });
543
+ }
544
+ };
545
+
525
546
  private readonly onAfterChange = (event: SharedTreeBranchChange<SharedTreeChange>): void => {
526
547
  this.editLock.lock();
527
548
  this.#events.emit("beforeBatch", event);
@@ -531,34 +552,7 @@ export class TreeCheckout implements ITreeCheckoutFork {
531
552
  ? this.#transaction.activeBranch.getHead().revision
532
553
  : event.change.revision;
533
554
 
534
- // Conflicts due to schema will be empty and thus are not applied.
535
- for (const change of event.change.change.changes) {
536
- if (change.type === "data") {
537
- const delta = intoDelta(tagChange(change.innerChange, revision));
538
- this.withCombinedVisitor((visitor) => {
539
- visitDelta(delta, visitor, this.removedRoots, revision);
540
- });
541
- } else if (change.type === "schema") {
542
- // Schema changes from a current to a new schema are expected to be backwards compatible.
543
- // This guarantees that all data in the forest (which is valid before the schema change)
544
- // is also valid under the new schema.
545
- // Note however, that such schema changes may in some cases be rolled back:
546
- // Case 1: A transaction with a schema change may be aborted.
547
- // The transaction may have made some data changes that would render some trees invalid
548
- // under the old schema, but these changes will also be rolled back, thereby putting the forest
549
- // back in the state before the transaction, which is valid under the original (reinstated) schema.
550
- // Case 2: A branch with a schema change may be rebased such that the schema change (because
551
- // of a constraint) is no longer applied.
552
- // Such a branch may contain data changes that would render some trees invalid under the
553
- // original schema. These data changes may not necessarily be rolled back.
554
- // They will however be rebased over the rollback of the schema change. This rebasing will
555
- // ensure that these data changes are muted if they would render some trees invalid under the
556
- // original (reinstated) schema.
557
- this.storedSchema.apply(change.innerChange.schema.new);
558
- } else {
559
- fail(0xad1 /* Unknown Shared Tree change type. */);
560
- }
561
- }
555
+ this.applyChange(event.change.change, revision);
562
556
  }
563
557
  this.#events.emit("afterBatch");
564
558
  this.editLock.unlock();
@@ -567,6 +561,38 @@ export class TreeCheckout implements ITreeCheckoutFork {
567
561
  }
568
562
  };
569
563
 
564
+ // Revision is the revision of the commit, if any, which caused this change.
565
+ private applyChange(change: SharedTreeChange, revision?: RevisionTag): void {
566
+ // Conflicts due to schema will be empty and thus are not applied.
567
+ for (const innerChange of change.changes) {
568
+ if (innerChange.type === "data") {
569
+ const delta = intoDelta(tagChange(innerChange.innerChange, revision));
570
+ this.withCombinedVisitor((visitor) => {
571
+ visitDelta(delta, visitor, this.removedRoots, revision);
572
+ });
573
+ } else if (innerChange.type === "schema") {
574
+ // Schema changes from a current to a new schema are expected to be backwards compatible.
575
+ // This guarantees that all data in the forest (which is valid before the schema change)
576
+ // is also valid under the new schema.
577
+ // Note however, that such schema changes may in some cases be rolled back:
578
+ // Case 1: A transaction with a schema change may be aborted.
579
+ // The transaction may have made some data changes that would render some trees invalid
580
+ // under the old schema, but these changes will also be rolled back, thereby putting the forest
581
+ // back in the state before the transaction, which is valid under the original (reinstated) schema.
582
+ // Case 2: A branch with a schema change may be rebased such that the schema change (because
583
+ // of a constraint) is no longer applied.
584
+ // Such a branch may contain data changes that would render some trees invalid under the
585
+ // original schema. These data changes may not necessarily be rolled back.
586
+ // They will however be rebased over the rollback of the schema change. This rebasing will
587
+ // ensure that these data changes are muted if they would render some trees invalid under the
588
+ // original (reinstated) schema.
589
+ this.storedSchema.apply(innerChange.innerChange.schema.new);
590
+ } else {
591
+ fail(0xad1 /* Unknown Shared Tree change type. */);
592
+ }
593
+ }
594
+ }
595
+
570
596
  private readonly onAncestryTrimmed = (revisions: RevisionTag[]): void => {
571
597
  // When the branch is trimmed, we can garbage collect any repair data whose latest relevant revision is one of the
572
598
  // trimmed revisions.
@@ -730,7 +756,7 @@ export class TreeCheckout implements ITreeCheckoutFork {
730
756
  * To avoid updating observers of the view state with intermediate results during a transaction,
731
757
  * use {@link ITreeCheckout#branch} and {@link ISharedTreeFork#merge}.
732
758
  */
733
- readonly #transaction: SquashingTransactionStack<SharedTreeEditBuilder, SharedTreeChange>;
759
+ #transaction: SquashingTransactionStack<SharedTreeEditBuilder, SharedTreeChange>;
734
760
 
735
761
  public branch(): TreeCheckout {
736
762
  this.checkNotDisposed(
@@ -743,7 +769,7 @@ export class TreeCheckout implements ITreeCheckoutFork {
743
769
  const forest = this.forest.clone(storedSchema, anchors);
744
770
  const checkout = new TreeCheckout(
745
771
  branch,
746
- true,
772
+ false,
747
773
  this.changeFamily,
748
774
  storedSchema,
749
775
  forest,
@@ -759,6 +785,29 @@ export class TreeCheckout implements ITreeCheckoutFork {
759
785
  return checkout;
760
786
  }
761
787
 
788
+ public switchBranch(
789
+ branch: SharedTreeBranch<SharedTreeEditBuilder, SharedTreeChange>,
790
+ ): void {
791
+ // TODO: Dispose old branch, if necessary
792
+ assert(!this.#transaction.isInProgress(), "Cannot switch branches during a transaction");
793
+ const diff = diffHistories(
794
+ this.changeFamily.rebaser,
795
+ this.#transaction.branch.getHead(),
796
+ branch.getHead(),
797
+ this.mintRevisionTag,
798
+ );
799
+
800
+ this.unregisterFromBranchEvents();
801
+
802
+ this.#transaction = this.createTransactionStack(branch);
803
+ this.editLock = new EditLock(this.#transaction.activeBranchEditor);
804
+ this.registerForBranchEvents();
805
+
806
+ // TODO: Rework eventing
807
+ this.applyChange(diff);
808
+ this.#events.emit("afterBatch");
809
+ }
810
+
762
811
  public rebase(checkout: TreeCheckout): void {
763
812
  this.checkNotDisposed(
764
813
  "The target of the branch rebase has been disposed and cannot be rebased.",
@@ -772,8 +821,8 @@ export class TreeCheckout implements ITreeCheckoutFork {
772
821
  0x9af /* A view cannot be rebased while it has a pending transaction */,
773
822
  );
774
823
  assert(
775
- checkout.isBranch,
776
- 0xa5d /* The main branch cannot be rebased onto another branch. */,
824
+ !checkout.isSharedBranch,
825
+ 0xa5d /* Shared branches cannot be rebased onto another branch. */,
777
826
  );
778
827
 
779
828
  checkout.#transaction.activeBranch.rebaseOnto(this.#transaction.activeBranch);
@@ -804,8 +853,8 @@ export class TreeCheckout implements ITreeCheckoutFork {
804
853
  checkout.transaction.commit();
805
854
  }
806
855
  this.#transaction.activeBranch.merge(checkout.#transaction.activeBranch);
807
- if (disposeMerged && checkout.isBranch) {
808
- // Dispose the merged checkout unless it is the main branch.
856
+ if (disposeMerged && !checkout.isSharedBranch) {
857
+ // Dispose the merged checkout unless it is a shared branch.
809
858
  checkout[disposeSymbol]();
810
859
  }
811
860
  }
@@ -961,10 +1010,10 @@ export class TreeCheckout implements ITreeCheckoutFork {
961
1010
  */
962
1011
  private isRemoteChangeEvent(event: SharedTreeBranchChange<SharedTreeChange>): boolean {
963
1012
  return (
964
- // Remote changes are only ever applied to the main branch
965
- !this.isBranch &&
966
- // Remote changes are applied to the main branch by rebasing it onto the trunk.
967
- // No other rebases are allowed on the main branch, so we can use this to detect remote changes.
1013
+ // Remote changes are only ever applied to shared branches
1014
+ this.isSharedBranch &&
1015
+ // Remote changes are applied to the branch by rebasing it onto the trunk.
1016
+ // No other rebases are allowed on shared branches, so we can use this to detect remote changes.
968
1017
  event.type === "rebase"
969
1018
  );
970
1019
  }
@@ -1020,7 +1069,7 @@ class EditLock {
1020
1069
  * Edits the tree by calling the methods of the editor passed into the {@link EditLock} constructor.
1021
1070
  * @remarks Edits will throw an error if the lock is currently locked.
1022
1071
  */
1023
- public editor: ISharedTreeEditor;
1072
+ public readonly editor: ISharedTreeEditor;
1024
1073
  private locked = false;
1025
1074
 
1026
1075
  /**
@@ -24,6 +24,13 @@ import {
24
24
  type RebaseStatsWithDuration,
25
25
  } from "../core/index.js";
26
26
  import { hasSome, defineLazyCachedProperty } from "../util/index.js";
27
+ import type {
28
+ OpSpaceCompressedId,
29
+ SessionSpaceCompressedId,
30
+ } from "@fluidframework/id-compressor";
31
+
32
+ export type BranchId = SessionSpaceCompressedId | "main";
33
+ export type EncodedBranchId = OpSpaceCompressedId;
27
34
 
28
35
  /**
29
36
  * Describes a change to a `SharedTreeBranch`. Each of the following event types provides a `change` which contains the net change to the branch (or is undefined if there was no net change):
@@ -0,0 +1,28 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import type {
7
+ IIdCompressor,
8
+ OpSpaceCompressedId,
9
+ SessionId,
10
+ } from "@fluidframework/id-compressor";
11
+ import type { BranchId } from "./branch.js";
12
+
13
+ export function encodeBranchId(
14
+ idCompressor: IIdCompressor,
15
+ branchId: BranchId,
16
+ ): OpSpaceCompressedId | undefined {
17
+ return branchId === "main" ? undefined : idCompressor.normalizeToOpSpace(branchId);
18
+ }
19
+
20
+ export function decodeBranchId(
21
+ idCompressor: IIdCompressor,
22
+ encoded: OpSpaceCompressedId | undefined,
23
+ context: { readonly originatorId: SessionId },
24
+ ): BranchId {
25
+ return encoded === undefined
26
+ ? "main"
27
+ : idCompressor.normalizeToSessionSpace(encoded, context.originatorId);
28
+ }