@fluidframework/tree 2.92.0 → 2.100.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 (366) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/INCREMENTAL_SUMMARY.md +89 -0
  3. package/README.md +7 -1
  4. package/api-report/tree.alpha.api.md +60 -29
  5. package/api-report/tree.beta.api.md +41 -12
  6. package/api-report/tree.legacy.beta.api.md +41 -12
  7. package/dist/api.d.ts +6 -1
  8. package/dist/api.d.ts.map +1 -1
  9. package/dist/api.js.map +1 -1
  10. package/dist/core/tree/anchorSet.d.ts.map +1 -1
  11. package/dist/core/tree/anchorSet.js +21 -0
  12. package/dist/core/tree/anchorSet.js.map +1 -1
  13. package/dist/entrypoints/alpha.d.ts +1 -1
  14. package/dist/entrypoints/alpha.d.ts.map +1 -1
  15. package/dist/entrypoints/alpha.js +4 -4
  16. package/dist/entrypoints/alpha.js.map +1 -1
  17. package/dist/entrypoints/beta.d.ts +1 -1
  18. package/dist/entrypoints/beta.d.ts.map +1 -1
  19. package/dist/entrypoints/beta.js +3 -1
  20. package/dist/entrypoints/beta.js.map +1 -1
  21. package/dist/entrypoints/legacy.d.ts +1 -1
  22. package/dist/entrypoints/legacy.d.ts.map +1 -1
  23. package/dist/entrypoints/legacy.js +3 -1
  24. package/dist/entrypoints/legacy.js.map +1 -1
  25. package/dist/feature-libraries/chunked-forest/basicChunk.d.ts +25 -1
  26. package/dist/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  27. package/dist/feature-libraries/chunked-forest/basicChunk.js +71 -18
  28. package/dist/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  29. package/dist/feature-libraries/chunked-forest/chunkTree.d.ts +2 -2
  30. package/dist/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
  31. package/dist/feature-libraries/chunked-forest/chunkTree.js +2 -1
  32. package/dist/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
  33. package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.js +1 -1
  34. package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.js.map +1 -1
  35. package/dist/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
  36. package/dist/feature-libraries/chunked-forest/codec/codecs.js +1 -1
  37. package/dist/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
  38. package/dist/feature-libraries/chunked-forest/codec/compressedEncode.d.ts +1 -1
  39. package/dist/feature-libraries/chunked-forest/codec/compressedEncode.d.ts.map +1 -1
  40. package/dist/feature-libraries/chunked-forest/codec/compressedEncode.js +1 -1
  41. package/dist/feature-libraries/chunked-forest/codec/compressedEncode.js.map +1 -1
  42. package/dist/feature-libraries/chunked-forest/codec/format/formatGeneric.d.ts +1 -2
  43. package/dist/feature-libraries/chunked-forest/codec/format/formatGeneric.d.ts.map +1 -1
  44. package/dist/feature-libraries/chunked-forest/codec/format/formatGeneric.js +0 -1
  45. package/dist/feature-libraries/chunked-forest/codec/format/formatGeneric.js.map +1 -1
  46. package/dist/feature-libraries/chunked-forest/codec/format/index.d.ts +1 -1
  47. package/dist/feature-libraries/chunked-forest/codec/format/index.d.ts.map +1 -1
  48. package/dist/feature-libraries/chunked-forest/codec/format/index.js +2 -1
  49. package/dist/feature-libraries/chunked-forest/codec/format/index.js.map +1 -1
  50. package/dist/feature-libraries/chunked-forest/codec/format/versions.d.ts +10 -2
  51. package/dist/feature-libraries/chunked-forest/codec/format/versions.d.ts.map +1 -1
  52. package/dist/feature-libraries/chunked-forest/codec/format/versions.js +15 -1
  53. package/dist/feature-libraries/chunked-forest/codec/format/versions.js.map +1 -1
  54. package/dist/feature-libraries/chunked-forest/uniformChunk.d.ts +18 -5
  55. package/dist/feature-libraries/chunked-forest/uniformChunk.d.ts.map +1 -1
  56. package/dist/feature-libraries/chunked-forest/uniformChunk.js +47 -19
  57. package/dist/feature-libraries/chunked-forest/uniformChunk.js.map +1 -1
  58. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts +19 -0
  59. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts.map +1 -1
  60. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.js +76 -22
  61. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.js.map +1 -1
  62. package/dist/feature-libraries/indexing/anchorTreeIndex.d.ts +1 -0
  63. package/dist/feature-libraries/indexing/anchorTreeIndex.d.ts.map +1 -1
  64. package/dist/feature-libraries/indexing/anchorTreeIndex.js +3 -1
  65. package/dist/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
  66. package/dist/feature-libraries/indexing/types.d.ts +4 -3
  67. package/dist/feature-libraries/indexing/types.d.ts.map +1 -1
  68. package/dist/feature-libraries/indexing/types.js.map +1 -1
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/packageVersion.d.ts +1 -1
  73. package/dist/packageVersion.d.ts.map +1 -1
  74. package/dist/packageVersion.js +1 -1
  75. package/dist/packageVersion.js.map +1 -1
  76. package/dist/serializableDomainSchema.d.ts +5 -5
  77. package/dist/serializableDomainSchema.d.ts.map +1 -1
  78. package/dist/serializableDomainSchema.js.map +1 -1
  79. package/dist/shared-tree/treeAlpha.d.ts +6 -2
  80. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  81. package/dist/shared-tree/treeAlpha.js.map +1 -1
  82. package/dist/shared-tree/treeCheckout.d.ts +1 -1
  83. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  84. package/dist/simple-tree/api/discrepancies.js +4 -1
  85. package/dist/simple-tree/api/discrepancies.js.map +1 -1
  86. package/dist/simple-tree/api/identifierIndex.d.ts +2 -2
  87. package/dist/simple-tree/api/identifierIndex.js +1 -1
  88. package/dist/simple-tree/api/identifierIndex.js.map +1 -1
  89. package/dist/simple-tree/api/index.d.ts +2 -2
  90. package/dist/simple-tree/api/index.d.ts.map +1 -1
  91. package/dist/simple-tree/api/index.js +3 -2
  92. package/dist/simple-tree/api/index.js.map +1 -1
  93. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts +47 -2
  94. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
  95. package/dist/simple-tree/api/schemaFactoryAlpha.js +26 -1
  96. package/dist/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
  97. package/dist/simple-tree/api/simpleTreeIndex.d.ts +5 -5
  98. package/dist/simple-tree/api/simpleTreeIndex.js +1 -1
  99. package/dist/simple-tree/api/simpleTreeIndex.js.map +1 -1
  100. package/dist/simple-tree/api/storedSchema.d.ts.map +1 -1
  101. package/dist/simple-tree/api/storedSchema.js +4 -1
  102. package/dist/simple-tree/api/storedSchema.js.map +1 -1
  103. package/dist/simple-tree/api/treeAlpha.d.ts +70 -13
  104. package/dist/simple-tree/api/treeAlpha.d.ts.map +1 -1
  105. package/dist/simple-tree/api/treeAlpha.js.map +1 -1
  106. package/dist/simple-tree/api/treeChangeEvents.d.ts +1 -1
  107. package/dist/simple-tree/api/treeChangeEvents.js.map +1 -1
  108. package/dist/simple-tree/api/treeNodeApi.d.ts +60 -1
  109. package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  110. package/dist/simple-tree/api/treeNodeApi.js +68 -6
  111. package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
  112. package/dist/simple-tree/core/toStored.d.ts +7 -0
  113. package/dist/simple-tree/core/toStored.d.ts.map +1 -1
  114. package/dist/simple-tree/core/toStored.js.map +1 -1
  115. package/dist/simple-tree/core/unhydratedFlexTree.d.ts +17 -3
  116. package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  117. package/dist/simple-tree/core/unhydratedFlexTree.js +114 -12
  118. package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  119. package/dist/simple-tree/fieldSchema.d.ts +6 -1
  120. package/dist/simple-tree/fieldSchema.d.ts.map +1 -1
  121. package/dist/simple-tree/fieldSchema.js +3 -0
  122. package/dist/simple-tree/fieldSchema.js.map +1 -1
  123. package/dist/simple-tree/index.d.ts +2 -2
  124. package/dist/simple-tree/index.d.ts.map +1 -1
  125. package/dist/simple-tree/index.js +4 -3
  126. package/dist/simple-tree/index.js.map +1 -1
  127. package/dist/simple-tree/node-kinds/index.d.ts +1 -1
  128. package/dist/simple-tree/node-kinds/index.d.ts.map +1 -1
  129. package/dist/simple-tree/node-kinds/index.js.map +1 -1
  130. package/dist/simple-tree/node-kinds/map/index.d.ts +1 -1
  131. package/dist/simple-tree/node-kinds/map/index.d.ts.map +1 -1
  132. package/dist/simple-tree/node-kinds/map/index.js.map +1 -1
  133. package/dist/simple-tree/node-kinds/map/mapNode.d.ts +13 -0
  134. package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  135. package/dist/simple-tree/node-kinds/map/mapNode.js +6 -1
  136. package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  137. package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts +6 -6
  138. package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
  139. package/dist/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
  140. package/dist/simple-tree/simpleSchema.d.ts +17 -0
  141. package/dist/simple-tree/simpleSchema.d.ts.map +1 -1
  142. package/dist/simple-tree/simpleSchema.js.map +1 -1
  143. package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
  144. package/dist/simple-tree/toStoredSchema.js +23 -1
  145. package/dist/simple-tree/toStoredSchema.js.map +1 -1
  146. package/dist/tableSchema.d.ts +4 -5
  147. package/dist/tableSchema.d.ts.map +1 -1
  148. package/dist/tableSchema.js +12 -23
  149. package/dist/tableSchema.js.map +1 -1
  150. package/dist/text/textDomain.d.ts.map +1 -1
  151. package/dist/text/textDomain.js +27 -0
  152. package/dist/text/textDomain.js.map +1 -1
  153. package/dist/text/textDomainFormatted.d.ts +4 -4
  154. package/dist/util/index.d.ts +1 -1
  155. package/dist/util/index.d.ts.map +1 -1
  156. package/dist/util/index.js +2 -3
  157. package/dist/util/index.js.map +1 -1
  158. package/dist/util/utils.d.ts +0 -1
  159. package/dist/util/utils.d.ts.map +1 -1
  160. package/dist/util/utils.js +1 -6
  161. package/dist/util/utils.js.map +1 -1
  162. package/docs/user-facing/isolated-declarations.md +147 -0
  163. package/eslint.config.mts +1 -1
  164. package/lib/api.d.ts +6 -1
  165. package/lib/api.d.ts.map +1 -1
  166. package/lib/api.js.map +1 -1
  167. package/lib/core/tree/anchorSet.d.ts.map +1 -1
  168. package/lib/core/tree/anchorSet.js +21 -0
  169. package/lib/core/tree/anchorSet.js.map +1 -1
  170. package/lib/entrypoints/alpha.d.ts +1 -1
  171. package/lib/entrypoints/alpha.d.ts.map +1 -1
  172. package/lib/entrypoints/alpha.js +1 -1
  173. package/lib/entrypoints/alpha.js.map +1 -1
  174. package/lib/entrypoints/beta.d.ts +1 -1
  175. package/lib/entrypoints/beta.d.ts.map +1 -1
  176. package/lib/entrypoints/beta.js +1 -1
  177. package/lib/entrypoints/beta.js.map +1 -1
  178. package/lib/entrypoints/legacy.d.ts +1 -1
  179. package/lib/entrypoints/legacy.d.ts.map +1 -1
  180. package/lib/entrypoints/legacy.js +1 -1
  181. package/lib/entrypoints/legacy.js.map +1 -1
  182. package/lib/feature-libraries/chunked-forest/basicChunk.d.ts +25 -1
  183. package/lib/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  184. package/lib/feature-libraries/chunked-forest/basicChunk.js +72 -19
  185. package/lib/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  186. package/lib/feature-libraries/chunked-forest/chunkTree.d.ts +2 -2
  187. package/lib/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
  188. package/lib/feature-libraries/chunked-forest/chunkTree.js +2 -1
  189. package/lib/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
  190. package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.js +2 -2
  191. package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.js.map +1 -1
  192. package/lib/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
  193. package/lib/feature-libraries/chunked-forest/codec/codecs.js +2 -2
  194. package/lib/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
  195. package/lib/feature-libraries/chunked-forest/codec/compressedEncode.d.ts +1 -1
  196. package/lib/feature-libraries/chunked-forest/codec/compressedEncode.d.ts.map +1 -1
  197. package/lib/feature-libraries/chunked-forest/codec/compressedEncode.js +2 -2
  198. package/lib/feature-libraries/chunked-forest/codec/compressedEncode.js.map +1 -1
  199. package/lib/feature-libraries/chunked-forest/codec/format/formatGeneric.d.ts +1 -2
  200. package/lib/feature-libraries/chunked-forest/codec/format/formatGeneric.d.ts.map +1 -1
  201. package/lib/feature-libraries/chunked-forest/codec/format/formatGeneric.js +0 -1
  202. package/lib/feature-libraries/chunked-forest/codec/format/formatGeneric.js.map +1 -1
  203. package/lib/feature-libraries/chunked-forest/codec/format/index.d.ts +1 -1
  204. package/lib/feature-libraries/chunked-forest/codec/format/index.d.ts.map +1 -1
  205. package/lib/feature-libraries/chunked-forest/codec/format/index.js +1 -1
  206. package/lib/feature-libraries/chunked-forest/codec/format/index.js.map +1 -1
  207. package/lib/feature-libraries/chunked-forest/codec/format/versions.d.ts +10 -2
  208. package/lib/feature-libraries/chunked-forest/codec/format/versions.d.ts.map +1 -1
  209. package/lib/feature-libraries/chunked-forest/codec/format/versions.js +13 -0
  210. package/lib/feature-libraries/chunked-forest/codec/format/versions.js.map +1 -1
  211. package/lib/feature-libraries/chunked-forest/uniformChunk.d.ts +18 -5
  212. package/lib/feature-libraries/chunked-forest/uniformChunk.d.ts.map +1 -1
  213. package/lib/feature-libraries/chunked-forest/uniformChunk.js +48 -20
  214. package/lib/feature-libraries/chunked-forest/uniformChunk.js.map +1 -1
  215. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts +19 -0
  216. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts.map +1 -1
  217. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.js +76 -22
  218. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.js.map +1 -1
  219. package/lib/feature-libraries/indexing/anchorTreeIndex.d.ts +1 -0
  220. package/lib/feature-libraries/indexing/anchorTreeIndex.d.ts.map +1 -1
  221. package/lib/feature-libraries/indexing/anchorTreeIndex.js +3 -1
  222. package/lib/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
  223. package/lib/feature-libraries/indexing/types.d.ts +4 -3
  224. package/lib/feature-libraries/indexing/types.d.ts.map +1 -1
  225. package/lib/feature-libraries/indexing/types.js.map +1 -1
  226. package/lib/index.d.ts +1 -1
  227. package/lib/index.d.ts.map +1 -1
  228. package/lib/index.js.map +1 -1
  229. package/lib/packageVersion.d.ts +1 -1
  230. package/lib/packageVersion.d.ts.map +1 -1
  231. package/lib/packageVersion.js +1 -1
  232. package/lib/packageVersion.js.map +1 -1
  233. package/lib/serializableDomainSchema.d.ts +5 -5
  234. package/lib/serializableDomainSchema.d.ts.map +1 -1
  235. package/lib/serializableDomainSchema.js +4 -1
  236. package/lib/serializableDomainSchema.js.map +1 -1
  237. package/lib/shared-tree/treeAlpha.d.ts +6 -2
  238. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  239. package/lib/shared-tree/treeAlpha.js.map +1 -1
  240. package/lib/shared-tree/treeCheckout.d.ts +1 -1
  241. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  242. package/lib/simple-tree/api/discrepancies.js +4 -1
  243. package/lib/simple-tree/api/discrepancies.js.map +1 -1
  244. package/lib/simple-tree/api/identifierIndex.d.ts +2 -2
  245. package/lib/simple-tree/api/identifierIndex.js +1 -1
  246. package/lib/simple-tree/api/identifierIndex.js.map +1 -1
  247. package/lib/simple-tree/api/index.d.ts +2 -2
  248. package/lib/simple-tree/api/index.d.ts.map +1 -1
  249. package/lib/simple-tree/api/index.js +1 -1
  250. package/lib/simple-tree/api/index.js.map +1 -1
  251. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts +47 -2
  252. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
  253. package/lib/simple-tree/api/schemaFactoryAlpha.js +28 -3
  254. package/lib/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
  255. package/lib/simple-tree/api/simpleTreeIndex.d.ts +5 -5
  256. package/lib/simple-tree/api/simpleTreeIndex.js +1 -1
  257. package/lib/simple-tree/api/simpleTreeIndex.js.map +1 -1
  258. package/lib/simple-tree/api/storedSchema.d.ts.map +1 -1
  259. package/lib/simple-tree/api/storedSchema.js +4 -1
  260. package/lib/simple-tree/api/storedSchema.js.map +1 -1
  261. package/lib/simple-tree/api/treeAlpha.d.ts +70 -13
  262. package/lib/simple-tree/api/treeAlpha.d.ts.map +1 -1
  263. package/lib/simple-tree/api/treeAlpha.js.map +1 -1
  264. package/lib/simple-tree/api/treeChangeEvents.d.ts +1 -1
  265. package/lib/simple-tree/api/treeChangeEvents.js.map +1 -1
  266. package/lib/simple-tree/api/treeNodeApi.d.ts +60 -1
  267. package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  268. package/lib/simple-tree/api/treeNodeApi.js +66 -6
  269. package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
  270. package/lib/simple-tree/core/toStored.d.ts +7 -0
  271. package/lib/simple-tree/core/toStored.d.ts.map +1 -1
  272. package/lib/simple-tree/core/toStored.js.map +1 -1
  273. package/lib/simple-tree/core/unhydratedFlexTree.d.ts +17 -3
  274. package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  275. package/lib/simple-tree/core/unhydratedFlexTree.js +115 -13
  276. package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  277. package/lib/simple-tree/fieldSchema.d.ts +6 -1
  278. package/lib/simple-tree/fieldSchema.d.ts.map +1 -1
  279. package/lib/simple-tree/fieldSchema.js +3 -0
  280. package/lib/simple-tree/fieldSchema.js.map +1 -1
  281. package/lib/simple-tree/index.d.ts +2 -2
  282. package/lib/simple-tree/index.d.ts.map +1 -1
  283. package/lib/simple-tree/index.js +1 -1
  284. package/lib/simple-tree/index.js.map +1 -1
  285. package/lib/simple-tree/node-kinds/index.d.ts +1 -1
  286. package/lib/simple-tree/node-kinds/index.d.ts.map +1 -1
  287. package/lib/simple-tree/node-kinds/index.js.map +1 -1
  288. package/lib/simple-tree/node-kinds/map/index.d.ts +1 -1
  289. package/lib/simple-tree/node-kinds/map/index.d.ts.map +1 -1
  290. package/lib/simple-tree/node-kinds/map/index.js.map +1 -1
  291. package/lib/simple-tree/node-kinds/map/mapNode.d.ts +13 -0
  292. package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  293. package/lib/simple-tree/node-kinds/map/mapNode.js +6 -1
  294. package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  295. package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts +6 -6
  296. package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
  297. package/lib/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
  298. package/lib/simple-tree/simpleSchema.d.ts +17 -0
  299. package/lib/simple-tree/simpleSchema.d.ts.map +1 -1
  300. package/lib/simple-tree/simpleSchema.js.map +1 -1
  301. package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
  302. package/lib/simple-tree/toStoredSchema.js +24 -2
  303. package/lib/simple-tree/toStoredSchema.js.map +1 -1
  304. package/lib/tableSchema.d.ts +4 -5
  305. package/lib/tableSchema.d.ts.map +1 -1
  306. package/lib/tableSchema.js +12 -23
  307. package/lib/tableSchema.js.map +1 -1
  308. package/lib/text/textDomain.d.ts.map +1 -1
  309. package/lib/text/textDomain.js +29 -0
  310. package/lib/text/textDomain.js.map +1 -1
  311. package/lib/text/textDomainFormatted.d.ts +4 -4
  312. package/lib/tsdoc-metadata.json +1 -1
  313. package/lib/util/index.d.ts +1 -1
  314. package/lib/util/index.d.ts.map +1 -1
  315. package/lib/util/index.js +1 -1
  316. package/lib/util/index.js.map +1 -1
  317. package/lib/util/utils.d.ts +0 -1
  318. package/lib/util/utils.d.ts.map +1 -1
  319. package/lib/util/utils.js +0 -1
  320. package/lib/util/utils.js.map +1 -1
  321. package/package.json +32 -37
  322. package/src/api.ts +10 -0
  323. package/src/core/tree/anchorSet.ts +25 -0
  324. package/src/entrypoints/alpha.ts +20 -16
  325. package/src/entrypoints/beta.ts +7 -1
  326. package/src/entrypoints/legacy.ts +8 -10
  327. package/src/feature-libraries/chunked-forest/basicChunk.ts +76 -20
  328. package/src/feature-libraries/chunked-forest/chunkTree.ts +3 -2
  329. package/src/feature-libraries/chunked-forest/codec/chunkDecoding.ts +2 -2
  330. package/src/feature-libraries/chunked-forest/codec/codecs.ts +2 -1
  331. package/src/feature-libraries/chunked-forest/codec/compressedEncode.ts +3 -2
  332. package/src/feature-libraries/chunked-forest/codec/format/formatGeneric.ts +0 -1
  333. package/src/feature-libraries/chunked-forest/codec/format/index.ts +1 -0
  334. package/src/feature-libraries/chunked-forest/codec/format/versions.ts +15 -0
  335. package/src/feature-libraries/chunked-forest/uniformChunk.ts +73 -21
  336. package/src/feature-libraries/forest-summary/incrementalSummaryBuilder.ts +116 -31
  337. package/src/feature-libraries/indexing/anchorTreeIndex.ts +1 -0
  338. package/src/feature-libraries/indexing/types.ts +5 -3
  339. package/src/index.ts +4 -0
  340. package/src/packageVersion.ts +1 -1
  341. package/src/serializableDomainSchema.ts +6 -0
  342. package/src/shared-tree/treeAlpha.ts +6 -2
  343. package/src/simple-tree/api/discrepancies.ts +6 -1
  344. package/src/simple-tree/api/identifierIndex.ts +2 -2
  345. package/src/simple-tree/api/index.ts +4 -0
  346. package/src/simple-tree/api/schemaFactoryAlpha.ts +99 -3
  347. package/src/simple-tree/api/simpleTreeIndex.ts +6 -6
  348. package/src/simple-tree/api/storedSchema.ts +4 -1
  349. package/src/simple-tree/api/treeAlpha.ts +75 -12
  350. package/src/simple-tree/api/treeChangeEvents.ts +1 -1
  351. package/src/simple-tree/api/treeNodeApi.ts +101 -7
  352. package/src/simple-tree/core/toStored.ts +8 -0
  353. package/src/simple-tree/core/unhydratedFlexTree.ts +134 -10
  354. package/src/simple-tree/fieldSchema.ts +10 -0
  355. package/src/simple-tree/index.ts +5 -0
  356. package/src/simple-tree/node-kinds/index.ts +1 -0
  357. package/src/simple-tree/node-kinds/map/index.ts +1 -0
  358. package/src/simple-tree/node-kinds/map/mapNode.ts +20 -3
  359. package/src/simple-tree/node-kinds/map/mapNodeTypes.ts +6 -6
  360. package/src/simple-tree/simpleSchema.ts +20 -0
  361. package/src/simple-tree/toStoredSchema.ts +28 -1
  362. package/src/tableSchema.ts +16 -28
  363. package/src/text/textDomain.ts +68 -1
  364. package/src/util/index.ts +0 -1
  365. package/src/util/utils.ts +0 -2
  366. package/.mocharc.customBenchmarks.cjs +0 -25
@@ -102,10 +102,6 @@ export {
102
102
  AnnotatedAllowedTypeUnsafe,
103
103
  AnnotatedAllowedTypes,
104
104
  AnnotatedAllowedTypesUnsafe,
105
- ArrayNodeDeltaOp,
106
- ArrayNodeInsertOp,
107
- ArrayNodeRemoveOp,
108
- ArrayNodeRetainOp,
109
105
  CodecWriteOptionsBeta,
110
106
  ConciseTree,
111
107
  ExtensibleUnionNode,
@@ -116,13 +112,11 @@ export {
116
112
  ForestTypeExpensiveDebug,
117
113
  ForestTypeOptimized,
118
114
  ForestTypeReference,
115
+ IdentifierIndex,
119
116
  JsonCompatible,
120
117
  JsonCompatibleObject,
121
118
  KeyEncodingOptions,
122
- NodeChangedData,
123
- NodeChangedDataAlpha,
124
- NodeChangedDataDelta,
125
- NodeChangedDataProperties,
119
+ NodeChangedData,
126
120
  ObjectSchemaOptions,
127
121
  PopUnion,
128
122
  RecordNodeInsertableData,
@@ -136,9 +130,11 @@ export {
136
130
  TableSchema,
137
131
  TreeBeta,
138
132
  TreeBranch,
139
- TreeChangeEventsBeta,
140
- TreeChangeEventsAlpha,
133
+ TreeChangeEventsBeta,
141
134
  TreeEncodingOptions,
135
+ TreeIndex,
136
+ TreeIndexKey,
137
+ TreeIndexNodes,
142
138
  TreeRecordNode,
143
139
  TreeRecordNodeUnsafe,
144
140
  TreeViewBeta,
@@ -149,7 +145,9 @@ export {
149
145
  adaptEnum,
150
146
  asBeta,
151
147
  configuredSharedTreeBeta,
148
+ createIdentifierIndex,
152
149
  createIndependentTreeBeta,
150
+ createTreeIndex,
153
151
  enumFromStrings,
154
152
  singletonSchema,
155
153
  snapshotSchemaCompatibility,
@@ -160,8 +158,14 @@ export {
160
158
  ArrayNodeCustomizableSchema,
161
159
  ArrayNodeCustomizableSchemaAlpha,
162
160
  ArrayNodeCustomizableSchemaUnsafe,
161
+ ArrayNodeDeltaOp,
162
+ ArrayNodeInsertOp,
163
163
  ArrayNodePojoEmulationSchema,
164
+ ArrayNodeRemoveOp,
165
+ ArrayNodeRetainOp,
164
166
  ArrayNodeSchema,
167
+ ArrayNodeTreeChangedDeltaOp,
168
+ ArrayNodeTreeChangedRetainOp,
165
169
  ArrayPlaceAnchor,
166
170
  ChangeMetadata,
167
171
  CodecName,
@@ -187,7 +191,6 @@ export {
187
191
  HandleConverter,
188
192
  ICodecOptions,
189
193
  ITreeAlpha,
190
- IdentifierIndex,
191
194
  IncrementalEncodingPolicy,
192
195
  IndependentViewOptions,
193
196
  Insertable,
@@ -220,6 +223,10 @@ export {
220
223
  MapNodePojoEmulationSchema,
221
224
  MapNodeSchema,
222
225
  NoChangeConstraint,
226
+ NodeChangedDataAlpha,
227
+ NodeChangedDataDelta,
228
+ NodeChangedDataProperties,
229
+ NodeChangedDataTreeDelta,
223
230
  NodeProvider,
224
231
  NodeSchemaOptionsAlpha,
225
232
  ObjectNodeSchema,
@@ -263,12 +270,11 @@ export {
263
270
  TreeArrayNodeAlpha,
264
271
  TreeBranchAlpha,
265
272
  TreeBranchEvents,
273
+ TreeChangeEventsAlpha,
266
274
  TreeCompressionStrategy,
267
275
  TreeContextAlpha,
268
276
  TreeIdentifierUtils,
269
- TreeIndex,
270
- TreeIndexKey,
271
- TreeIndexNodes,
277
+ TreeMapNodeAlpha,
272
278
  TreeParsingOptions,
273
279
  TreeSchema,
274
280
  TreeSchemaEncodingOptions,
@@ -290,9 +296,7 @@ export {
290
296
  configuredSharedTreeAlpha,
291
297
  contentSchemaSymbol,
292
298
  createArrayInsertionAnchor,
293
- createIdentifierIndex,
294
299
  createIndependentTreeAlpha,
295
- createTreeIndex,
296
300
  decodeSchemaCompatibilitySnapshot,
297
301
  encodeSchemaCompatibilitySnapshot,
298
302
  eraseSchemaDetails,
@@ -112,10 +112,11 @@ export {
112
112
  ForestTypeExpensiveDebug,
113
113
  ForestTypeOptimized,
114
114
  ForestTypeReference,
115
+ IdentifierIndex,
115
116
  JsonCompatible,
116
117
  JsonCompatibleObject,
117
118
  KeyEncodingOptions,
118
- NodeChangedData,
119
+ NodeChangedData,
119
120
  ObjectSchemaOptions,
120
121
  PopUnion,
121
122
  RecordNodeInsertableData,
@@ -131,6 +132,9 @@ export {
131
132
  TreeBranch,
132
133
  TreeChangeEventsBeta,
133
134
  TreeEncodingOptions,
135
+ TreeIndex,
136
+ TreeIndexKey,
137
+ TreeIndexNodes,
134
138
  TreeRecordNode,
135
139
  TreeRecordNodeUnsafe,
136
140
  TreeViewBeta,
@@ -141,7 +145,9 @@ export {
141
145
  adaptEnum,
142
146
  asBeta,
143
147
  configuredSharedTreeBeta,
148
+ createIdentifierIndex,
144
149
  createIndependentTreeBeta,
150
+ createTreeIndex,
145
151
  enumFromStrings,
146
152
  singletonSchema,
147
153
  snapshotSchemaCompatibility
@@ -102,10 +102,6 @@ export {
102
102
  AnnotatedAllowedTypeUnsafe,
103
103
  AnnotatedAllowedTypes,
104
104
  AnnotatedAllowedTypesUnsafe,
105
- ArrayNodeDeltaOp,
106
- ArrayNodeInsertOp,
107
- ArrayNodeRemoveOp,
108
- ArrayNodeRetainOp,
109
105
  CodecWriteOptionsBeta,
110
106
  ConciseTree,
111
107
  ExtensibleUnionNode,
@@ -116,13 +112,11 @@ export {
116
112
  ForestTypeExpensiveDebug,
117
113
  ForestTypeOptimized,
118
114
  ForestTypeReference,
115
+ IdentifierIndex,
119
116
  JsonCompatible,
120
117
  JsonCompatibleObject,
121
118
  KeyEncodingOptions,
122
- NodeChangedData,
123
- NodeChangedDataAlpha,
124
- NodeChangedDataDelta,
125
- NodeChangedDataProperties,
119
+ NodeChangedData,
126
120
  ObjectSchemaOptions,
127
121
  PopUnion,
128
122
  RecordNodeInsertableData,
@@ -136,9 +130,11 @@ export {
136
130
  TableSchema,
137
131
  TreeBeta,
138
132
  TreeBranch,
139
- TreeChangeEventsBeta,
140
- TreeChangeEventsAlpha,
133
+ TreeChangeEventsBeta,
141
134
  TreeEncodingOptions,
135
+ TreeIndex,
136
+ TreeIndexKey,
137
+ TreeIndexNodes,
142
138
  TreeRecordNode,
143
139
  TreeRecordNodeUnsafe,
144
140
  TreeViewBeta,
@@ -149,7 +145,9 @@ export {
149
145
  adaptEnum,
150
146
  asBeta,
151
147
  configuredSharedTreeBeta,
148
+ createIdentifierIndex,
152
149
  createIndependentTreeBeta,
150
+ createTreeIndex,
153
151
  enumFromStrings,
154
152
  singletonSchema,
155
153
  snapshotSchemaCompatibility,
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert, oob, fail } from "@fluidframework/core-utils/internal";
6
+ import { assert, oob, fail, debugAssert } from "@fluidframework/core-utils/internal";
7
7
 
8
8
  import {
9
9
  CursorLocationType,
@@ -166,10 +166,19 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
166
166
  if (this.nestedCursor !== undefined) {
167
167
  return this.nestedCursor.mode;
168
168
  }
169
- // Compute the number of nodes deep the current depth is.
170
- // We want the floor of the result, which can computed using a bitwise shift assuming the depth is less than 2^31, which seems safe.
171
- // eslint-disable-next-line no-bitwise
172
- const halfHeight = (this.siblingStack.length + 1) >> 1;
169
+ this.assertChunkStacksMatchNodeDepth();
170
+ return this.siblingStack.length % 2 === 0
171
+ ? CursorLocationType.Fields
172
+ : CursorLocationType.Nodes;
173
+ }
174
+
175
+ /**
176
+ * Asserts that the node-only stacks (`indexOfChunkStack` and `indexWithinChunkStack`) are in sync with `siblingStack`.
177
+ * Since `siblingStack` interleaves field and node levels while the node-only stacks are pushed/popped only on node-level transitions,
178
+ * their length should always equal the number of node levels traversed.
179
+ */
180
+ private assertChunkStacksMatchNodeDepth(): void {
181
+ const halfHeight = this.getNodeOnlyHeightFromHeight();
173
182
  assert(
174
183
  this.indexOfChunkStack.length === halfHeight,
175
184
  0x51c /* unexpected indexOfChunkStack */,
@@ -178,9 +187,6 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
178
187
  this.indexWithinChunkStack.length === halfHeight,
179
188
  0x51d /* unexpected indexWithinChunkStack */,
180
189
  );
181
- return this.siblingStack.length % 2 === 0
182
- ? CursorLocationType.Fields
183
- : CursorLocationType.Nodes;
184
190
  }
185
191
 
186
192
  public getFieldKey(): FieldKey {
@@ -203,9 +209,32 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
203
209
  return this.indexStack[height] ?? oob();
204
210
  }
205
211
 
206
- private getStackedNode(height: number): BasicChunk {
207
- const index = this.getStackedNodeIndex(height);
208
- return (this.siblingStack[height] as readonly TreeChunk[])[index] as BasicChunk;
212
+ private getStackedChunkIndex(height: number): number {
213
+ assert(height % 2 === 1, 0xcf3 /* must be node height */);
214
+ assert(height >= 0, 0xcf4 /* must not be above root */);
215
+ return this.indexOfChunkStack[this.getNodeOnlyHeightFromHeight(height)] ?? oob();
216
+ }
217
+
218
+ private getStackedChunk(height: number): BasicChunk {
219
+ const index = this.getStackedChunkIndex(height);
220
+ const chunk = (this.siblingStack[height] as readonly TreeChunk[])[index];
221
+ debugAssert(() => chunk instanceof BasicChunk || "only basic chunks are expected");
222
+ return chunk as BasicChunk;
223
+ }
224
+
225
+ /**
226
+ * Converts a {@link height}, which contains field and node levels, into the corresponding depth/index
227
+ * for the node-only stacks ({@link indexOfChunkStack} and {@link indexWithinChunkStack}), which are
228
+ * only pushed on node-level transitions.
229
+ *
230
+ * @param height - A depth in {@link siblingStack} to convert. Defaults to {@link siblingStack}'s
231
+ * current length, which gives the current depth of the node-only stacks.
232
+ * @returns `floor(height / 2)` — the number of node levels at or below the given stack height.
233
+ */
234
+ private getNodeOnlyHeightFromHeight(height: number = this.siblingStack.length): number {
235
+ // The bitwise shift computes the floor, which is valid assuming the depth is less than 2^31, which seems safe.
236
+ // eslint-disable-next-line no-bitwise
237
+ return height >> 1;
209
238
  }
210
239
 
211
240
  public getFieldLength(): number {
@@ -322,6 +351,11 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
322
351
  assert(this.mode === CursorLocationType.Nodes, 0x528 /* must be in nodes mode */);
323
352
  this.siblingStack.push(this.siblings);
324
353
  this.indexStack.push(this.index);
354
+ // Save the chunk array position of the current node. When siblings contain
355
+ // multi node chunks, the flat node index diverges from the array position,
356
+ // so getField needs this to locate the parent in the sibling array.
357
+ this.indexOfChunkStack.push(this.indexOfChunk);
358
+ this.indexWithinChunkStack.push(this.indexWithinChunk);
325
359
 
326
360
  // For fields, siblings are only used for key lookup and
327
361
  // nextField and which has arbitrary iteration order,
@@ -330,6 +364,7 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
330
364
  // at the cost of an allocation here.
331
365
  this.index = 0;
332
366
  this.siblings = [key];
367
+ this.assertChunkStacksMatchNodeDepth();
333
368
  }
334
369
 
335
370
  public nextField(): boolean {
@@ -355,8 +390,11 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
355
390
 
356
391
  this.siblingStack.push(this.siblings);
357
392
  this.indexStack.push(this.index);
393
+ this.indexOfChunkStack.push(this.indexOfChunk);
394
+ this.indexWithinChunkStack.push(this.indexWithinChunk);
358
395
  this.index = 0;
359
396
  this.siblings = [...fields.keys()]; // TODO: avoid this copy
397
+ this.assertChunkStacksMatchNodeDepth();
360
398
  return true;
361
399
  }
362
400
 
@@ -422,12 +460,11 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
422
460
  }
423
461
  this.siblingStack.push(this.siblings);
424
462
  this.indexStack.push(this.index);
425
- this.indexOfChunkStack.push(this.indexOfChunk);
426
- this.indexWithinChunkStack.push(this.indexWithinChunk);
427
463
  this.index = 0;
428
464
  this.siblings = siblings;
429
465
  this.indexOfChunk = 0;
430
466
  this.indexWithinChunk = 0;
467
+ this.assertChunkStacksMatchNodeDepth();
431
468
  this.initNestedCursor();
432
469
  return true;
433
470
  }
@@ -486,6 +523,12 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
486
523
  this.siblings =
487
524
  this.siblingStack.pop() ?? fail(0xaf0 /* Unexpected siblingStack.length */);
488
525
  this.index = this.indexStack.pop() ?? fail(0xaf1 /* Unexpected indexStack.length */);
526
+ this.indexOfChunk =
527
+ this.indexOfChunkStack.pop() ?? fail(0xcf5 /* Unexpected indexOfChunkStack.length */);
528
+ this.indexWithinChunk =
529
+ this.indexWithinChunkStack.pop() ??
530
+ fail(0xcf6 /* Unexpected indexWithinChunkStack.length */);
531
+ this.assertChunkStacksMatchNodeDepth();
489
532
  }
490
533
 
491
534
  public exitNode(): void {
@@ -502,18 +545,27 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
502
545
  this.siblings =
503
546
  this.siblingStack.pop() ?? fail(0xaf2 /* Unexpected siblingStack.length */);
504
547
  this.index = this.indexStack.pop() ?? fail(0xaf3 /* Unexpected indexStack.length */);
505
- this.indexOfChunk =
506
- this.indexOfChunkStack.pop() ?? fail(0xaf4 /* Unexpected indexOfChunkStack.length */);
507
- this.indexWithinChunk =
508
- this.indexWithinChunkStack.pop() ??
509
- fail(0xaf5 /* Unexpected indexWithinChunkStack.length */);
548
+ // At the Fields level these aren't semantically used, but reset for consistent state
549
+ // (so a fully-iterated cursor matches a fresh cursor at the same logical position).
550
+ this.indexOfChunk = 0;
551
+ this.indexWithinChunk = 0;
552
+ this.assertChunkStacksMatchNodeDepth();
510
553
  }
511
554
 
512
555
  private getNode(): BasicChunk {
513
556
  assert(this.mode === CursorLocationType.Nodes, 0x52f /* can only get node when in node */);
514
- return (this.siblings as TreeChunk[])[this.index] as BasicChunk;
557
+ const chunk = (this.siblings as TreeChunk[])[this.indexOfChunk];
558
+ debugAssert(() => chunk instanceof BasicChunk || "only basic chunks are expected");
559
+ return chunk as BasicChunk;
515
560
  }
516
561
 
562
+ /**
563
+ * Resolves the chunks that make up the field the cursor is currently in. At the root, this is
564
+ * {@link root} directly. Otherwise, the cursor must be in {@link CursorLocationType.Fields} mode,
565
+ * and the result is looked up on the parent node using the current field key.
566
+ *
567
+ * @returns The chunks that make up the field the cursor is currently in.
568
+ */
517
569
  private getField(): readonly TreeChunk[] {
518
570
  if (this.siblingStack.length === 0) {
519
571
  return this.root;
@@ -522,7 +574,11 @@ export class BasicChunkCursor extends SynchronousCursor implements ChunkedCursor
522
574
  this.mode === CursorLocationType.Fields,
523
575
  0x530 /* can only get field when in fields */,
524
576
  );
525
- const parent = this.getStackedNode(this.indexStack.length - 1);
577
+ // The parent node is the `BasicChunk` in the node array at the top of
578
+ // `siblingStack` while we are in `CursorLocationType.Fields` mode. We need the parent
579
+ // since a field's chunks are stored on the parent node's `BasicChunk.fields` map, not on
580
+ // the cursor itself.
581
+ const parent = this.getStackedChunk(this.siblingStack.length - 1);
526
582
  const key: FieldKey = this.getFieldKey();
527
583
  const field = parent.fields.get(key) ?? [];
528
584
  return field;
@@ -424,8 +424,8 @@ export interface ChunkCompressor {
424
424
  /**
425
425
  * If the idCompressor is provided, {@link UniformChunk}s with identifiers will be encoded for its in-memory representation.
426
426
  * @remarks
427
- * This compression applies to {@link UniformChunk}s when {@link TreeShape.maybeDecompressedStringAsNumber} is set.
428
- * If the `policy` does not use UniformChunks or does not set `maybeDecompressedStringAsNumber`, then no compression will be applied even when providing `idCompressor`.
427
+ * This compression applies to {@link UniformChunk}s when {@link TreeShape.mayContainCompressedIds} is set.
428
+ * If the `policy` does not use UniformChunks or does not set `mayContainCompressedIds`, then no compression will be applied even when providing `idCompressor`.
429
429
  */
430
430
  readonly idCompressor: IIdCompressor | undefined;
431
431
  }
@@ -583,6 +583,7 @@ export function insertValues(
583
583
  // Slow path: walk shape and cursor together, inserting values.
584
584
  if (shape.hasValue) {
585
585
  if (
586
+ shape.mayContainCompressedIds &&
586
587
  typeof cursor.value === "string" &&
587
588
  idCompressor !== undefined &&
588
589
  isStableNodeIdentifier(cursor.value)
@@ -49,8 +49,8 @@ import {
49
49
  type EncodedNestedArrayShape,
50
50
  type EncodedNodeShape,
51
51
  type EncodedValueShape,
52
- FieldBatchFormatVersion,
53
52
  SpecialField,
53
+ supportsIncrementalEncoding,
54
54
  } from "./format/index.js";
55
55
 
56
56
  export interface IdDecodingContext {
@@ -256,7 +256,7 @@ export class IncrementalChunkDecoder implements ChunkDecoder {
256
256
 
257
257
  const chunkDecoder = (batch: EncodedFieldBatchV2): TreeChunk => {
258
258
  assert(
259
- batch.version >= FieldBatchFormatVersion.v2,
259
+ supportsIncrementalEncoding(batch.version),
260
260
  0xc9f /* Unsupported FieldBatchFormatVersion for incremental chunks; must be v2 or higher */,
261
261
  );
262
262
  const context = new DecoderContext(
@@ -30,6 +30,7 @@ import {
30
30
  EncodedFieldBatchV1,
31
31
  EncodedFieldBatchV2,
32
32
  FieldBatchFormatVersion,
33
+ supportsIncrementalEncoding,
33
34
  type EncodedFieldBatchV1OrV2,
34
35
  } from "./format/index.js";
35
36
  import type { IncrementalEncodingPolicy } from "./incrementalEncodingPolicy.js";
@@ -147,7 +148,7 @@ function makeFieldBatchCodecForVersion(
147
148
  }
148
149
  case TreeCompressionStrategy.CompressedIncremental: {
149
150
  assert(
150
- version >= FieldBatchFormatVersion.v2,
151
+ supportsIncrementalEncoding(version),
151
152
  0xca0 /* Unsupported FieldBatchFormatVersion for incremental encoding; must be v2 or higher */,
152
153
  );
153
154
  // Incremental encoding is only supported for CompressedIncremental.
@@ -36,8 +36,9 @@ import {
36
36
  type EncodedFieldBatchV1OrV2,
37
37
  type EncodedNestedArrayShape,
38
38
  type EncodedValueShape,
39
- FieldBatchFormatVersion,
39
+ type FieldBatchFormatVersion,
40
40
  SpecialField,
41
+ supportsIncrementalEncoding,
41
42
  } from "./format/index.js";
42
43
 
43
44
  /**
@@ -461,7 +462,7 @@ export const incrementalFieldEncoder: FieldEncoder = {
461
462
  0xc88 /* incremental encoder must be defined to use incrementalFieldEncoder */,
462
463
  );
463
464
  assert(
464
- context.version >= FieldBatchFormatVersion.v2,
465
+ supportsIncrementalEncoding(context.version),
465
466
  0xca1 /* Unsupported FieldBatchFormatVersion for incremental encoding; must be v2 or higher */,
466
467
  );
467
468
 
@@ -28,7 +28,6 @@ export const Count = Type.Number({ multipleOf: 1, minimum: 0 });
28
28
 
29
29
  const EncodedFieldBatchBase = Type.Object(
30
30
  {
31
- version: Type.Number(),
32
31
  identifiers: Type.Array(Type.String()),
33
32
  /**
34
33
  * Top level array is list of field from batch.
@@ -20,6 +20,7 @@ export {
20
20
  FieldBatchFormatVersion,
21
21
  EncodedFieldBatchV1,
22
22
  EncodedFieldBatchV2,
23
+ supportsIncrementalEncoding,
23
24
  type EncodedFieldBatchV1OrV2,
24
25
  type EncodedFieldBatchV1AndV2,
25
26
  type EncodedChunkShapeV1OrV2,
@@ -31,6 +31,21 @@ export const FieldBatchFormatVersion = strictEnum("FieldBatchFormatVersion", {
31
31
  v2: 2,
32
32
  });
33
33
 
34
+ /**
35
+ * Whether the given format version supports incremental chunk encoding.
36
+ *
37
+ * @remarks
38
+ * This helper should be used for comparison since experimental versions
39
+ * can be a string.
40
+ */
41
+ export function supportsIncrementalEncoding(version: FieldBatchFormatVersion): boolean {
42
+ if (version === FieldBatchFormatVersion.v1) {
43
+ return false;
44
+ }
45
+
46
+ return true;
47
+ }
48
+
34
49
  /**
35
50
  * Encoded {@link FieldBatch} using V1 format.
36
51
  * @remarks
@@ -5,7 +5,6 @@
5
5
 
6
6
  import { assert, compareArrays, oob, fail } from "@fluidframework/core-utils/internal";
7
7
  import type { SessionSpaceCompressedId, IIdCompressor } from "@fluidframework/id-compressor";
8
- import { UsageError } from "@fluidframework/telemetry-utils/internal";
9
8
 
10
9
  import {
11
10
  CursorLocationType,
@@ -21,7 +20,7 @@ import {
21
20
  cursorChunk,
22
21
  dummyRoot,
23
22
  } from "../../core/index.js";
24
- import { ReferenceCountedBase, hasSome } from "../../util/index.js";
23
+ import { ReferenceCountedBase, getOrCreate, hasSome } from "../../util/index.js";
25
24
  import { SynchronousCursor, prefixFieldPath, prefixPath } from "../treeCursorUtils.js";
26
25
 
27
26
  /**
@@ -54,7 +53,7 @@ export class UniformChunk extends ReferenceCountedBase implements TreeChunk {
54
53
  idCompressor?: IIdCompressor,
55
54
  ) {
56
55
  super();
57
- this.idCompressor = idCompressor;
56
+ this.idCompressor = shape.treeShape.mayContainCompressedIds ? idCompressor : undefined;
58
57
  assert(
59
58
  shape.treeShape.valuesPerTopLevelNode * shape.topLevelLength === values.length,
60
59
  0x4c3 /* invalid number of values for shape */,
@@ -84,6 +83,23 @@ export class UniformChunk extends ReferenceCountedBase implements TreeChunk {
84
83
  */
85
84
  export type FieldShape = readonly [FieldKey, TreeShape, number];
86
85
 
86
+ /**
87
+ * Maximum topLevelLength value (exclusive) for which {@link TreeShape.withTopLevelLength}
88
+ * caches the resulting {@link ChunkShape}. Values at or above this threshold always
89
+ * create a new instance to prevent unbounded cache growth.
90
+ *
91
+ * @remarks
92
+ * This value is an estimation of the general size needed to cover current workflows,
93
+ * not a researched constant, and is safe to tune as workloads change.
94
+ *
95
+ * Raising this value captures more chunk sizes in the cache, at the cost of
96
+ * each `TreeShape` retaining up to `chunkShapeCacheLimit - 1` cached entries for the
97
+ * lifetime of the shape. Lowering it reduces memory held per `TreeShape` but forces
98
+ * small chunks, where the relative cost of rebuilding `positions` is highest, to pay
99
+ * the construction cost on every call.
100
+ */
101
+ const chunkShapeCacheLimit = 8;
102
+
87
103
  /**
88
104
  * The "shape" of a tree.
89
105
  * Does not contain the actual values from the tree, but describes everything else,
@@ -101,29 +117,50 @@ export class TreeShape {
101
117
  public readonly positions: readonly NodePositionInfo[];
102
118
 
103
119
  /**
120
+ * Whether chunks using this shape (including any descendant leaf within it) may contain values compressed by the {@link UniformChunk.idCompressor}.
104
121
  *
122
+ * @remarks
123
+ * For string leaf nodes, this can be explicitly set to `true` to indicate that the value may be a compressed id
124
+ * stored as a number that needs to be decompressed back to a string.
125
+ * For non-leaf nodes, this is automatically derived from whether any child shapes have it set.
126
+ */
127
+ public readonly mayContainCompressedIds: boolean;
128
+
129
+ /**
130
+ * Cache for ChunkShape instances created by {@link withTopLevelLength}.
131
+ * `topLevelLength` is always a positive integer (enforced by the {@link ChunkShape} constructor),
132
+ * so the cache only ever holds entries for values in `1..chunkShapeCacheLimit - 1` to prevent unbounded growth.
133
+ */
134
+ private readonly chunkShapeCache: Map<number, ChunkShape> = new Map();
135
+
136
+ /**
105
137
  * @param type - {@link TreeNodeSchemaIdentifier} used to compare shapes.
106
138
  * @param hasValue - whether or not the TreeShape has a value.
107
139
  * @param fieldsArray - an array of {@link FieldShape} values, which contains a TreeShape for each FieldKey.
108
140
  *
109
- * @param maybeDecompressedStringAsNumber - used to check whether or not the value could have been compressed by the idCompressor.
110
- * This flag can only be set on string leaf nodes, and will throw a usage error otherwise.
111
- * If set to true, an additional check can be made (example: getting the value of {@link Cursor}) to return the original uncompressed value.
141
+ * @param maybeCompressedIdLeaf - whether the value may have been compressed by the {@link UniformChunk.idCompressor}.
142
+ * Can only be explicitly set to `true` on string leaf nodes; otherwise this constructor asserts.
143
+ * For non-leaf nodes, {@link TreeShape.mayContainCompressedIds} is automatically derived from child shapes.
112
144
  */
113
145
  public constructor(
114
146
  public readonly type: TreeNodeSchemaIdentifier,
115
147
  public readonly hasValue: boolean,
116
148
  public readonly fieldsArray: readonly FieldShape[],
117
- public readonly maybeDecompressedStringAsNumber: boolean = false,
149
+ maybeCompressedIdLeaf: boolean = false,
118
150
  ) {
119
- if (
120
- maybeDecompressedStringAsNumber &&
121
- !(hasValue && type === "com.fluidframework.leaf.string")
122
- ) {
123
- throw new UsageError(
124
- "maybeDecompressedStringAsNumber flag can only be set to true for string leaf node.",
151
+ assert(
152
+ hasValue === false || fieldsArray.length === 0,
153
+ 0xcef /* only non-leaf can have fields */,
154
+ );
155
+ if (maybeCompressedIdLeaf) {
156
+ assert(
157
+ hasValue && type === "com.fluidframework.leaf.string",
158
+ 0xcf0 /* only strings can opt into maybeCompressedIdLeaf */,
125
159
  );
126
160
  }
161
+ // For non-leaf nodes, derive from whether any child shapes contain compressed ids.
162
+ this.mayContainCompressedIds =
163
+ maybeCompressedIdLeaf || fieldsArray.some(([, shape]) => shape.mayContainCompressedIds);
127
164
  const fields: Map<FieldKey, OffsetShape> = new Map();
128
165
  let numberOfValues = hasValue ? 1 : 0;
129
166
  const infos: NodePositionInfo[] = [
@@ -146,7 +183,7 @@ export class TreeShape {
146
183
  }
147
184
 
148
185
  public equals(other: TreeShape): boolean {
149
- // TODO: either dedup instances and/or store a collision resistant hash for fast compare.
186
+ // TODO: either dedupe instances and/or store a collision resistant hash for fast compare.
150
187
 
151
188
  if (
152
189
  !compareArrays(
@@ -157,10 +194,21 @@ export class TreeShape {
157
194
  ) {
158
195
  return false;
159
196
  }
160
- return this.type === other.type && this.hasValue === other.hasValue;
197
+ return (
198
+ this.type === other.type &&
199
+ this.hasValue === other.hasValue &&
200
+ this.mayContainCompressedIds === other.mayContainCompressedIds
201
+ );
161
202
  }
162
203
 
163
204
  public withTopLevelLength(topLevelLength: number): ChunkShape {
205
+ if (topLevelLength < chunkShapeCacheLimit) {
206
+ return getOrCreate(
207
+ this.chunkShapeCache,
208
+ topLevelLength,
209
+ () => new ChunkShape(this, topLevelLength),
210
+ );
211
+ }
164
212
  return new ChunkShape(this, topLevelLength);
165
213
  }
166
214
  }
@@ -548,16 +596,20 @@ class Cursor extends SynchronousCursor implements ChunkedCursor {
548
596
  }
549
597
 
550
598
  public get value(): Value {
551
- const idCompressor = this.chunk.idCompressor;
552
599
  const info = this.nodeInfo(CursorLocationType.Nodes);
553
- // If the maybeDecompressedStringAsNumber flag is set to true, we check if the value is a number.
554
- // This flag can only ever be set on string leaf nodes, so if the value is a number, we can assume it is a compressible, known stable id.
555
- if (info.shape.hasValue && info.shape.maybeDecompressedStringAsNumber) {
600
+ if (info.shape.hasValue) {
556
601
  const value = this.chunk.values[info.valueOffset];
557
- if (typeof value === "number" && idCompressor !== undefined) {
602
+ // If mayContainCompressedIds is set, check if the value is a number (i.e. a compressed ID that needs decompression).
603
+ if (info.shape.mayContainCompressedIds && typeof value === "number") {
604
+ const idCompressor = this.chunk.idCompressor;
605
+ assert(
606
+ idCompressor !== undefined,
607
+ 0xcf1 /* chunk required idCompressor but did not provide it */,
608
+ );
558
609
  return idCompressor.decompress(value as SessionSpaceCompressedId);
559
610
  }
611
+ return value;
560
612
  }
561
- return info.shape.hasValue ? this.chunk.values[info.valueOffset] : undefined;
613
+ return undefined;
562
614
  }
563
615
  }