@fluidframework/tree 2.116.1 → 2.117.0

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 (362) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/api-report/tree.alpha.api.md +78 -30
  3. package/api-report/tree.beta.api.md +12 -9
  4. package/api-report/tree.legacy.beta.api.md +12 -9
  5. package/dist/codec/codec.d.ts +18 -0
  6. package/dist/codec/codec.d.ts.map +1 -1
  7. package/dist/codec/codec.js +18 -0
  8. package/dist/codec/codec.js.map +1 -1
  9. package/dist/core/index.d.ts +2 -2
  10. package/dist/core/index.d.ts.map +1 -1
  11. package/dist/core/index.js +3 -2
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/core/rebase/index.d.ts +1 -1
  14. package/dist/core/rebase/index.d.ts.map +1 -1
  15. package/dist/core/rebase/index.js +2 -1
  16. package/dist/core/rebase/index.js.map +1 -1
  17. package/dist/core/rebase/types.d.ts +39 -2
  18. package/dist/core/rebase/types.d.ts.map +1 -1
  19. package/dist/core/rebase/types.js +37 -2
  20. package/dist/core/rebase/types.js.map +1 -1
  21. package/dist/core/rebase/utils.d.ts.map +1 -1
  22. package/dist/core/rebase/utils.js +1 -0
  23. package/dist/core/rebase/utils.js.map +1 -1
  24. package/dist/core/revertible.d.ts +62 -6
  25. package/dist/core/revertible.d.ts.map +1 -1
  26. package/dist/core/revertible.js.map +1 -1
  27. package/dist/entrypoints/alpha.d.ts +1 -1
  28. package/dist/entrypoints/alpha.d.ts.map +1 -1
  29. package/dist/entrypoints/alpha.js.map +1 -1
  30. package/dist/entrypoints/beta.d.ts +1 -1
  31. package/dist/entrypoints/beta.d.ts.map +1 -1
  32. package/dist/entrypoints/beta.js.map +1 -1
  33. package/dist/entrypoints/legacy.d.ts +1 -1
  34. package/dist/entrypoints/legacy.d.ts.map +1 -1
  35. package/dist/entrypoints/legacy.js.map +1 -1
  36. package/dist/feature-libraries/indexing/types.d.ts +1 -1
  37. package/dist/feature-libraries/indexing/types.js.map +1 -1
  38. package/dist/index.d.ts +2 -2
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/packageVersion.d.ts +1 -1
  42. package/dist/packageVersion.js +1 -1
  43. package/dist/packageVersion.js.map +1 -1
  44. package/dist/shared-tree/history.d.ts +22 -0
  45. package/dist/shared-tree/history.d.ts.map +1 -0
  46. package/dist/shared-tree/history.js +66 -0
  47. package/dist/shared-tree/history.js.map +1 -0
  48. package/dist/shared-tree/schematizingTreeView.d.ts +12 -7
  49. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  50. package/dist/shared-tree/schematizingTreeView.js +13 -0
  51. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  52. package/dist/shared-tree/sharedTree.d.ts +3 -2
  53. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  54. package/dist/shared-tree/sharedTree.js +2 -0
  55. package/dist/shared-tree/sharedTree.js.map +1 -1
  56. package/dist/shared-tree/tree.js +1 -1
  57. package/dist/shared-tree/tree.js.map +1 -1
  58. package/dist/shared-tree/treeAlpha.d.ts +8 -20
  59. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  60. package/dist/shared-tree/treeAlpha.js +9 -12
  61. package/dist/shared-tree/treeAlpha.js.map +1 -1
  62. package/dist/shared-tree/treeCheckout.d.ts +16 -9
  63. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  64. package/dist/shared-tree/treeCheckout.js +122 -25
  65. package/dist/shared-tree/treeCheckout.js.map +1 -1
  66. package/dist/shared-tree/unhydratedTreeContext.d.ts +3 -2
  67. package/dist/shared-tree/unhydratedTreeContext.d.ts.map +1 -1
  68. package/dist/shared-tree/unhydratedTreeContext.js +3 -0
  69. package/dist/shared-tree/unhydratedTreeContext.js.map +1 -1
  70. package/dist/shared-tree-core/branch.d.ts +16 -2
  71. package/dist/shared-tree-core/branch.d.ts.map +1 -1
  72. package/dist/shared-tree-core/branch.js +20 -2
  73. package/dist/shared-tree-core/branch.js.map +1 -1
  74. package/dist/shared-tree-core/branchCommitCounter.d.ts +31 -0
  75. package/dist/shared-tree-core/branchCommitCounter.d.ts.map +1 -0
  76. package/dist/shared-tree-core/branchCommitCounter.js +79 -0
  77. package/dist/shared-tree-core/branchCommitCounter.js.map +1 -0
  78. package/dist/shared-tree-core/customMetadataCodec.d.ts +9 -0
  79. package/dist/shared-tree-core/customMetadataCodec.d.ts.map +1 -0
  80. package/dist/shared-tree-core/customMetadataCodec.js +37 -0
  81. package/dist/shared-tree-core/customMetadataCodec.js.map +1 -0
  82. package/dist/shared-tree-core/customMetadataFormat.d.ts +18 -0
  83. package/dist/shared-tree-core/customMetadataFormat.d.ts.map +1 -0
  84. package/dist/shared-tree-core/customMetadataFormat.js +15 -0
  85. package/dist/shared-tree-core/customMetadataFormat.js.map +1 -0
  86. package/dist/shared-tree-core/editManager.d.ts.map +1 -1
  87. package/dist/shared-tree-core/editManager.js +15 -3
  88. package/dist/shared-tree-core/editManager.js.map +1 -1
  89. package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  90. package/dist/shared-tree-core/editManagerCodecs.js +5 -0
  91. package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
  92. package/dist/shared-tree-core/editManagerCodecsCommons.d.ts +1 -1
  93. package/dist/shared-tree-core/editManagerCodecsCommons.d.ts.map +1 -1
  94. package/dist/shared-tree-core/editManagerCodecsCommons.js +17 -5
  95. package/dist/shared-tree-core/editManagerCodecsCommons.js.map +1 -1
  96. package/dist/shared-tree-core/editManagerCodecsV1toV4.d.ts.map +1 -1
  97. package/dist/shared-tree-core/editManagerCodecsV1toV4.js +4 -2
  98. package/dist/shared-tree-core/editManagerCodecsV1toV4.js.map +1 -1
  99. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.d.ts.map +1 -1
  100. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.js +2 -2
  101. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.js.map +1 -1
  102. package/dist/shared-tree-core/editManagerFormatCommons.d.ts +17 -6
  103. package/dist/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
  104. package/dist/shared-tree-core/editManagerFormatCommons.js +18 -8
  105. package/dist/shared-tree-core/editManagerFormatCommons.js.map +1 -1
  106. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts +7 -5
  107. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
  108. package/dist/shared-tree-core/editManagerFormatV1toV4.js +4 -3
  109. package/dist/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
  110. package/dist/shared-tree-core/editManagerFormatVSharedBranches.d.ts +4 -0
  111. package/dist/shared-tree-core/editManagerFormatVSharedBranches.d.ts.map +1 -1
  112. package/dist/shared-tree-core/editManagerFormatVSharedBranches.js +2 -2
  113. package/dist/shared-tree-core/editManagerFormatVSharedBranches.js.map +1 -1
  114. package/dist/shared-tree-core/index.d.ts +2 -1
  115. package/dist/shared-tree-core/index.d.ts.map +1 -1
  116. package/dist/shared-tree-core/index.js +3 -1
  117. package/dist/shared-tree-core/index.js.map +1 -1
  118. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts +2 -2
  119. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
  120. package/dist/shared-tree-core/messageCodecV1ToV4.js +12 -3
  121. package/dist/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
  122. package/dist/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -1
  123. package/dist/shared-tree-core/messageCodecVSharedBranches.js +8 -2
  124. package/dist/shared-tree-core/messageCodecVSharedBranches.js.map +1 -1
  125. package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
  126. package/dist/shared-tree-core/messageCodecs.js +5 -0
  127. package/dist/shared-tree-core/messageCodecs.js.map +1 -1
  128. package/dist/shared-tree-core/messageFormat.d.ts +1 -0
  129. package/dist/shared-tree-core/messageFormat.d.ts.map +1 -1
  130. package/dist/shared-tree-core/messageFormat.js +6 -0
  131. package/dist/shared-tree-core/messageFormat.js.map +1 -1
  132. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts +10 -3
  133. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
  134. package/dist/shared-tree-core/messageFormatV1ToV4.js +10 -2
  135. package/dist/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
  136. package/dist/shared-tree-core/messageFormatVSharedBranches.d.ts +7 -0
  137. package/dist/shared-tree-core/messageFormatVSharedBranches.d.ts.map +1 -1
  138. package/dist/shared-tree-core/messageFormatVSharedBranches.js +2 -0
  139. package/dist/shared-tree-core/messageFormatVSharedBranches.js.map +1 -1
  140. package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  141. package/dist/shared-tree-core/sharedTreeCore.js +4 -2
  142. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  143. package/dist/shared-tree-core/transaction.d.ts +9 -0
  144. package/dist/shared-tree-core/transaction.d.ts.map +1 -1
  145. package/dist/shared-tree-core/transaction.js +26 -4
  146. package/dist/shared-tree-core/transaction.js.map +1 -1
  147. package/dist/simple-tree/api/index.d.ts +1 -1
  148. package/dist/simple-tree/api/index.d.ts.map +1 -1
  149. package/dist/simple-tree/api/index.js.map +1 -1
  150. package/dist/simple-tree/api/transactionTypes.d.ts +28 -2
  151. package/dist/simple-tree/api/transactionTypes.d.ts.map +1 -1
  152. package/dist/simple-tree/api/transactionTypes.js.map +1 -1
  153. package/dist/simple-tree/api/tree.d.ts +180 -61
  154. package/dist/simple-tree/api/tree.d.ts.map +1 -1
  155. package/dist/simple-tree/api/tree.js.map +1 -1
  156. package/dist/simple-tree/index.d.ts +1 -1
  157. package/dist/simple-tree/index.d.ts.map +1 -1
  158. package/dist/simple-tree/index.js.map +1 -1
  159. package/dist/tableSchema.js +10 -10
  160. package/dist/tableSchema.js.map +1 -1
  161. package/lib/codec/codec.d.ts +18 -0
  162. package/lib/codec/codec.d.ts.map +1 -1
  163. package/lib/codec/codec.js +18 -0
  164. package/lib/codec/codec.js.map +1 -1
  165. package/lib/core/index.d.ts +2 -2
  166. package/lib/core/index.d.ts.map +1 -1
  167. package/lib/core/index.js +1 -1
  168. package/lib/core/index.js.map +1 -1
  169. package/lib/core/rebase/index.d.ts +1 -1
  170. package/lib/core/rebase/index.d.ts.map +1 -1
  171. package/lib/core/rebase/index.js +1 -1
  172. package/lib/core/rebase/index.js.map +1 -1
  173. package/lib/core/rebase/types.d.ts +39 -2
  174. package/lib/core/rebase/types.d.ts.map +1 -1
  175. package/lib/core/rebase/types.js +35 -1
  176. package/lib/core/rebase/types.js.map +1 -1
  177. package/lib/core/rebase/utils.d.ts.map +1 -1
  178. package/lib/core/rebase/utils.js +1 -0
  179. package/lib/core/rebase/utils.js.map +1 -1
  180. package/lib/core/revertible.d.ts +62 -6
  181. package/lib/core/revertible.d.ts.map +1 -1
  182. package/lib/core/revertible.js.map +1 -1
  183. package/lib/entrypoints/alpha.d.ts +1 -1
  184. package/lib/entrypoints/alpha.d.ts.map +1 -1
  185. package/lib/entrypoints/alpha.js.map +1 -1
  186. package/lib/entrypoints/beta.d.ts +1 -1
  187. package/lib/entrypoints/beta.d.ts.map +1 -1
  188. package/lib/entrypoints/beta.js.map +1 -1
  189. package/lib/entrypoints/legacy.d.ts +1 -1
  190. package/lib/entrypoints/legacy.d.ts.map +1 -1
  191. package/lib/entrypoints/legacy.js.map +1 -1
  192. package/lib/feature-libraries/indexing/types.d.ts +1 -1
  193. package/lib/feature-libraries/indexing/types.js.map +1 -1
  194. package/lib/index.d.ts +2 -2
  195. package/lib/index.d.ts.map +1 -1
  196. package/lib/index.js.map +1 -1
  197. package/lib/packageVersion.d.ts +1 -1
  198. package/lib/packageVersion.js +1 -1
  199. package/lib/packageVersion.js.map +1 -1
  200. package/lib/shared-tree/history.d.ts +22 -0
  201. package/lib/shared-tree/history.d.ts.map +1 -0
  202. package/lib/shared-tree/history.js +62 -0
  203. package/lib/shared-tree/history.js.map +1 -0
  204. package/lib/shared-tree/schematizingTreeView.d.ts +12 -7
  205. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  206. package/lib/shared-tree/schematizingTreeView.js +13 -0
  207. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  208. package/lib/shared-tree/sharedTree.d.ts +3 -2
  209. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  210. package/lib/shared-tree/sharedTree.js +2 -0
  211. package/lib/shared-tree/sharedTree.js.map +1 -1
  212. package/lib/shared-tree/tree.js +1 -1
  213. package/lib/shared-tree/tree.js.map +1 -1
  214. package/lib/shared-tree/treeAlpha.d.ts +8 -20
  215. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  216. package/lib/shared-tree/treeAlpha.js +9 -12
  217. package/lib/shared-tree/treeAlpha.js.map +1 -1
  218. package/lib/shared-tree/treeCheckout.d.ts +16 -9
  219. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  220. package/lib/shared-tree/treeCheckout.js +123 -26
  221. package/lib/shared-tree/treeCheckout.js.map +1 -1
  222. package/lib/shared-tree/unhydratedTreeContext.d.ts +3 -2
  223. package/lib/shared-tree/unhydratedTreeContext.d.ts.map +1 -1
  224. package/lib/shared-tree/unhydratedTreeContext.js +3 -0
  225. package/lib/shared-tree/unhydratedTreeContext.js.map +1 -1
  226. package/lib/shared-tree-core/branch.d.ts +16 -2
  227. package/lib/shared-tree-core/branch.d.ts.map +1 -1
  228. package/lib/shared-tree-core/branch.js +20 -2
  229. package/lib/shared-tree-core/branch.js.map +1 -1
  230. package/lib/shared-tree-core/branchCommitCounter.d.ts +31 -0
  231. package/lib/shared-tree-core/branchCommitCounter.d.ts.map +1 -0
  232. package/lib/shared-tree-core/branchCommitCounter.js +75 -0
  233. package/lib/shared-tree-core/branchCommitCounter.js.map +1 -0
  234. package/lib/shared-tree-core/customMetadataCodec.d.ts +9 -0
  235. package/lib/shared-tree-core/customMetadataCodec.d.ts.map +1 -0
  236. package/lib/shared-tree-core/customMetadataCodec.js +32 -0
  237. package/lib/shared-tree-core/customMetadataCodec.js.map +1 -0
  238. package/lib/shared-tree-core/customMetadataFormat.d.ts +18 -0
  239. package/lib/shared-tree-core/customMetadataFormat.d.ts.map +1 -0
  240. package/lib/shared-tree-core/customMetadataFormat.js +11 -0
  241. package/lib/shared-tree-core/customMetadataFormat.js.map +1 -0
  242. package/lib/shared-tree-core/editManager.d.ts.map +1 -1
  243. package/lib/shared-tree-core/editManager.js +16 -4
  244. package/lib/shared-tree-core/editManager.js.map +1 -1
  245. package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  246. package/lib/shared-tree-core/editManagerCodecs.js +5 -0
  247. package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
  248. package/lib/shared-tree-core/editManagerCodecsCommons.d.ts +1 -1
  249. package/lib/shared-tree-core/editManagerCodecsCommons.d.ts.map +1 -1
  250. package/lib/shared-tree-core/editManagerCodecsCommons.js +17 -5
  251. package/lib/shared-tree-core/editManagerCodecsCommons.js.map +1 -1
  252. package/lib/shared-tree-core/editManagerCodecsV1toV4.d.ts.map +1 -1
  253. package/lib/shared-tree-core/editManagerCodecsV1toV4.js +4 -2
  254. package/lib/shared-tree-core/editManagerCodecsV1toV4.js.map +1 -1
  255. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.d.ts.map +1 -1
  256. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.js +2 -2
  257. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.js.map +1 -1
  258. package/lib/shared-tree-core/editManagerFormatCommons.d.ts +17 -6
  259. package/lib/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
  260. package/lib/shared-tree-core/editManagerFormatCommons.js +18 -8
  261. package/lib/shared-tree-core/editManagerFormatCommons.js.map +1 -1
  262. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts +7 -5
  263. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
  264. package/lib/shared-tree-core/editManagerFormatV1toV4.js +4 -3
  265. package/lib/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
  266. package/lib/shared-tree-core/editManagerFormatVSharedBranches.d.ts +4 -0
  267. package/lib/shared-tree-core/editManagerFormatVSharedBranches.d.ts.map +1 -1
  268. package/lib/shared-tree-core/editManagerFormatVSharedBranches.js +2 -2
  269. package/lib/shared-tree-core/editManagerFormatVSharedBranches.js.map +1 -1
  270. package/lib/shared-tree-core/index.d.ts +2 -1
  271. package/lib/shared-tree-core/index.d.ts.map +1 -1
  272. package/lib/shared-tree-core/index.js +1 -0
  273. package/lib/shared-tree-core/index.js.map +1 -1
  274. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts +2 -2
  275. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
  276. package/lib/shared-tree-core/messageCodecV1ToV4.js +12 -3
  277. package/lib/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
  278. package/lib/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -1
  279. package/lib/shared-tree-core/messageCodecVSharedBranches.js +8 -2
  280. package/lib/shared-tree-core/messageCodecVSharedBranches.js.map +1 -1
  281. package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
  282. package/lib/shared-tree-core/messageCodecs.js +5 -0
  283. package/lib/shared-tree-core/messageCodecs.js.map +1 -1
  284. package/lib/shared-tree-core/messageFormat.d.ts +1 -0
  285. package/lib/shared-tree-core/messageFormat.d.ts.map +1 -1
  286. package/lib/shared-tree-core/messageFormat.js +6 -0
  287. package/lib/shared-tree-core/messageFormat.js.map +1 -1
  288. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts +10 -3
  289. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
  290. package/lib/shared-tree-core/messageFormatV1ToV4.js +10 -2
  291. package/lib/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
  292. package/lib/shared-tree-core/messageFormatVSharedBranches.d.ts +7 -0
  293. package/lib/shared-tree-core/messageFormatVSharedBranches.d.ts.map +1 -1
  294. package/lib/shared-tree-core/messageFormatVSharedBranches.js +2 -0
  295. package/lib/shared-tree-core/messageFormatVSharedBranches.js.map +1 -1
  296. package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  297. package/lib/shared-tree-core/sharedTreeCore.js +5 -3
  298. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  299. package/lib/shared-tree-core/transaction.d.ts +9 -0
  300. package/lib/shared-tree-core/transaction.d.ts.map +1 -1
  301. package/lib/shared-tree-core/transaction.js +27 -5
  302. package/lib/shared-tree-core/transaction.js.map +1 -1
  303. package/lib/simple-tree/api/index.d.ts +1 -1
  304. package/lib/simple-tree/api/index.d.ts.map +1 -1
  305. package/lib/simple-tree/api/index.js.map +1 -1
  306. package/lib/simple-tree/api/transactionTypes.d.ts +28 -2
  307. package/lib/simple-tree/api/transactionTypes.d.ts.map +1 -1
  308. package/lib/simple-tree/api/transactionTypes.js.map +1 -1
  309. package/lib/simple-tree/api/tree.d.ts +180 -61
  310. package/lib/simple-tree/api/tree.d.ts.map +1 -1
  311. package/lib/simple-tree/api/tree.js.map +1 -1
  312. package/lib/simple-tree/index.d.ts +1 -1
  313. package/lib/simple-tree/index.d.ts.map +1 -1
  314. package/lib/simple-tree/index.js.map +1 -1
  315. package/lib/tableSchema.js +10 -10
  316. package/lib/tableSchema.js.map +1 -1
  317. package/package.json +22 -22
  318. package/src/codec/codec.ts +19 -0
  319. package/src/core/index.ts +4 -0
  320. package/src/core/rebase/index.ts +2 -0
  321. package/src/core/rebase/types.ts +72 -2
  322. package/src/core/rebase/utils.ts +1 -0
  323. package/src/core/revertible.ts +67 -6
  324. package/src/entrypoints/alpha.ts +8 -0
  325. package/src/entrypoints/beta.ts +1 -0
  326. package/src/entrypoints/legacy.ts +1 -0
  327. package/src/feature-libraries/indexing/types.ts +1 -1
  328. package/src/index.ts +8 -0
  329. package/src/packageVersion.ts +1 -1
  330. package/src/shared-tree/history.ts +99 -0
  331. package/src/shared-tree/schematizingTreeView.ts +25 -8
  332. package/src/shared-tree/sharedTree.ts +5 -2
  333. package/src/shared-tree/tree.ts +1 -1
  334. package/src/shared-tree/treeAlpha.ts +17 -35
  335. package/src/shared-tree/treeCheckout.ts +170 -31
  336. package/src/shared-tree/unhydratedTreeContext.ts +6 -2
  337. package/src/shared-tree-core/branch.ts +34 -2
  338. package/src/shared-tree-core/branchCommitCounter.ts +103 -0
  339. package/src/shared-tree-core/customMetadataCodec.ts +42 -0
  340. package/src/shared-tree-core/customMetadataFormat.ts +39 -0
  341. package/src/shared-tree-core/editManager.ts +22 -3
  342. package/src/shared-tree-core/editManagerCodecs.ts +12 -0
  343. package/src/shared-tree-core/editManagerCodecsCommons.ts +41 -15
  344. package/src/shared-tree-core/editManagerCodecsV1toV4.ts +7 -1
  345. package/src/shared-tree-core/editManagerCodecsVSharedBranches.ts +2 -0
  346. package/src/shared-tree-core/editManagerFormatCommons.ts +46 -12
  347. package/src/shared-tree-core/editManagerFormatV1toV4.ts +13 -5
  348. package/src/shared-tree-core/editManagerFormatVSharedBranches.ts +2 -2
  349. package/src/shared-tree-core/index.ts +3 -0
  350. package/src/shared-tree-core/messageCodecV1ToV4.ts +18 -5
  351. package/src/shared-tree-core/messageCodecVSharedBranches.ts +9 -2
  352. package/src/shared-tree-core/messageCodecs.ts +12 -0
  353. package/src/shared-tree-core/messageFormat.ts +6 -0
  354. package/src/shared-tree-core/messageFormatV1ToV4.ts +21 -3
  355. package/src/shared-tree-core/messageFormatVSharedBranches.ts +8 -0
  356. package/src/shared-tree-core/sharedTreeCore.ts +5 -2
  357. package/src/shared-tree-core/transaction.ts +56 -4
  358. package/src/simple-tree/api/index.ts +5 -0
  359. package/src/simple-tree/api/transactionTypes.ts +29 -2
  360. package/src/simple-tree/api/tree.ts +199 -60
  361. package/src/simple-tree/index.ts +5 -0
  362. package/src/tableSchema.ts +9 -9
@@ -524,6 +524,7 @@ export const changeFormatVersionForEditManager = DependentFormatVersion.fromPair
524
524
  [EditManagerFormatVersion.v4, SharedTreeChangeFormatVersion.v4],
525
525
  [EditManagerFormatVersion.vSharedBranches, SharedTreeChangeFormatVersion.v4],
526
526
  [EditManagerFormatVersion.v6, SharedTreeChangeFormatVersion.v5],
527
+ [EditManagerFormatVersion.v7, SharedTreeChangeFormatVersion.v5],
527
528
  ]);
528
529
 
529
530
  /**
@@ -540,6 +541,7 @@ export const changeFormatVersionForMessage = DependentFormatVersion.fromPairs<
540
541
  [MessageFormatVersion.v4, SharedTreeChangeFormatVersion.v4],
541
542
  [MessageFormatVersion.vSharedBranches, SharedTreeChangeFormatVersion.v4],
542
543
  [MessageFormatVersion.v6, SharedTreeChangeFormatVersion.v5],
544
+ [MessageFormatVersion.v7, SharedTreeChangeFormatVersion.v5],
543
545
  ]);
544
546
 
545
547
  function getCodecTreeForEditManagerFormat(
@@ -659,8 +661,9 @@ export interface SharedTreeOptions
659
661
  * @remarks
660
662
  * By default, SharedTree evicts trunk commits once all peers have acknowledged them (i.e. once they
661
663
  * are outside the collaboration window), and they are not otherwise retained (e.g. by revertibles or
662
- * local branches), to bound memory usage. Enabling this flag retains the full trunk history for the
663
- * lifetime of the client, which increases memory usage over time and should be used with care.
664
+ * local branches), to bound memory usage and document size.
665
+ * As long as this flag is enabled, trunk commits are retained - this increases memory usage and document size
666
+ * over time and should be used with care.
664
667
  */
665
668
  readonly retainHistory?: boolean;
666
669
 
@@ -58,7 +58,7 @@ export const Tree: Tree = {
58
58
  ...treeNodeApi,
59
59
 
60
60
  // Note: the implementation details of `createRunTransaction` are deprecated.
61
- // We have introduced replacement `@alpha` APIs on `TreeBranch`, but until they are `@public`, we can't reasonably deprecated this.
61
+ // We have introduced replacement `@alpha` APIs on `UntypedTreeView`, but until they are `@public`, we can't reasonably deprecated this.
62
62
  // Once they have been promoted to public, we can deprecate this API.
63
63
  runTransaction: createRunTransaction(),
64
64
 
@@ -58,7 +58,7 @@ import {
58
58
  type TreeEncodingOptions,
59
59
  type VerboseTree,
60
60
  extractPersistedSchema,
61
- type TreeBranch,
61
+ type UntypedTreeView,
62
62
  TreeViewConfigurationAlpha,
63
63
  getStoredKey,
64
64
  getPropertyKeyFromStoredKey,
@@ -84,7 +84,6 @@ import {
84
84
  type TreeContextAlpha,
85
85
  type TreeNodeSchema,
86
86
  getUnhydratedContext,
87
- type TreeBranchAlpha,
88
87
  } from "../simple-tree/index.js";
89
88
  import { brand, extractFromOpaque, type JsonCompatible } from "../util/index.js";
90
89
 
@@ -96,22 +95,22 @@ const identifier: TreeIdentifierUtils = (node: TreeNode): string | undefined =>
96
95
  return getIdentifierFromNode(node, "uncompressed");
97
96
  };
98
97
 
99
- identifier.shorten = (branch: TreeBranch, nodeIdentifier: string): number | undefined => {
98
+ identifier.shorten = (view: UntypedTreeView, nodeIdentifier: string): number | undefined => {
100
99
  assert(
101
- branch instanceof SchematizingSimpleTreeView,
100
+ view instanceof SchematizingSimpleTreeView,
102
101
  0xcac /* Unexpected branch implementation */,
103
102
  );
104
- const { nodeKeyManager } = branch;
103
+ const { nodeKeyManager } = view;
105
104
  const localNodeKey = nodeKeyManager.tryLocalizeNodeIdentifier(nodeIdentifier);
106
105
  return localNodeKey === undefined ? undefined : extractFromOpaque(localNodeKey);
107
106
  };
108
107
 
109
- identifier.lengthen = (branch: TreeBranch, nodeIdentifier: number): string => {
108
+ identifier.lengthen = (view: UntypedTreeView, nodeIdentifier: number): string => {
110
109
  assert(
111
- branch instanceof SchematizingSimpleTreeView,
110
+ view instanceof SchematizingSimpleTreeView,
112
111
  0xcad /* Unexpected branch implementation */,
113
112
  );
114
- const { nodeKeyManager } = branch;
113
+ const { nodeKeyManager } = view;
115
114
  const local = brand<LocalNodeIdentifier>(nodeIdentifier as SessionSpaceCompressedId);
116
115
  return nodeKeyManager.stabilizeNodeIdentifier(local);
117
116
  };
@@ -121,8 +120,8 @@ identifier.getShort = (node: TreeNode): number | undefined => {
121
120
  return typeof shortIdentifier === "number" ? shortIdentifier : undefined;
122
121
  };
123
122
 
124
- identifier.create = (branch: TreeBranch): string => {
125
- const nodeKeyManager = (branch as SchematizingSimpleTreeView<ImplicitFieldSchema>)
123
+ identifier.create = (view: UntypedTreeView): string => {
124
+ const nodeKeyManager = (view as SchematizingSimpleTreeView<ImplicitFieldSchema>)
126
125
  .nodeKeyManager;
127
126
  return nodeKeyManager.stabilizeNodeIdentifier(nodeKeyManager.generateLocalNodeIdentifier());
128
127
  };
@@ -154,7 +153,7 @@ export interface TreeIdentifierUtils {
154
153
  (node: TreeNode): string | undefined;
155
154
 
156
155
  /**
157
- * Returns the shortened identifier as a number given a UUID known by the id compressor on the branch.
156
+ * Returns the shortened identifier as a number given a UUID known by the id compressor on the view.
158
157
  * @remarks
159
158
  * If the given string is not a valid identifier and/or was not generated by the SharedTree, this will return `undefined`.
160
159
  *
@@ -163,10 +162,10 @@ export interface TreeIdentifierUtils {
163
162
  * This method is the inverse of {@link TreeIdentifierUtils.lengthen}.
164
163
  * If you shorten an identifier and then immediately pass it to {@link TreeIdentifierUtils.lengthen}, you will get the original string back.
165
164
  *
166
- * @param branch - The branch (and/or view) of the SharedTree that will perform the compression.
165
+ * @param view - The view of the SharedTree that will perform the compression.
167
166
  * @param nodeIdentifier - the stable identifier to be shortened.
168
167
  */
169
- shorten(branch: TreeBranch, nodeIdentifier: string): number | undefined;
168
+ shorten(view: UntypedTreeView, nodeIdentifier: string): number | undefined;
170
169
 
171
170
  /**
172
171
  * Returns the stable id as a string if the identifier is decompressible and known by the id compressor.
@@ -176,10 +175,10 @@ export interface TreeIdentifierUtils {
176
175
  * This method is the inverse of {@link TreeIdentifierUtils.shorten}.
177
176
  * If you lengthen an identifier and then immediately pass it to {@link TreeIdentifierUtils.shorten}, you will get the original short identifier back.
178
177
  *
179
- * @param branch - The branch (and/or view) of the SharedTree that will perform the decompression.
178
+ * @param view - The view of the SharedTree that will perform the decompression.
180
179
  * @param nodeIdentifier - The local identifier to be lengthened.
181
180
  */
182
- lengthen(branch: TreeBranch, nodeIdentifier: number): string;
181
+ lengthen(view: UntypedTreeView, nodeIdentifier: number): string;
183
182
 
184
183
  /**
185
184
  * Returns the {@link TreeIdentifierUtils.shorten | shortened} form of the identifier {@link SchemaFactory.identifier | identifier} for the given node.
@@ -206,9 +205,9 @@ export interface TreeIdentifierUtils {
206
205
  * @remarks
207
206
  * The returned UUID string can be {@link TreeIdentifierUtils.shorten | shortened} for high-performance scenarios.
208
207
  *
209
- * @param branch - The branch (and/or view) of the SharedTree that will generate and manage the identifier.
208
+ * @param view - The view of the SharedTree that will generate and manage the identifier.
210
209
  */
211
- create(branch: TreeBranch): string;
210
+ create(view: UntypedTreeView): string;
212
211
  }
213
212
 
214
213
  /**
@@ -253,19 +252,6 @@ export interface TreeAlpha {
253
252
  listener: NoInfer<TreeChangeEventsAlpha<TNode>[K]>,
254
253
  ): () => void;
255
254
 
256
- /**
257
- * Retrieve the {@link TreeBranch | branch}, if any, for the given node.
258
- * @param node - The node to query
259
- * @remarks If the node has already been inserted into the tree, this will return the branch associated with that node's {@link TreeView | view}.
260
- * Otherwise, it will return `undefined` (because the node has not yet been inserted and is therefore not part of a branch or view).
261
- *
262
- * This does not fork a new branch, but rather retrieves the _existing_ branch for the node.
263
- * To create a new branch, use e.g. {@link TreeBranch.fork | `myBranch.fork()`}.
264
- *
265
- * @deprecated To obtain a {@link TreeBranchAlpha | branch }, use `TreeAlpha.context(node)` to obtain a {@link TreeContextAlpha | context} and then check {@link TreeContextAlpha.isBranch | isBranch()}.
266
- */
267
- branch(node: TreeNode): TreeBranchAlpha | undefined;
268
-
269
255
  /**
270
256
  * Retrieve the {@link TreeContextAlpha | context} for the given node.
271
257
  * @param node - The node to query
@@ -842,13 +828,9 @@ export const TreeAlpha: TreeAlpha = {
842
828
  },
843
829
 
844
830
  context(node: TreeNode): TreeContextAlpha {
845
- return this.branch(node) ?? UnhydratedTreeContext.instance;
846
- },
847
-
848
- branch(node: TreeNode): TreeBranchAlpha | undefined {
849
831
  const kernel = getKernel(node);
850
832
  if (!kernel.isHydrated()) {
851
- return undefined;
833
+ return UnhydratedTreeContext.instance;
852
834
  }
853
835
  const view = kernel.anchorNode.anchorSet.slots.get(ViewSlot);
854
836
  assert(
@@ -10,7 +10,7 @@ import type {
10
10
  Listenable,
11
11
  } from "@fluidframework/core-interfaces/internal";
12
12
  import { assert, unreachableCase, fail } from "@fluidframework/core-utils/internal";
13
- import type { IIdCompressor } from "@fluidframework/id-compressor";
13
+ import type { IIdCompressor, StableId } from "@fluidframework/id-compressor";
14
14
  import { type TelemetryLoggerExt, UsageError } from "@fluidframework/telemetry-utils/internal";
15
15
 
16
16
  import {
@@ -45,6 +45,9 @@ import {
45
45
  visitDelta,
46
46
  type RevertibleAlphaFactory,
47
47
  type RevertibleAlpha,
48
+ type RevertOptionsAlpha,
49
+ type RevertToOptionsAlpha,
50
+ type CustomMetadataTree,
48
51
  type GraphCommit,
49
52
  isAncestor,
50
53
  moveToDetachedField,
@@ -63,6 +66,7 @@ import {
63
66
  findCommonAncestor,
64
67
  rebaseBranch,
65
68
  type LocalCommitEvents,
69
+ findAncestor,
66
70
  } from "../core/index.js";
67
71
  import {
68
72
  type FieldBatchCodec,
@@ -91,8 +95,8 @@ import {
91
95
  type TreeViewConfiguration,
92
96
  type UnsafeUnknownSchema,
93
97
  type ViewableTree,
94
- type TreeBranch,
95
- type TreeBranchAlpha,
98
+ type UntypedTreeView,
99
+ type UntypedTreeViewAlpha,
96
100
  type VerboseTree,
97
101
  type VoidTransactionCallbackStatusAlpha,
98
102
  type TransactionCallbackStatusAlpha,
@@ -115,10 +119,12 @@ import {
115
119
  hasSome,
116
120
  throwIfBroken,
117
121
  type JsonCompatibleReadOnly,
122
+ type JsonCompatibleReadOnlyObject,
118
123
  type WithBreakable,
119
124
  } from "../util/index.js";
120
125
 
121
126
  import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
127
+ import { DefaultTreeBranchHistory } from "./history.js";
122
128
  import { SharedTreeChangeEnricher } from "./sharedTreeChangeEnricher.js";
123
129
  import type { SharedTreeChangeProcessingContext } from "./sharedTreeChangeFamily.js";
124
130
  import {
@@ -132,6 +138,46 @@ import type { ISharedTreeEditor, SharedTreeEditBuilder } from "./sharedTreeEditB
132
138
  import { extractTransactionChangeProcessor } from "./transactionPostProcessor.js";
133
139
  import { SerializedChange } from "./serializedChange.js";
134
140
 
141
+ /**
142
+ * Returns a defensive copy of the given metadata, validating that it can be persisted.
143
+ * @remarks
144
+ * The round-trip through JSON ensures that the value read back locally is exactly the value that peers and
145
+ * future summaries will see, and that later mutation of the caller's object cannot affect an existing commit.
146
+ * @throws A `UsageError` if the value cannot be represented as a JSON object.
147
+ */
148
+ function snapshotCustomMetadata(
149
+ customMetadata: JsonCompatibleReadOnlyObject | undefined,
150
+ ): JsonCompatibleReadOnlyObject | undefined {
151
+ if (customMetadata === undefined) {
152
+ return undefined;
153
+ }
154
+ let serialized: string | undefined;
155
+ try {
156
+ serialized = JSON.stringify(customMetadata);
157
+ } catch (error: unknown) {
158
+ throw new UsageError(
159
+ `"customMetadata" must be JSON-serializable: ${error instanceof Error ? error.message : String(error)}`,
160
+ );
161
+ }
162
+ if (serialized === undefined) {
163
+ throw new UsageError(`"customMetadata" must be JSON-serializable.`);
164
+ }
165
+ const snapshot: unknown = JSON.parse(serialized);
166
+ if (typeof snapshot !== "object" || snapshot === null || Array.isArray(snapshot)) {
167
+ throw new UsageError(`"customMetadata" must be a JSON object.`);
168
+ }
169
+ return snapshot as JsonCompatibleReadOnlyObject;
170
+ }
171
+
172
+ /**
173
+ * Wraps metadata for an operation which produces a single commit.
174
+ */
175
+ function toMetadataTree(
176
+ customMetadata: JsonCompatibleReadOnlyObject | undefined,
177
+ ): CustomMetadataTree | undefined {
178
+ return customMetadata === undefined ? undefined : { metadata: customMetadata, children: [] };
179
+ }
180
+
135
181
  /**
136
182
  * Yields all defined (non-`undefined`) labels from a {@link LabelTree}, depth-first.
137
183
  */
@@ -235,7 +281,7 @@ export type TreeTransactor = Transactor<
235
281
  * Implementations of this interface must implement the {@link branchKey} property.
236
282
  */
237
283
  export interface ITreeCheckout
238
- extends TreeBranchAlpha,
284
+ extends UntypedTreeViewAlpha,
239
285
  AnchorLocator,
240
286
  ViewableTree,
241
287
  WithBreakable {
@@ -362,6 +408,7 @@ export function createTreeCheckout(
362
408
  {
363
409
  change: changeFamily.rebaser.compose([]),
364
410
  revision: "root",
411
+ customMetadata: undefined,
365
412
  },
366
413
  changeFamily,
367
414
  () => idCompressor.generateCompressedId(),
@@ -395,9 +442,9 @@ export interface RevertMetrics {
395
442
  }
396
443
 
397
444
  /**
398
- * Get the {@link TreeCheckout} associated with a given {@link TreeBranch}.
445
+ * Get the {@link TreeCheckout} associated with a given {@link UntypedTreeView}.
399
446
  */
400
- function getCheckout(context: TreeBranch): TreeCheckout {
447
+ function getCheckout(context: UntypedTreeView): TreeCheckout {
401
448
  if (context instanceof TreeCheckout) {
402
449
  return context;
403
450
  }
@@ -566,9 +613,10 @@ export class TreeCheckout implements ITreeCheckout {
566
613
 
567
614
  readonly #events = createEmitter<CheckoutEvents>();
568
615
  public events: Listenable<CheckoutEvents> = this.#events;
616
+ private _branchHistory?: DefaultTreeBranchHistory;
569
617
 
570
618
  public constructor(
571
- branch: SharedTreeBranch<
619
+ private branch: SharedTreeBranch<
572
620
  SharedTreeEditBuilder,
573
621
  SharedTreeChange,
574
622
  SharedTreeChangeProcessingContext
@@ -593,6 +641,11 @@ export class TreeCheckout implements ITreeCheckout {
593
641
  this.registerForBranchEvents();
594
642
  }
595
643
 
644
+ public get branchHistory(): DefaultTreeBranchHistory {
645
+ this._branchHistory ??= new DefaultTreeBranchHistory(this.branch, this.idCompressor);
646
+ return this._branchHistory;
647
+ }
648
+
596
649
  /**
597
650
  * Pushes a new label node for a transaction nesting level.
598
651
  *
@@ -962,17 +1015,21 @@ export class TreeCheckout implements ITreeCheckout {
962
1015
  serializedChange,
963
1016
  );
964
1017
  // Apply the change to the branch, but _not_ the `activeBranch` - we do not support squashing serialized commits in a transaction.
965
- this.#transaction.branch.apply(change);
1018
+ this.#transaction.branch.apply(change, CommitKind.Default, undefined);
966
1019
  }
967
1020
 
968
- // #region TreeBranchAlpha
1021
+ // #region UntypedTreeViewAlpha
969
1022
 
970
1023
  @throwIfBroken
971
1024
  public applyChange(change: JsonCompatibleReadOnly): void {
972
1025
  this.applySerializedChange(change);
973
1026
  }
974
1027
 
975
- public isBranch(): this is TreeBranchAlpha {
1028
+ public isBranch(): this is UntypedTreeViewAlpha {
1029
+ return this.isView();
1030
+ }
1031
+
1032
+ public isView(): this is UntypedTreeViewAlpha {
976
1033
  return true;
977
1034
  }
978
1035
 
@@ -1047,6 +1104,9 @@ export class TreeCheckout implements ITreeCheckout {
1047
1104
  this.pushLabelFrame(params?.label);
1048
1105
  this.transaction.start({
1049
1106
  postProcessor: extractTransactionChangeProcessor(params?.postProcessor),
1107
+ // Like the validation described above, rejecting malformed metadata breaks the checkout rather
1108
+ // than being recoverable. Tracked by https://github.com/microsoft/FluidFramework/issues/28085.
1109
+ customMetadata: snapshotCustomMetadata(params?.customMetadata),
1050
1110
  });
1051
1111
 
1052
1112
  addConstraintsToTransaction(this, false, params?.preconditions);
@@ -1084,7 +1144,7 @@ export class TreeCheckout implements ITreeCheckout {
1084
1144
  : { success: true, value: value as TSuccessValue };
1085
1145
  }
1086
1146
 
1087
- // #endregion TreeBranchAlpha
1147
+ // #endregion UntypedTreeViewAlpha
1088
1148
 
1089
1149
  // Revision is the revision of the commit, if any, which caused this change.
1090
1150
  private applyInternalChange(change: SharedTreeChange, revision?: RevisionTag): void {
@@ -1182,24 +1242,33 @@ export class TreeCheckout implements ITreeCheckout {
1182
1242
  ? RevertibleStatus.Disposed
1183
1243
  : RevertibleStatus.Valid;
1184
1244
  },
1185
- revert: (release: boolean = true) => {
1245
+ revert: (releaseOrOptions: boolean | RevertOptionsAlpha = true) => {
1186
1246
  if (revertible.status === RevertibleStatus.Disposed) {
1187
1247
  throw new UsageError("Unable to revert a revertible that has been disposed.");
1188
1248
  }
1189
1249
 
1190
- const revertMetrics = checkout.revertRevertible(revision, kind, labelTree);
1250
+ const options =
1251
+ typeof releaseOrOptions === "boolean"
1252
+ ? { dispose: releaseOrOptions }
1253
+ : releaseOrOptions;
1254
+ const revertMetrics = checkout.revertRevertible(
1255
+ revision,
1256
+ kind,
1257
+ labelTree,
1258
+ snapshotCustomMetadata(options.customMetadata),
1259
+ );
1191
1260
  checkout.logger?.sendTelemetryEvent({
1192
1261
  eventName: TreeCheckout.revertTelemetryEventName,
1193
1262
  ...revertMetrics,
1194
1263
  });
1195
1264
 
1196
- if (release) {
1265
+ if (options.dispose ?? true) {
1197
1266
  revertible.dispose();
1198
1267
  }
1199
1268
  },
1200
- clone: (targetBranch: TreeBranch) => {
1269
+ clone: (targetView: UntypedTreeView) => {
1201
1270
  // TODO:#23442: When a revertible is cloned for a forked branch, optimize to create a fork of a revertible branch once per revision NOT once per revision per checkout.
1202
- const targetCheckout = getCheckout(targetBranch);
1271
+ const targetCheckout = getCheckout(targetView);
1203
1272
 
1204
1273
  const revertibleBranch = this.revertibleCommitBranches.get(revision);
1205
1274
  if (revertibleBranch === undefined) {
@@ -1334,11 +1403,15 @@ export class TreeCheckout implements ITreeCheckout {
1334
1403
  SharedTreeChangeProcessingContext
1335
1404
  >,
1336
1405
  ): void {
1337
- // TODO: Dispose old branch, if necessary
1338
1406
  assert(
1339
1407
  this.#transaction.size === 0,
1340
1408
  0xc55 /* Cannot switch branches during a transaction */,
1341
1409
  );
1410
+ if (this.isSharedBranch) {
1411
+ throw new UsageError(
1412
+ "Cannot switch a view away from a shared branch. Consider forking first.",
1413
+ );
1414
+ }
1342
1415
  const diff = diffHistories(
1343
1416
  this.changeFamily.rebaser,
1344
1417
  this.#transaction.branch.getHead(),
@@ -1349,6 +1422,9 @@ export class TreeCheckout implements ITreeCheckout {
1349
1422
  this.unregisterFromBranchEvents();
1350
1423
 
1351
1424
  this.#transaction = this.createTransactionStack(branch);
1425
+ this.branch = branch;
1426
+ this._branchHistory?.dispose();
1427
+ this._branchHistory = undefined;
1352
1428
  this.editLock = new EditLock(this.#transaction.activeBranchEditor);
1353
1429
  this.registerForBranchEvents();
1354
1430
 
@@ -1357,8 +1433,67 @@ export class TreeCheckout implements ITreeCheckout {
1357
1433
  this.#events.emit("afterBatch");
1358
1434
  }
1359
1435
 
1360
- private rebase(branch: TreeBranch): void {
1361
- const checkout = getCheckout(branch);
1436
+ public rewindTo(revisionString: string): void {
1437
+ this.checkNotDisposed("The branch has already been disposed and cannot be rewound.");
1438
+ if (this.#transaction.size > 0) {
1439
+ throw new UsageError("Rewinding is not supported during transactions.");
1440
+ }
1441
+ const revision = this.idCompressor.tryRecompress(revisionString as StableId);
1442
+ if (revision === undefined) {
1443
+ throw new UsageError(`Unrecognized revision id: ${revisionString}`);
1444
+ }
1445
+ const targetCommit = findAncestor(
1446
+ this.#transaction.branch.getHead(),
1447
+ (commit) => commit.revision === revision,
1448
+ );
1449
+ if (targetCommit === undefined) {
1450
+ throw new UsageError(`No commit found with revision: ${revisionString}`);
1451
+ }
1452
+ this.switchBranch(this.#transaction.branch.fork(targetCommit));
1453
+ }
1454
+
1455
+ public revertTo(revisionString: string, options?: RevertToOptionsAlpha): void {
1456
+ this.checkNotDisposed(
1457
+ "The branch has already been disposed and prior revisions cannot be reverted to.",
1458
+ );
1459
+ this.editLock.checkUnlocked("Reverting to a revision");
1460
+ if (this.#transaction.size > 0) {
1461
+ throw new UsageError("Reverting to a revision is not supported during transactions.");
1462
+ }
1463
+ const customMetadata = snapshotCustomMetadata(options?.customMetadata);
1464
+ const revision = this.idCompressor.tryRecompress(revisionString as StableId);
1465
+ if (revision === undefined) {
1466
+ throw new UsageError(`Unrecognized revision id: ${revisionString}`);
1467
+ }
1468
+ // Populated with the commits that came after the target commit, from oldest to newest.
1469
+ const commitsToUndo: GraphCommit<SharedTreeChange>[] = [];
1470
+ const targetCommit = findAncestor(
1471
+ [this.#transaction.activeBranch.getHead(), commitsToUndo],
1472
+ (commit) => commit.revision === revision,
1473
+ );
1474
+ if (targetCommit === undefined) {
1475
+ throw new UsageError(`No commit found with revision: ${revisionString}`);
1476
+ }
1477
+ if (!hasSome(commitsToUndo)) {
1478
+ // The target commit is already the head of the branch, so there is nothing to revert.
1479
+ return;
1480
+ }
1481
+ const revisionForInvert = this.mintRevisionTag();
1482
+ const toUndo = this.changeFamily.rebaser.compose(commitsToUndo);
1483
+ const inverse = this.changeFamily.rebaser.invert(
1484
+ makeAnonChange(toUndo),
1485
+ false,
1486
+ revisionForInvert,
1487
+ );
1488
+ this.#transaction.branch.apply(
1489
+ tagChange(inverse, revisionForInvert),
1490
+ CommitKind.Default,
1491
+ toMetadataTree(customMetadata),
1492
+ );
1493
+ }
1494
+
1495
+ private rebase(view: UntypedTreeView): void {
1496
+ const checkout = getCheckout(view);
1362
1497
  this.checkNotDisposed(
1363
1498
  "The target branch of the rebase has been disposed and cannot be rebased.",
1364
1499
  );
@@ -1384,15 +1519,15 @@ export class TreeCheckout implements ITreeCheckout {
1384
1519
  checkout.#transaction.branch.rebaseOnto(this.#transaction.branch);
1385
1520
  }
1386
1521
 
1387
- public rebaseOnto(branch: TreeBranch): void {
1388
- getCheckout(branch).rebase(this);
1522
+ public rebaseOnto(view: UntypedTreeView): void {
1523
+ getCheckout(view).rebase(this);
1389
1524
  }
1390
1525
 
1391
- public isMissingEditsFrom(branch: TreeBranch): boolean {
1392
- const branchCheckout = getCheckout(branch);
1526
+ public isMissingEditsFrom(view: UntypedTreeView): boolean {
1527
+ const viewCheckout = getCheckout(view);
1393
1528
  const targetPath: GraphCommit<unknown>[] = [];
1394
1529
  const ancestor = findCommonAncestor(this.mainBranch.getHead(), [
1395
- branchCheckout.mainBranch.getHead(),
1530
+ viewCheckout.mainBranch.getHead(),
1396
1531
  targetPath,
1397
1532
  ]);
1398
1533
  if (ancestor === undefined) {
@@ -1402,14 +1537,14 @@ export class TreeCheckout implements ITreeCheckout {
1402
1537
  }
1403
1538
 
1404
1539
  public computeNetChangeIfRebasedOnto(
1405
- branch: TreeBranch,
1540
+ view: UntypedTreeView,
1406
1541
  ): JsonCompatibleReadOnly | undefined {
1407
- const branchCheckout = getCheckout(branch);
1542
+ const viewCheckout = getCheckout(view);
1408
1543
  const rebased = rebaseBranch(
1409
1544
  this.mintRevisionTag,
1410
1545
  this.changeFamily.rebaser,
1411
1546
  this.#transaction.branch.getHead(),
1412
- branchCheckout.#transaction.branch.getHead(),
1547
+ viewCheckout.#transaction.branch.getHead(),
1413
1548
  );
1414
1549
 
1415
1550
  if (rebased.sourceChange === undefined) {
@@ -1425,10 +1560,10 @@ export class TreeCheckout implements ITreeCheckout {
1425
1560
  );
1426
1561
  }
1427
1562
 
1428
- public merge(branch: TreeBranch): void;
1429
- public merge(branch: TreeBranch, disposeMerged: boolean): void;
1430
- public merge(branch: TreeBranch, disposeMerged = true): void {
1431
- const checkout = getCheckout(branch);
1563
+ public merge(view: UntypedTreeView): void;
1564
+ public merge(view: UntypedTreeView, disposeMerged: boolean): void;
1565
+ public merge(view: UntypedTreeView, disposeMerged = true): void {
1566
+ const checkout = getCheckout(view);
1432
1567
  this.checkNotDisposed(
1433
1568
  "The target branch of the merge has been disposed and cannot be merged.",
1434
1569
  );
@@ -1481,6 +1616,8 @@ export class TreeCheckout implements ITreeCheckout {
1481
1616
  view.dispose();
1482
1617
  }
1483
1618
  this.#events.emit("dispose");
1619
+ this._branchHistory?.dispose();
1620
+ this._branchHistory = undefined;
1484
1621
  }
1485
1622
 
1486
1623
  public getRemovedRoots(): [string | number | undefined, number, JsonableTree][] {
@@ -1529,6 +1666,7 @@ export class TreeCheckout implements ITreeCheckout {
1529
1666
  revision: RevisionTag,
1530
1667
  kind: CommitKind,
1531
1668
  labelTree: LabelTree | undefined,
1669
+ customMetadata: JsonCompatibleReadOnlyObject | undefined,
1532
1670
  ): RevertMetrics {
1533
1671
  this.editLock.checkUnlocked("Reverting a commit");
1534
1672
  if (this.transaction.size > 0) {
@@ -1583,6 +1721,7 @@ export class TreeCheckout implements ITreeCheckout {
1583
1721
  kind === CommitKind.Default || kind === CommitKind.Redo
1584
1722
  ? CommitKind.Undo
1585
1723
  : CommitKind.Redo,
1724
+ toMetadataTree(customMetadata),
1586
1725
  );
1587
1726
  } finally {
1588
1727
  this.labelTreeNode = previousLabelTreeNode;
@@ -7,7 +7,7 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal";
7
7
 
8
8
  import type {
9
9
  TreeContextAlpha,
10
- TreeBranchAlpha,
10
+ UntypedTreeViewAlpha,
11
11
  RunTransactionParamsAlpha,
12
12
  TransactionVoidResult,
13
13
  TransactionValueResult,
@@ -24,7 +24,11 @@ export class UnhydratedTreeContext implements TreeContextAlpha {
24
24
  private transactionCount = 0;
25
25
  private constructor() {}
26
26
 
27
- public isBranch(): this is TreeBranchAlpha {
27
+ public isBranch(): this is UntypedTreeViewAlpha {
28
+ return this.isView();
29
+ }
30
+
31
+ public isView(): this is UntypedTreeViewAlpha {
28
32
  return false;
29
33
  }
30
34
 
@@ -17,6 +17,7 @@ import {
17
17
  type ChangeFamily,
18
18
  type ChangeFamilyEditor,
19
19
  CommitKind,
20
+ type CustomMetadataTree,
20
21
  type GraphCommit,
21
22
  type RevisionTag,
22
23
  type TaggedChange,
@@ -56,6 +57,10 @@ export type SharedTreeBranchChange<TChange> =
56
57
  | {
57
58
  type: "rebase";
58
59
  change: TaggedChange<TChange> | undefined;
60
+ /** The commits removed from the head of the branch by this operation */
61
+ removedCommits: readonly GraphCommit<TChange>[];
62
+ /** The commits appended to the head of the branch by this operation */
63
+ newCommits: readonly GraphCommit<TChange>[];
59
64
  };
60
65
 
61
66
  /**
@@ -152,7 +157,7 @@ export class SharedTreeBranch<
152
157
  >,
153
158
  ) {
154
159
  this.editor = this.changeFamily.buildEditor(mintRevisionTag, (change) =>
155
- this.apply(change),
160
+ this.apply(change, CommitKind.Default, undefined),
156
161
  );
157
162
  this.unsubscribeBranchTrimmer = branchTrimmer?.on("ancestryTrimmed", (commit) => {
158
163
  this.#events.emit("ancestryTrimmed", commit);
@@ -173,9 +178,15 @@ export class SharedTreeBranch<
173
178
  * Apply a change to this branch.
174
179
  * @param change - the change to apply
175
180
  * @param kind - the kind of change to apply
181
+ * @param customMetadata - {@link GraphCommit.customMetadata | metadata} to attach to the new commit.
182
+ * Callers reconstructing an existing commit, rather than minting one, must pass that commit's metadata.
176
183
  * @returns the change that was applied and the new head commit of the branch
177
184
  */
178
- public apply(change: TaggedChange<TChange>, kind: CommitKind = CommitKind.Default): void {
185
+ public apply(
186
+ change: TaggedChange<TChange>,
187
+ kind: CommitKind,
188
+ customMetadata: CustomMetadataTree | undefined,
189
+ ): void {
179
190
  this.assertNotDisposed();
180
191
 
181
192
  const revisionTag = change.revision;
@@ -184,6 +195,7 @@ export class SharedTreeBranch<
184
195
  const newHead = mintCommit(this.head, {
185
196
  revision: revisionTag,
186
197
  change: change.change,
198
+ customMetadata,
187
199
  });
188
200
 
189
201
  const changeEvent = {
@@ -213,6 +225,26 @@ export class SharedTreeBranch<
213
225
  return this.head;
214
226
  }
215
227
 
228
+ /**
229
+ * Gets the number of commits in this branch.
230
+ * This includes commits on ancestor branches but excludes the sentinel commit at the root of all branches.
231
+ * @remarks
232
+ * This method has linear complexity in the number of commits in the branch.
233
+ * See {@link BranchCommitCounter} for a cached version.
234
+ */
235
+ public getCommitCount(): number {
236
+ let count = 0;
237
+ for (
238
+ let commit: GraphCommit<TChange> | undefined = this.head;
239
+ commit !== undefined;
240
+ commit = commit.parent
241
+ ) {
242
+ count++;
243
+ }
244
+ // Exclude the sentinel commit that serves as the base to all branches.
245
+ return count - 1;
246
+ }
247
+
216
248
  /**
217
249
  * Spawn a new branch that is based off of the current state of this branch.
218
250
  * @param commit - The commit to base the new branch off of. Defaults to the head of this branch.