@fluidframework/container-runtime 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191457

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 (526) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/README.md +4 -3
  3. package/dist/batchTracker.d.ts +3 -2
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/batchTracker.js +6 -5
  6. package/dist/batchTracker.js.map +1 -1
  7. package/dist/blobManager.d.ts +10 -16
  8. package/dist/blobManager.d.ts.map +1 -1
  9. package/dist/blobManager.js +184 -172
  10. package/dist/blobManager.js.map +1 -1
  11. package/dist/connectionTelemetry.d.ts.map +1 -1
  12. package/dist/connectionTelemetry.js +25 -16
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerRuntime.d.ts +161 -35
  15. package/dist/containerRuntime.d.ts.map +1 -1
  16. package/dist/containerRuntime.js +697 -449
  17. package/dist/containerRuntime.js.map +1 -1
  18. package/dist/dataStore.d.ts.map +1 -1
  19. package/dist/dataStore.js +15 -7
  20. package/dist/dataStore.js.map +1 -1
  21. package/dist/dataStoreContext.d.ts +3 -2
  22. package/dist/dataStoreContext.d.ts.map +1 -1
  23. package/dist/dataStoreContext.js +83 -87
  24. package/dist/dataStoreContext.js.map +1 -1
  25. package/dist/dataStoreContexts.d.ts +1 -2
  26. package/dist/dataStoreContexts.d.ts.map +1 -1
  27. package/dist/dataStoreContexts.js +8 -9
  28. package/dist/dataStoreContexts.js.map +1 -1
  29. package/dist/dataStoreRegistry.js +2 -2
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.d.ts +22 -6
  32. package/dist/dataStores.d.ts.map +1 -1
  33. package/dist/dataStores.js +123 -81
  34. package/dist/dataStores.js.map +1 -1
  35. package/dist/deltaManagerProxyBase.d.ts +35 -0
  36. package/dist/deltaManagerProxyBase.d.ts.map +1 -0
  37. package/dist/deltaManagerProxyBase.js +77 -0
  38. package/dist/deltaManagerProxyBase.js.map +1 -0
  39. package/dist/deltaManagerSummarizerProxy.d.ts +1 -1
  40. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  41. package/dist/deltaManagerSummarizerProxy.js +4 -2
  42. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  43. package/dist/deltaScheduler.d.ts.map +1 -1
  44. package/dist/deltaScheduler.js +10 -10
  45. package/dist/deltaScheduler.js.map +1 -1
  46. package/dist/error.d.ts +14 -0
  47. package/dist/error.d.ts.map +1 -0
  48. package/dist/error.js +21 -0
  49. package/dist/error.js.map +1 -0
  50. package/dist/gc/garbageCollection.d.ts +10 -9
  51. package/dist/gc/garbageCollection.d.ts.map +1 -1
  52. package/dist/gc/garbageCollection.js +61 -53
  53. package/dist/gc/garbageCollection.js.map +1 -1
  54. package/dist/gc/gcConfigs.d.ts.map +1 -1
  55. package/dist/gc/gcConfigs.js +18 -14
  56. package/dist/gc/gcConfigs.js.map +1 -1
  57. package/dist/gc/gcDefinitions.d.ts +17 -4
  58. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  59. package/dist/gc/gcDefinitions.js +14 -15
  60. package/dist/gc/gcDefinitions.js.map +1 -1
  61. package/dist/gc/gcHelpers.d.ts +0 -8
  62. package/dist/gc/gcHelpers.d.ts.map +1 -1
  63. package/dist/gc/gcHelpers.js +11 -24
  64. package/dist/gc/gcHelpers.js.map +1 -1
  65. package/dist/gc/gcSummaryStateTracker.d.ts +4 -7
  66. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  67. package/dist/gc/gcSummaryStateTracker.js +19 -58
  68. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  69. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  70. package/dist/gc/gcTelemetry.js +45 -35
  71. package/dist/gc/gcTelemetry.js.map +1 -1
  72. package/dist/gc/gcUnreferencedStateTracker.js +4 -4
  73. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  74. package/dist/gc/index.d.ts +2 -2
  75. package/dist/gc/index.d.ts.map +1 -1
  76. package/dist/gc/index.js +3 -5
  77. package/dist/gc/index.js.map +1 -1
  78. package/dist/id-compressor/appendOnlySortedMap.d.ts +8 -30
  79. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  80. package/dist/id-compressor/appendOnlySortedMap.js +26 -68
  81. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  82. package/dist/id-compressor/finalSpace.d.ts +29 -0
  83. package/dist/id-compressor/finalSpace.d.ts.map +1 -0
  84. package/dist/id-compressor/finalSpace.js +62 -0
  85. package/dist/id-compressor/finalSpace.js.map +1 -0
  86. package/dist/id-compressor/idCompressor.d.ts +25 -250
  87. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  88. package/dist/id-compressor/idCompressor.js +390 -1153
  89. package/dist/id-compressor/idCompressor.js.map +1 -1
  90. package/dist/id-compressor/identifiers.d.ts +32 -0
  91. package/dist/id-compressor/identifiers.d.ts.map +1 -0
  92. package/dist/id-compressor/identifiers.js +15 -0
  93. package/dist/id-compressor/identifiers.js.map +1 -0
  94. package/dist/id-compressor/index.d.ts +5 -6
  95. package/dist/id-compressor/index.d.ts.map +1 -1
  96. package/dist/id-compressor/index.js +20 -26
  97. package/dist/id-compressor/index.js.map +1 -1
  98. package/dist/id-compressor/persistanceUtilities.d.ts +22 -0
  99. package/dist/id-compressor/persistanceUtilities.d.ts.map +1 -0
  100. package/dist/id-compressor/persistanceUtilities.js +43 -0
  101. package/dist/id-compressor/persistanceUtilities.js.map +1 -0
  102. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  103. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  104. package/dist/id-compressor/sessionSpaceNormalizer.js +80 -0
  105. package/dist/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  106. package/dist/id-compressor/sessions.d.ts +115 -0
  107. package/dist/id-compressor/sessions.d.ts.map +1 -0
  108. package/dist/id-compressor/sessions.js +305 -0
  109. package/dist/id-compressor/sessions.js.map +1 -0
  110. package/dist/id-compressor/utilities.d.ts +49 -0
  111. package/dist/id-compressor/utilities.d.ts.map +1 -0
  112. package/dist/id-compressor/utilities.js +166 -0
  113. package/dist/id-compressor/utilities.js.map +1 -0
  114. package/dist/index.d.ts +3 -3
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +6 -4
  117. package/dist/index.js.map +1 -1
  118. package/dist/opLifecycle/batchManager.js +10 -6
  119. package/dist/opLifecycle/batchManager.js.map +1 -1
  120. package/dist/opLifecycle/opCompressor.d.ts +2 -2
  121. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  122. package/dist/opLifecycle/opCompressor.js +12 -7
  123. package/dist/opLifecycle/opCompressor.js.map +1 -1
  124. package/dist/opLifecycle/opDecompressor.d.ts +2 -2
  125. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  126. package/dist/opLifecycle/opDecompressor.js +23 -20
  127. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  128. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  129. package/dist/opLifecycle/opGroupingManager.js +19 -9
  130. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  131. package/dist/opLifecycle/opSplitter.d.ts +2 -2
  132. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  133. package/dist/opLifecycle/opSplitter.js +22 -19
  134. package/dist/opLifecycle/opSplitter.js.map +1 -1
  135. package/dist/opLifecycle/outbox.d.ts +7 -5
  136. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  137. package/dist/opLifecycle/outbox.js +22 -31
  138. package/dist/opLifecycle/outbox.js.map +1 -1
  139. package/dist/opLifecycle/remoteMessageProcessor.d.ts +6 -1
  140. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  141. package/dist/opLifecycle/remoteMessageProcessor.js +19 -7
  142. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  143. package/dist/opProperties.js +1 -2
  144. package/dist/opProperties.js.map +1 -1
  145. package/dist/packageVersion.d.ts +1 -1
  146. package/dist/packageVersion.js +1 -1
  147. package/dist/packageVersion.js.map +1 -1
  148. package/dist/pendingStateManager.d.ts +18 -8
  149. package/dist/pendingStateManager.d.ts.map +1 -1
  150. package/dist/pendingStateManager.js +73 -51
  151. package/dist/pendingStateManager.js.map +1 -1
  152. package/dist/scheduleManager.d.ts.map +1 -1
  153. package/dist/scheduleManager.js +36 -32
  154. package/dist/scheduleManager.js.map +1 -1
  155. package/dist/summary/index.d.ts +3 -3
  156. package/dist/summary/index.d.ts.map +1 -1
  157. package/dist/summary/index.js +2 -1
  158. package/dist/summary/index.js.map +1 -1
  159. package/dist/summary/orderedClientElection.d.ts +3 -3
  160. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  161. package/dist/summary/orderedClientElection.js +26 -27
  162. package/dist/summary/orderedClientElection.js.map +1 -1
  163. package/dist/summary/runWhileConnectedCoordinator.js +3 -3
  164. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  165. package/dist/summary/runningSummarizer.d.ts +31 -10
  166. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  167. package/dist/summary/runningSummarizer.js +271 -139
  168. package/dist/summary/runningSummarizer.js.map +1 -1
  169. package/dist/summary/summarizer.d.ts +8 -7
  170. package/dist/summary/summarizer.d.ts.map +1 -1
  171. package/dist/summary/summarizer.js +79 -78
  172. package/dist/summary/summarizer.js.map +1 -1
  173. package/dist/summary/summarizerClientElection.d.ts +2 -2
  174. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  175. package/dist/summary/summarizerClientElection.js +7 -11
  176. package/dist/summary/summarizerClientElection.js.map +1 -1
  177. package/dist/summary/summarizerHeuristics.js +10 -14
  178. package/dist/summary/summarizerHeuristics.js.map +1 -1
  179. package/dist/summary/summarizerNode/index.d.ts +1 -1
  180. package/dist/summary/summarizerNode/index.d.ts.map +1 -1
  181. package/dist/summary/summarizerNode/index.js.map +1 -1
  182. package/dist/summary/summarizerNode/summarizerNode.d.ts +10 -19
  183. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  184. package/dist/summary/summarizerNode/summarizerNode.js +57 -130
  185. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  186. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  187. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  188. package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  189. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  190. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -14
  191. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  192. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +15 -101
  193. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  194. package/dist/summary/summarizerTypes.d.ts +38 -25
  195. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  196. package/dist/summary/summarizerTypes.js.map +1 -1
  197. package/dist/summary/summaryCollection.d.ts +2 -3
  198. package/dist/summary/summaryCollection.d.ts.map +1 -1
  199. package/dist/summary/summaryCollection.js +12 -13
  200. package/dist/summary/summaryCollection.js.map +1 -1
  201. package/dist/summary/summaryFormat.d.ts +3 -0
  202. package/dist/summary/summaryFormat.d.ts.map +1 -1
  203. package/dist/summary/summaryFormat.js +6 -4
  204. package/dist/summary/summaryFormat.js.map +1 -1
  205. package/dist/summary/summaryGenerator.d.ts +10 -4
  206. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  207. package/dist/summary/summaryGenerator.js +106 -57
  208. package/dist/summary/summaryGenerator.js.map +1 -1
  209. package/dist/summary/summaryManager.d.ts +8 -8
  210. package/dist/summary/summaryManager.d.ts.map +1 -1
  211. package/dist/summary/summaryManager.js +38 -28
  212. package/dist/summary/summaryManager.js.map +1 -1
  213. package/lib/batchTracker.d.ts +3 -2
  214. package/lib/batchTracker.d.ts.map +1 -1
  215. package/lib/batchTracker.js +5 -4
  216. package/lib/batchTracker.js.map +1 -1
  217. package/lib/blobManager.d.ts +10 -16
  218. package/lib/blobManager.d.ts.map +1 -1
  219. package/lib/blobManager.js +159 -147
  220. package/lib/blobManager.js.map +1 -1
  221. package/lib/connectionTelemetry.d.ts.map +1 -1
  222. package/lib/connectionTelemetry.js +15 -6
  223. package/lib/connectionTelemetry.js.map +1 -1
  224. package/lib/containerRuntime.d.ts +161 -35
  225. package/lib/containerRuntime.d.ts.map +1 -1
  226. package/lib/containerRuntime.js +651 -402
  227. package/lib/containerRuntime.js.map +1 -1
  228. package/lib/dataStore.d.ts.map +1 -1
  229. package/lib/dataStore.js +13 -5
  230. package/lib/dataStore.js.map +1 -1
  231. package/lib/dataStoreContext.d.ts +3 -2
  232. package/lib/dataStoreContext.d.ts.map +1 -1
  233. package/lib/dataStoreContext.js +47 -51
  234. package/lib/dataStoreContext.js.map +1 -1
  235. package/lib/dataStoreContexts.d.ts +1 -2
  236. package/lib/dataStoreContexts.d.ts.map +1 -1
  237. package/lib/dataStoreContexts.js +3 -4
  238. package/lib/dataStoreContexts.js.map +1 -1
  239. package/lib/dataStoreRegistry.js +1 -1
  240. package/lib/dataStoreRegistry.js.map +1 -1
  241. package/lib/dataStores.d.ts +22 -6
  242. package/lib/dataStores.d.ts.map +1 -1
  243. package/lib/dataStores.js +107 -65
  244. package/lib/dataStores.js.map +1 -1
  245. package/lib/deltaManagerProxyBase.d.ts +35 -0
  246. package/lib/deltaManagerProxyBase.d.ts.map +1 -0
  247. package/lib/deltaManagerProxyBase.js +73 -0
  248. package/lib/deltaManagerProxyBase.js.map +1 -0
  249. package/lib/deltaManagerSummarizerProxy.d.ts +1 -1
  250. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
  251. package/lib/deltaManagerSummarizerProxy.js +3 -1
  252. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  253. package/lib/deltaScheduler.d.ts.map +1 -1
  254. package/lib/deltaScheduler.js +7 -7
  255. package/lib/deltaScheduler.js.map +1 -1
  256. package/lib/error.d.ts +14 -0
  257. package/lib/error.d.ts.map +1 -0
  258. package/lib/error.js +17 -0
  259. package/lib/error.js.map +1 -0
  260. package/lib/gc/garbageCollection.d.ts +10 -9
  261. package/lib/gc/garbageCollection.d.ts.map +1 -1
  262. package/lib/gc/garbageCollection.js +61 -53
  263. package/lib/gc/garbageCollection.js.map +1 -1
  264. package/lib/gc/gcConfigs.d.ts.map +1 -1
  265. package/lib/gc/gcConfigs.js +16 -12
  266. package/lib/gc/gcConfigs.js.map +1 -1
  267. package/lib/gc/gcDefinitions.d.ts +17 -4
  268. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  269. package/lib/gc/gcDefinitions.js +13 -14
  270. package/lib/gc/gcDefinitions.js.map +1 -1
  271. package/lib/gc/gcHelpers.d.ts +0 -8
  272. package/lib/gc/gcHelpers.d.ts.map +1 -1
  273. package/lib/gc/gcHelpers.js +5 -17
  274. package/lib/gc/gcHelpers.js.map +1 -1
  275. package/lib/gc/gcSummaryStateTracker.d.ts +4 -7
  276. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  277. package/lib/gc/gcSummaryStateTracker.js +20 -59
  278. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  279. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  280. package/lib/gc/gcTelemetry.js +46 -36
  281. package/lib/gc/gcTelemetry.js.map +1 -1
  282. package/lib/gc/gcUnreferencedStateTracker.js +1 -1
  283. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  284. package/lib/gc/index.d.ts +2 -2
  285. package/lib/gc/index.d.ts.map +1 -1
  286. package/lib/gc/index.js +2 -2
  287. package/lib/gc/index.js.map +1 -1
  288. package/lib/id-compressor/appendOnlySortedMap.d.ts +8 -30
  289. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  290. package/lib/id-compressor/appendOnlySortedMap.js +25 -66
  291. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  292. package/lib/id-compressor/finalSpace.d.ts +29 -0
  293. package/lib/id-compressor/finalSpace.d.ts.map +1 -0
  294. package/lib/id-compressor/finalSpace.js +58 -0
  295. package/lib/id-compressor/finalSpace.js.map +1 -0
  296. package/lib/id-compressor/idCompressor.d.ts +25 -250
  297. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  298. package/lib/id-compressor/idCompressor.js +385 -1142
  299. package/lib/id-compressor/idCompressor.js.map +1 -1
  300. package/lib/id-compressor/identifiers.d.ts +32 -0
  301. package/lib/id-compressor/identifiers.d.ts.map +1 -0
  302. package/lib/id-compressor/identifiers.js +11 -0
  303. package/lib/id-compressor/identifiers.js.map +1 -0
  304. package/lib/id-compressor/index.d.ts +5 -6
  305. package/lib/id-compressor/index.d.ts.map +1 -1
  306. package/lib/id-compressor/index.js +5 -6
  307. package/lib/id-compressor/index.js.map +1 -1
  308. package/lib/id-compressor/persistanceUtilities.d.ts +22 -0
  309. package/lib/id-compressor/persistanceUtilities.d.ts.map +1 -0
  310. package/lib/id-compressor/persistanceUtilities.js +34 -0
  311. package/lib/id-compressor/persistanceUtilities.js.map +1 -0
  312. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  313. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  314. package/lib/id-compressor/sessionSpaceNormalizer.js +76 -0
  315. package/lib/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  316. package/lib/id-compressor/sessions.d.ts +115 -0
  317. package/lib/id-compressor/sessions.d.ts.map +1 -0
  318. package/lib/id-compressor/sessions.js +290 -0
  319. package/lib/id-compressor/sessions.js.map +1 -0
  320. package/lib/id-compressor/utilities.d.ts +49 -0
  321. package/lib/id-compressor/utilities.d.ts.map +1 -0
  322. package/lib/id-compressor/utilities.js +148 -0
  323. package/lib/id-compressor/utilities.js.map +1 -0
  324. package/lib/index.d.ts +3 -3
  325. package/lib/index.d.ts.map +1 -1
  326. package/lib/index.js +2 -2
  327. package/lib/index.js.map +1 -1
  328. package/lib/opLifecycle/batchManager.js +10 -6
  329. package/lib/opLifecycle/batchManager.js.map +1 -1
  330. package/lib/opLifecycle/opCompressor.d.ts +2 -2
  331. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  332. package/lib/opLifecycle/opCompressor.js +10 -5
  333. package/lib/opLifecycle/opCompressor.js.map +1 -1
  334. package/lib/opLifecycle/opDecompressor.d.ts +2 -2
  335. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  336. package/lib/opLifecycle/opDecompressor.js +15 -12
  337. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  338. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  339. package/lib/opLifecycle/opGroupingManager.js +17 -7
  340. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  341. package/lib/opLifecycle/opSplitter.d.ts +2 -2
  342. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  343. package/lib/opLifecycle/opSplitter.js +13 -10
  344. package/lib/opLifecycle/opSplitter.js.map +1 -1
  345. package/lib/opLifecycle/outbox.d.ts +7 -5
  346. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  347. package/lib/opLifecycle/outbox.js +13 -22
  348. package/lib/opLifecycle/outbox.js.map +1 -1
  349. package/lib/opLifecycle/remoteMessageProcessor.d.ts +6 -1
  350. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  351. package/lib/opLifecycle/remoteMessageProcessor.js +20 -8
  352. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  353. package/lib/opProperties.js +1 -2
  354. package/lib/opProperties.js.map +1 -1
  355. package/lib/packageVersion.d.ts +1 -1
  356. package/lib/packageVersion.js +1 -1
  357. package/lib/packageVersion.js.map +1 -1
  358. package/lib/pendingStateManager.d.ts +18 -8
  359. package/lib/pendingStateManager.d.ts.map +1 -1
  360. package/lib/pendingStateManager.js +62 -40
  361. package/lib/pendingStateManager.js.map +1 -1
  362. package/lib/scheduleManager.d.ts.map +1 -1
  363. package/lib/scheduleManager.js +18 -14
  364. package/lib/scheduleManager.js.map +1 -1
  365. package/lib/summary/index.d.ts +3 -3
  366. package/lib/summary/index.d.ts.map +1 -1
  367. package/lib/summary/index.js +1 -1
  368. package/lib/summary/index.js.map +1 -1
  369. package/lib/summary/orderedClientElection.d.ts +3 -3
  370. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  371. package/lib/summary/orderedClientElection.js +21 -22
  372. package/lib/summary/orderedClientElection.js.map +1 -1
  373. package/lib/summary/runWhileConnectedCoordinator.js +1 -1
  374. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  375. package/lib/summary/runningSummarizer.d.ts +31 -10
  376. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  377. package/lib/summary/runningSummarizer.js +265 -133
  378. package/lib/summary/runningSummarizer.js.map +1 -1
  379. package/lib/summary/summarizer.d.ts +8 -7
  380. package/lib/summary/summarizer.d.ts.map +1 -1
  381. package/lib/summary/summarizer.js +75 -74
  382. package/lib/summary/summarizer.js.map +1 -1
  383. package/lib/summary/summarizerClientElection.d.ts +2 -2
  384. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  385. package/lib/summary/summarizerClientElection.js +6 -10
  386. package/lib/summary/summarizerClientElection.js.map +1 -1
  387. package/lib/summary/summarizerHeuristics.js +9 -13
  388. package/lib/summary/summarizerHeuristics.js.map +1 -1
  389. package/lib/summary/summarizerNode/index.d.ts +1 -1
  390. package/lib/summary/summarizerNode/index.d.ts.map +1 -1
  391. package/lib/summary/summarizerNode/index.js.map +1 -1
  392. package/lib/summary/summarizerNode/summarizerNode.d.ts +10 -19
  393. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  394. package/lib/summary/summarizerNode/summarizerNode.js +42 -115
  395. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  396. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  397. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  398. package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  399. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  400. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -14
  401. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  402. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +14 -100
  403. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  404. package/lib/summary/summarizerTypes.d.ts +38 -25
  405. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  406. package/lib/summary/summarizerTypes.js.map +1 -1
  407. package/lib/summary/summaryCollection.d.ts +2 -3
  408. package/lib/summary/summaryCollection.d.ts.map +1 -1
  409. package/lib/summary/summaryCollection.js +5 -6
  410. package/lib/summary/summaryCollection.js.map +1 -1
  411. package/lib/summary/summaryFormat.d.ts +3 -0
  412. package/lib/summary/summaryFormat.d.ts.map +1 -1
  413. package/lib/summary/summaryFormat.js +5 -3
  414. package/lib/summary/summaryFormat.js.map +1 -1
  415. package/lib/summary/summaryGenerator.d.ts +10 -4
  416. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  417. package/lib/summary/summaryGenerator.js +100 -51
  418. package/lib/summary/summaryGenerator.js.map +1 -1
  419. package/lib/summary/summaryManager.d.ts +8 -8
  420. package/lib/summary/summaryManager.d.ts.map +1 -1
  421. package/lib/summary/summaryManager.js +35 -25
  422. package/lib/summary/summaryManager.js.map +1 -1
  423. package/package.json +28 -31
  424. package/src/batchTracker.ts +7 -5
  425. package/src/blobManager.ts +188 -166
  426. package/src/connectionTelemetry.ts +9 -4
  427. package/src/containerRuntime.ts +806 -441
  428. package/src/dataStore.ts +12 -4
  429. package/src/dataStoreContext.ts +39 -43
  430. package/src/dataStoreContexts.ts +4 -6
  431. package/src/dataStoreRegistry.ts +1 -1
  432. package/src/dataStores.ts +114 -80
  433. package/src/deltaManagerProxyBase.ts +111 -0
  434. package/src/deltaManagerSummarizerProxy.ts +4 -1
  435. package/src/deltaScheduler.ts +7 -11
  436. package/src/error.ts +18 -0
  437. package/src/gc/garbageCollection.md +53 -5
  438. package/src/gc/garbageCollection.ts +58 -52
  439. package/src/gc/gcConfigs.ts +4 -2
  440. package/src/gc/gcDefinitions.ts +17 -20
  441. package/src/gc/gcEarlyAdoption.md +145 -0
  442. package/src/gc/gcHelpers.ts +1 -12
  443. package/src/gc/gcSummaryStateTracker.ts +19 -65
  444. package/src/gc/gcTelemetry.ts +14 -12
  445. package/src/gc/gcUnreferencedStateTracker.ts +1 -1
  446. package/src/gc/index.ts +2 -4
  447. package/src/id-compressor/appendOnlySortedMap.ts +26 -87
  448. package/src/id-compressor/finalSpace.ts +67 -0
  449. package/src/id-compressor/idCompressor.ts +458 -1682
  450. package/src/id-compressor/identifiers.ts +42 -0
  451. package/src/id-compressor/index.ts +11 -20
  452. package/src/id-compressor/persistanceUtilities.ts +58 -0
  453. package/src/id-compressor/sessionSpaceNormalizer.ts +83 -0
  454. package/src/id-compressor/sessions.ts +405 -0
  455. package/src/id-compressor/utilities.ts +187 -0
  456. package/src/index.ts +7 -2
  457. package/src/opLifecycle/opCompressor.ts +6 -5
  458. package/src/opLifecycle/opDecompressor.ts +6 -4
  459. package/src/opLifecycle/opGroupingManager.ts +9 -6
  460. package/src/opLifecycle/opSplitter.ts +7 -6
  461. package/src/opLifecycle/outbox.ts +23 -32
  462. package/src/opLifecycle/remoteMessageProcessor.ts +27 -8
  463. package/src/packageVersion.ts +1 -1
  464. package/src/pendingStateManager.ts +72 -42
  465. package/src/scheduleManager.ts +7 -5
  466. package/src/summary/index.ts +4 -3
  467. package/src/summary/orderedClientElection.ts +10 -6
  468. package/src/summary/runWhileConnectedCoordinator.ts +1 -1
  469. package/src/summary/runningSummarizer.ts +291 -163
  470. package/src/summary/summarizer.ts +27 -16
  471. package/src/summary/summarizerClientElection.ts +2 -2
  472. package/src/summary/summarizerHeuristics.ts +1 -1
  473. package/src/summary/summarizerNode/index.ts +1 -2
  474. package/src/summary/summarizerNode/summarizerNode.ts +36 -160
  475. package/src/summary/summarizerNode/summarizerNodeUtils.ts +7 -38
  476. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +11 -130
  477. package/src/summary/summarizerTypes.ts +40 -25
  478. package/src/summary/summaryCollection.ts +3 -3
  479. package/src/summary/summaryFormat.ts +4 -1
  480. package/src/summary/summaryGenerator.ts +52 -52
  481. package/src/summary/summaryManager.ts +44 -17
  482. package/dist/id-compressor/idRange.d.ts +0 -11
  483. package/dist/id-compressor/idRange.d.ts.map +0 -1
  484. package/dist/id-compressor/idRange.js +0 -29
  485. package/dist/id-compressor/idRange.js.map +0 -1
  486. package/dist/id-compressor/numericUuid.d.ts +0 -59
  487. package/dist/id-compressor/numericUuid.d.ts.map +0 -1
  488. package/dist/id-compressor/numericUuid.js +0 -325
  489. package/dist/id-compressor/numericUuid.js.map +0 -1
  490. package/dist/id-compressor/sessionIdNormalizer.d.ts +0 -138
  491. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  492. package/dist/id-compressor/sessionIdNormalizer.js +0 -488
  493. package/dist/id-compressor/sessionIdNormalizer.js.map +0 -1
  494. package/dist/id-compressor/utils.d.ts +0 -57
  495. package/dist/id-compressor/utils.d.ts.map +0 -1
  496. package/dist/id-compressor/utils.js +0 -90
  497. package/dist/id-compressor/utils.js.map +0 -1
  498. package/dist/id-compressor/uuidUtilities.d.ts +0 -28
  499. package/dist/id-compressor/uuidUtilities.d.ts.map +0 -1
  500. package/dist/id-compressor/uuidUtilities.js +0 -104
  501. package/dist/id-compressor/uuidUtilities.js.map +0 -1
  502. package/lib/id-compressor/idRange.d.ts +0 -11
  503. package/lib/id-compressor/idRange.d.ts.map +0 -1
  504. package/lib/id-compressor/idRange.js +0 -25
  505. package/lib/id-compressor/idRange.js.map +0 -1
  506. package/lib/id-compressor/numericUuid.d.ts +0 -59
  507. package/lib/id-compressor/numericUuid.d.ts.map +0 -1
  508. package/lib/id-compressor/numericUuid.js +0 -315
  509. package/lib/id-compressor/numericUuid.js.map +0 -1
  510. package/lib/id-compressor/sessionIdNormalizer.d.ts +0 -138
  511. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  512. package/lib/id-compressor/sessionIdNormalizer.js +0 -484
  513. package/lib/id-compressor/sessionIdNormalizer.js.map +0 -1
  514. package/lib/id-compressor/utils.d.ts +0 -57
  515. package/lib/id-compressor/utils.d.ts.map +0 -1
  516. package/lib/id-compressor/utils.js +0 -79
  517. package/lib/id-compressor/utils.js.map +0 -1
  518. package/lib/id-compressor/uuidUtilities.d.ts +0 -28
  519. package/lib/id-compressor/uuidUtilities.d.ts.map +0 -1
  520. package/lib/id-compressor/uuidUtilities.js +0 -96
  521. package/lib/id-compressor/uuidUtilities.js.map +0 -1
  522. package/src/id-compressor/idRange.ts +0 -35
  523. package/src/id-compressor/numericUuid.ts +0 -383
  524. package/src/id-compressor/sessionIdNormalizer.ts +0 -609
  525. package/src/id-compressor/utils.ts +0 -114
  526. package/src/id-compressor/uuidUtilities.ts +0 -120
@@ -18,26 +18,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
18
18
  __setModuleDefault(result, mod);
19
19
  return result;
20
20
  };
21
- var __rest = (this && this.__rest) || function (s, e) {
22
- var t = {};
23
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
24
- t[p] = s[p];
25
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
26
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
27
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
28
- t[p[i]] = s[p[i]];
29
- }
30
- return t;
31
- };
32
21
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.TombstoneResponseHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
22
+ exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
34
23
  const container_definitions_1 = require("@fluidframework/container-definitions");
35
- const common_utils_1 = require("@fluidframework/common-utils");
36
24
  const core_utils_1 = require("@fluidframework/core-utils");
25
+ const client_utils_1 = require("@fluid-internal/client-utils");
37
26
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
38
27
  const driver_definitions_1 = require("@fluidframework/driver-definitions");
39
28
  const driver_utils_1 = require("@fluidframework/driver-utils");
40
- const container_utils_1 = require("@fluidframework/container-utils");
41
29
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
42
30
  const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
43
31
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
@@ -78,6 +66,18 @@ var ContainerMessageType;
78
66
  */
79
67
  ContainerMessageType["IdAllocation"] = "idAllocation";
80
68
  })(ContainerMessageType = exports.ContainerMessageType || (exports.ContainerMessageType = {}));
69
+ /**
70
+ * Utility to implement compat behaviors given an unknown message type
71
+ * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
72
+ *
73
+ * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
74
+ * handled before calling this function (e.g. in a switch statement).
75
+ * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
76
+ */
77
+ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, compatBehavior) {
78
+ // undefined defaults to same behavior as "FailToProcess"
79
+ return compatBehavior === "Ignore";
80
+ }
81
81
  exports.DefaultSummaryConfiguration = {
82
82
  state: "enabled",
83
83
  minIdleTime: 0,
@@ -104,8 +104,12 @@ var RuntimeHeaders;
104
104
  })(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
105
105
  /** True if a tombstoned object should be returned without erroring */
106
106
  exports.AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
107
+ /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
108
+ exports.AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
107
109
  /** Tombstone error responses will have this header set to true */
108
110
  exports.TombstoneResponseHeaderKey = "isTombstoned";
111
+ /** Inactive error responses will have this header set to true */
112
+ exports.InactiveResponseHeaderKey = "isInactive";
109
113
  /** Default values for Runtime Headers */
110
114
  exports.defaultRuntimeHeaderData = {
111
115
  wait: true,
@@ -132,12 +136,16 @@ const defaultCompressionConfig = {
132
136
  compressionAlgorithm: CompressionAlgorithms.lz4,
133
137
  };
134
138
  const defaultChunkSizeInBytes = 204800;
139
+ /** The default time to wait for pending ops to be processed during summarization */
140
+ exports.defaultPendingOpsWaitTimeoutMs = 1000;
141
+ /** The default time to delay a summarization retry attempt when there are pending ops */
142
+ exports.defaultPendingOpsRetryDelayMs = 1000;
135
143
  /**
136
144
  * Instead of refreshing from latest because we do not have 100% confidence in the state
137
145
  * of the current system, we should close the summarizer and let it recover.
138
146
  * This delay's goal is to prevent tight restart loops
139
147
  */
140
- const defaultCloseSummarizerDelayMs = 10000; // 10 seconds
148
+ const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
141
149
  /**
142
150
  * @deprecated - use ContainerRuntimeMessage instead
143
151
  */
@@ -174,23 +182,40 @@ function getDeviceSpec() {
174
182
  };
175
183
  }
176
184
  }
177
- catch (_a) { }
185
+ catch { }
178
186
  return {};
179
187
  }
180
188
  exports.getDeviceSpec = getDeviceSpec;
189
+ /**
190
+ * Older loader doesn't have a submitBatchFn member, this is the older way of submitting a batch.
191
+ * Rather than exposing the submitFn (now deprecated) and IDeltaManager (dangerous to hand out) to the Outbox,
192
+ * we can provide a partially-applied function to keep those items private to the ContainerRuntime.
193
+ */
194
+ const makeLegacySendBatchFn = (submitFn, deltaManager) => (batch) => {
195
+ for (const message of batch.content) {
196
+ submitFn(protocol_definitions_1.MessageType.Operation,
197
+ // For back-compat (submitFn only works on deserialized content)
198
+ message.contents === undefined ? undefined : JSON.parse(message.contents), true, // batch
199
+ message.metadata);
200
+ }
201
+ deltaManager.flush();
202
+ };
203
+ exports.makeLegacySendBatchFn = makeLegacySendBatchFn;
181
204
  /**
182
205
  * Represents the runtime of the container. Contains helper functions/state of the container.
183
206
  * It will define the store level mappings.
184
207
  */
185
- class ContainerRuntime extends common_utils_1.TypedEventEmitter {
208
+ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
186
209
  /**
187
210
  * @internal
188
211
  */
189
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration, initializeEntryPoint) {
190
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
191
- if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, exports.DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
212
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration = {
213
+ // the defaults
214
+ ...exports.DefaultSummaryConfiguration,
215
+ // the runtime configuration overrides
216
+ ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
217
+ }, initializeEntryPoint) {
192
218
  super();
193
- this.context = context;
194
219
  this.registry = registry;
195
220
  this.runtimeOptions = runtimeOptions;
196
221
  this.containerScope = containerScope;
@@ -219,51 +244,56 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
219
244
  signalTimestamp: 0,
220
245
  trackingSignalSequenceNumber: undefined,
221
246
  };
222
- this.summarizeOnDemand = (...args) => {
223
- if (this.clientDetails.type === summary_1.summarizerClientType) {
224
- return this.summarizer.summarizeOnDemand(...args);
225
- }
226
- else if (this.summaryManager !== undefined) {
227
- return this.summaryManager.summarizeOnDemand(...args);
228
- }
229
- else {
230
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
231
- // disableSummaries is turned on. We are throwing instead of returning a failure here,
232
- // because it is a misuse of the API rather than an expected failure.
233
- throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
234
- }
235
- };
236
- this.enqueueSummarize = (...args) => {
237
- if (this.clientDetails.type === summary_1.summarizerClientType) {
238
- return this.summarizer.enqueueSummarize(...args);
239
- }
240
- else if (this.summaryManager !== undefined) {
241
- return this.summaryManager.enqueueSummarize(...args);
242
- }
243
- else {
244
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
245
- // generateSummaries is turned off. We are throwing instead of returning a failure here,
246
- // because it is a misuse of the API rather than an expected failure.
247
- throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
248
- }
247
+ const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
248
+ this.innerDeltaManager = deltaManager;
249
+ this.deltaManager = new deltaManagerSummarizerProxy_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
250
+ // Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
251
+ // This makes ContainerRuntime the final gatekeeper for outgoing messages.
252
+ this.submitFn = submitFn;
253
+ this.submitBatchFn = submitBatchFn;
254
+ this.submitSummaryFn = submitSummaryFn;
255
+ this.submitSignalFn = submitSignalFn;
256
+ this.options = options;
257
+ this.clientDetails = clientDetails;
258
+ this.isSummarizerClient = this.clientDetails.type === summary_1.summarizerClientType;
259
+ this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
260
+ this._getClientId = () => context.clientId;
261
+ this._getAttachState = () => context.attachState;
262
+ this.getAbsoluteUrl = async (relativeUrl) => {
263
+ if (context.getAbsoluteUrl === undefined) {
264
+ throw new Error("Driver does not implement getAbsoluteUrl");
265
+ }
266
+ if (this.attachState !== container_definitions_1.AttachState.Attached) {
267
+ return undefined;
268
+ }
269
+ return context.getAbsoluteUrl(relativeUrl);
249
270
  };
250
- this.innerDeltaManager = context.deltaManager;
251
- this.deltaManager = new deltaManagerSummarizerProxy_1.DeltaManagerSummarizerProxy(context.deltaManager);
252
- this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(this.logger, "ContainerRuntime"));
271
+ // TODO: Consider that the Container could just listen to these events itself, or even more appropriately maybe the
272
+ // customer should observe dirty state on the runtime (the owner of dirty state) directly, rather than on the IContainer.
273
+ this.on("dirty", () => context.updateDirtyContainerState(true));
274
+ this.on("saved", () => context.updateDirtyContainerState(false));
275
+ // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
276
+ this.disposeFn = disposeFn ?? closeFn;
277
+ // In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
278
+ this.closeFn = this.isSummarizerClient ? this.disposeFn : closeFn;
279
+ this.mc = (0, telemetry_utils_1.createChildMonitoringContext)({
280
+ logger: this.logger,
281
+ namespace: "ContainerRuntime",
282
+ });
253
283
  let loadSummaryNumber;
254
284
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
255
285
  // get the values from the metadata blob.
256
286
  if (existing) {
257
287
  this.createContainerMetadata = {
258
- createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
259
- createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
288
+ createContainerRuntimeVersion: metadata?.createContainerRuntimeVersion,
289
+ createContainerTimestamp: metadata?.createContainerTimestamp,
260
290
  };
261
291
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
262
292
  // the count is reset to 0.
263
- loadSummaryNumber = (_b = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _b !== void 0 ? _b : 0;
293
+ loadSummaryNumber = metadata?.summaryNumber ?? 0;
264
294
  // Enabling the IdCompressor is a one-way operation and we only want to
265
295
  // allow new containers to turn it on
266
- this.idCompressorEnabled = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.idCompressorEnabled) !== null && _c !== void 0 ? _c : false;
296
+ this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
267
297
  }
268
298
  else {
269
299
  this.createContainerMetadata = {
@@ -272,24 +302,27 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
272
302
  };
273
303
  loadSummaryNumber = 0;
274
304
  this.idCompressorEnabled =
275
- (_d = this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) !== null && _d !== void 0 ? _d : idCompressor !== undefined;
305
+ this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
306
+ idCompressor !== undefined;
276
307
  }
277
308
  this.nextSummaryNumber = loadSummaryNumber + 1;
278
- this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
279
- this._connected = this.context.connected;
280
- this.gcTombstoneEnforcementAllowed = (0, gc_1.shouldAllowGcTombstoneEnforcement)((_e = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _e === void 0 ? void 0 : _e.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gc_1.gcTombstoneGenerationOptionName] /* current */);
309
+ this.messageAtLastSummary = metadata?.message;
310
+ // Note that we only need to pull the *initial* connected state from the context.
311
+ // Later updates come through calls to setConnectionState.
312
+ this._connected = connected;
313
+ this.gcTombstoneEnforcementAllowed = (0, gc_1.shouldAllowGcTombstoneEnforcement)(metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gc_1.gcTombstoneGenerationOptionName] /* current */);
281
314
  this.mc.logger.sendTelemetryEvent({
282
315
  eventName: "GCFeatureMatrix",
283
- metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
316
+ metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
284
317
  inputs: JSON.stringify({
285
318
  gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gc_1.gcTombstoneGenerationOptionName],
286
319
  }),
287
320
  });
288
- this.telemetryDocumentId = (_f = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _f !== void 0 ? _f : (0, uuid_1.v4)();
321
+ this.telemetryDocumentId = metadata?.telemetryDocumentId ?? (0, uuid_1.v4)();
289
322
  this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
290
323
  const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
291
324
  const opGroupingManager = new opLifecycle_1.OpGroupingManager(this.groupedBatchingEnabled);
292
- const opSplitter = new opLifecycle_1.OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
325
+ const opSplitter = new opLifecycle_1.OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
293
326
  this.remoteMessageProcessor = new opLifecycle_1.RemoteMessageProcessor(opSplitter, new opLifecycle_1.OpDecompressor(this.mc.logger), opGroupingManager);
294
327
  this.handleContext = new containerHandleContext_1.ContainerFluidHandleContext("", this);
295
328
  if (this.summaryConfiguration.state === "enabled") {
@@ -308,9 +341,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
308
341
  this.idCompressor = idCompressor;
309
342
  }
310
343
  this.maxConsecutiveReconnects =
311
- (_g = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _g !== void 0 ? _g : this.defaultMaxConsecutiveReconnects;
344
+ this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
345
+ this.defaultMaxConsecutiveReconnects;
312
346
  if (runtimeOptions.flushMode === runtime_definitions_1.FlushModeExperimental.Async &&
313
- ((_h = context.supportedFeatures) === null || _h === void 0 ? void 0 : _h.get("referenceSequenceNumbers")) !== true) {
347
+ supportedFeatures?.get("referenceSequenceNumbers") !== true) {
314
348
  // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
315
349
  this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
316
350
  this._flushMode = runtime_definitions_1.FlushMode.TurnBased;
@@ -318,39 +352,39 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
318
352
  else {
319
353
  this._flushMode = runtimeOptions.flushMode;
320
354
  }
321
- const pendingRuntimeState = context.pendingLocalState;
322
- const maxSnapshotCacheDurationMs = (_k = (_j = this._storage) === null || _j === void 0 ? void 0 : _j.policies) === null || _k === void 0 ? void 0 : _k.maximumCacheDurationMs;
355
+ const pendingRuntimeState = pendingLocalState;
356
+ const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
323
357
  if (maxSnapshotCacheDurationMs !== undefined &&
324
358
  maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
325
359
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
326
360
  // which dictates the value is either undefined or exactly 5 days in ms.
327
361
  // As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
328
- throw new container_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
362
+ throw new telemetry_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
329
363
  }
330
364
  this.garbageCollector = gc_1.GarbageCollector.create({
331
365
  runtime: this,
332
366
  gcOptions: this.runtimeOptions.gcOptions,
333
- baseSnapshot: context.baseSnapshot,
367
+ baseSnapshot,
334
368
  baseLogger: this.mc.logger,
335
369
  existing,
336
370
  metadata,
337
371
  createContainerMetadata: this.createContainerMetadata,
338
- isSummarizerClient: this.context.clientDetails.type === summary_1.summarizerClientType,
372
+ isSummarizerClient: this.isSummarizerClient,
339
373
  getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
340
- getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
374
+ getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
341
375
  readAndParseBlob: async (id) => (0, driver_utils_1.readAndParse)(this.storage, id),
342
376
  // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
343
377
  // delta manager would always return false for summarizer client.
344
378
  activeConnection: () => this.innerDeltaManager.active,
345
379
  });
346
380
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
347
- this.summarizerNode = (0, summary_1.createRootSummarizerNodeWithGC)(telemetry_utils_1.ChildLogger.create(this.logger, "SummarizerNode"),
381
+ this.summarizerNode = (0, summary_1.createRootSummarizerNodeWithGC)((0, telemetry_utils_1.createChildLogger)({ logger: this.logger, namespace: "SummarizerNode" }),
348
382
  // Summarize function to call when summarize is called. Summarizer node always tracks summary state.
349
383
  async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
350
384
  // Latest change sequence number, no changes since summary applied yet
351
385
  loadedFromSequenceNumber,
352
386
  // Summary reference sequence number, undefined if no summary yet
353
- context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
387
+ baseSnapshot !== undefined ? loadedFromSequenceNumber : undefined, {
354
388
  // Must set to false to prevent sending summary handle which would be pointing to
355
389
  // a summary with an older protocol state.
356
390
  canReuseHandle: false,
@@ -364,19 +398,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
364
398
  async (fullGC) => this.getGCDataInternal(fullGC),
365
399
  // Function to get the GC details from the base snapshot we loaded from.
366
400
  async () => this.garbageCollector.getBaseGCDetails());
367
- if (context.baseSnapshot) {
368
- this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
401
+ if (baseSnapshot) {
402
+ this.summarizerNode.updateBaseSummaryState(baseSnapshot);
369
403
  }
370
- this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
404
+ this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata), this, (attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
371
405
  this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
372
406
  if (!this.disposed) {
373
- this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
407
+ this.submit({ type: ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
374
408
  localId,
375
409
  blobId,
376
410
  });
377
411
  }
378
- }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, (error) => this.closeFn(error));
379
- this.scheduleManager = new scheduleManager_1.ScheduleManager(context.deltaManager, this, () => this.clientId, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
412
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState?.pendingAttachmentBlobs, (error) => this.closeFn(error));
413
+ this.scheduleManager = new scheduleManager_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, telemetry_utils_1.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
380
414
  this.pendingStateManager = new pendingStateManager_1.PendingStateManager({
381
415
  applyStashedOp: this.applyStashedOp.bind(this),
382
416
  clientId: () => this.clientId,
@@ -384,7 +418,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
384
418
  connected: () => this.connected,
385
419
  reSubmit: this.reSubmit.bind(this),
386
420
  reSubmitBatch: this.reSubmitBatch.bind(this),
387
- }, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
421
+ isActiveConnection: () => this.innerDeltaManager.active,
422
+ }, pendingRuntimeState?.pending, this.logger);
388
423
  const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
389
424
  const compressionOptions = disableCompression === true
390
425
  ? {
@@ -393,10 +428,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
393
428
  }
394
429
  : runtimeOptions.compressionOptions;
395
430
  const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
431
+ const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
396
432
  this.outbox = new opLifecycle_1.Outbox({
397
433
  shouldSend: () => this.canSendOps(),
398
434
  pendingStateManager: this.pendingStateManager,
399
- containerContext: this.context,
435
+ submitBatchFn: this.submitBatchFn,
436
+ legacySendBatchFn,
400
437
  compressor: new opLifecycle_1.OpCompressor(this.mc.logger),
401
438
  splitter: opSplitter,
402
439
  config: {
@@ -415,44 +452,50 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
415
452
  opReentrancy: () => this.ensureNoDataModelChangesCalls > 0,
416
453
  closeContainer: this.closeFn,
417
454
  });
418
- this.context.quorum.on("removeMember", (clientId) => {
455
+ this._quorum = quorum;
456
+ this._quorum.on("removeMember", (clientId) => {
419
457
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
420
458
  });
421
- this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
459
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
460
+ this._audience = audience;
422
461
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
423
- this.closeSummarizerDelayMs = closeSummarizerDelayOverride !== null && closeSummarizerDelayOverride !== void 0 ? closeSummarizerDelayOverride : defaultCloseSummarizerDelayMs;
462
+ this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
424
463
  this.validateSummaryBeforeUpload =
425
- (_l = this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload")) !== null && _l !== void 0 ? _l : false;
464
+ this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
426
465
  this.summaryCollection = new summary_1.SummaryCollection(this.deltaManager, this.logger);
427
466
  this.dirtyContainer =
428
- this.context.attachState !== container_definitions_1.AttachState.Attached ||
429
- this.pendingStateManager.hasPendingMessages();
430
- this.context.updateDirtyContainerState(this.dirtyContainer);
467
+ this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
468
+ context.updateDirtyContainerState(this.dirtyContainer);
431
469
  if (this.summariesDisabled) {
432
470
  this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
433
471
  }
434
472
  else {
435
- const orderedClientLogger = telemetry_utils_1.ChildLogger.create(this.logger, "OrderedClientElection");
436
- const orderedClientCollection = new summary_1.OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
437
- const orderedClientElectionForSummarizer = new summary_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, summary_1.SummarizerClientElection.isClientEligible);
473
+ const orderedClientLogger = (0, telemetry_utils_1.createChildLogger)({
474
+ logger: this.logger,
475
+ namespace: "OrderedClientElection",
476
+ });
477
+ const orderedClientCollection = new summary_1.OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
478
+ const orderedClientElectionForSummarizer = new summary_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, summary_1.SummarizerClientElection.isClientEligible);
438
479
  this.summarizerClientElection = new summary_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
439
- if (this.context.clientDetails.type === summary_1.summarizerClientType) {
480
+ if (this.isSummarizerClient) {
440
481
  this._summarizer = new summary_1.Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => summary_1.RunWhileConnectedCoordinator.create(runtime,
441
482
  // Summarization runs in summarizer client and needs access to the real (non-proxy) active
442
483
  // information. The proxy delta manager would always return false for summarizer client.
443
484
  () => this.innerDeltaManager.active));
444
485
  }
445
- else if (summary_1.SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
486
+ else if (summary_1.SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
446
487
  // Only create a SummaryManager and SummarizerClientElection
447
488
  // if summaries are enabled and we are not the summarizer client.
448
489
  const defaultAction = () => {
449
490
  if (this.summaryCollection.opsSinceLastAck > this.maxOpsSinceLastSummary) {
450
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
491
+ this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
451
492
  // unregister default to no log on every op after falling behind
452
493
  // and register summary ack handler to re-register this handler
453
494
  // after successful summary
454
495
  this.summaryCollection.once(protocol_definitions_1.MessageType.SummaryAck, () => {
455
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
496
+ this.mc.logger.sendTelemetryEvent({
497
+ eventName: "SummaryStatus:CaughtUp",
498
+ });
456
499
  // we've caught up, so re-register the default action to monitor for
457
500
  // falling behind, and unregister ourself
458
501
  this.summaryCollection.on("default", defaultAction);
@@ -463,12 +506,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
463
506
  this.summaryCollection.on("default", defaultAction);
464
507
  // Create the SummaryManager and mark the initial state
465
508
  this.summaryManager = new summary_1.SummaryManager(this.summarizerClientElection, this, // IConnectedState
466
- this.summaryCollection, this.logger, this.formRequestSummarizerFn(this.context.loader), new throttler_1.Throttler(60 * 1000, // 60 sec delay window
509
+ this.summaryCollection, this.logger, this.formRequestSummarizerFn(loader), new throttler_1.Throttler(60 * 1000, // 60 sec delay window
467
510
  30 * 1000, // 30 sec max delay
468
511
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
469
512
  (0, throttler_1.formExponentialFn)({ coefficient: 20, initialDelay: 0 })), {
470
513
  initialDelayMs: this.initialSummarizerDelayMs,
471
514
  }, this.heuristicsDisabled);
515
+ this.summaryManager.on("summarize", (eventProps) => {
516
+ this.emit("summarize", eventProps);
517
+ });
472
518
  this.summaryManager.start();
473
519
  }
474
520
  }
@@ -476,7 +522,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
476
522
  // we accumulate ops while being in read-only state.
477
523
  // once user gets write permissions and we have active connection, flush all pending ops.
478
524
  // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
479
- (0, common_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
525
+ (0, core_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
480
526
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
481
527
  // when we either never send an op, or attempted to send it but we know for sure it was not
482
528
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -489,31 +535,48 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
489
535
  // can rely on same safety mechanism and resend ops only when we establish new connection.
490
536
  // This is applicable for read-only permissions (event is raised before connection is properly registered),
491
537
  // but it's an extra requirement for Container.forceReadonly() API
492
- (0, common_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
538
+ (0, core_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
493
539
  this.replayPendingStates();
494
540
  });
495
541
  // logging hardware telemetry
496
- logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
497
- this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature, options: JSON.stringify(runtimeOptions), featureGates: JSON.stringify({
542
+ logger.sendTelemetryEvent({
543
+ eventName: "DeviceSpec",
544
+ ...getDeviceSpec(),
545
+ });
546
+ this.mc.logger.sendTelemetryEvent({
547
+ eventName: "ContainerLoadStats",
548
+ ...this.createContainerMetadata,
549
+ ...this.dataStores.containerLoadStats,
550
+ summaryNumber: loadSummaryNumber,
551
+ summaryFormatVersion: metadata?.summaryFormatVersion,
552
+ disableIsolatedChannels: metadata?.disableIsolatedChannels,
553
+ gcVersion: metadata?.gcFeature,
554
+ options: JSON.stringify(runtimeOptions),
555
+ featureGates: JSON.stringify({
498
556
  disableCompression,
499
557
  disableOpReentryCheck,
500
558
  disableChunking,
501
559
  disableAttachReorder: this.disableAttachReorder,
502
560
  disablePartialFlush,
503
561
  idCompressorEnabled: this.idCompressorEnabled,
504
- summaryStateUpdateMethod: this.summaryStateUpdateMethod,
505
562
  closeSummarizerDelayOverride,
506
- }), telemetryDocumentId: this.telemetryDocumentId, groupedBatchingEnabled: this.groupedBatchingEnabled }));
507
- (0, connectionTelemetry_1.ReportOpPerfTelemetry)(this.context.clientId, this.deltaManager, this.logger);
563
+ }),
564
+ telemetryDocumentId: this.telemetryDocumentId,
565
+ groupedBatchingEnabled: this.groupedBatchingEnabled,
566
+ });
567
+ (0, connectionTelemetry_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this.logger);
508
568
  (0, batchTracker_1.BindBatchTracker)(this, this.logger);
509
569
  this.entryPoint = new core_utils_1.LazyPromise(async () => {
510
- if (this.context.clientDetails.type === summary_1.summarizerClientType) {
511
- (0, common_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
570
+ if (this.isSummarizerClient) {
571
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
512
572
  return this._summarizer;
513
573
  }
514
- return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
574
+ return initializeEntryPoint?.(this);
515
575
  });
516
576
  }
577
+ /**
578
+ * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
579
+ */
517
580
  get IFluidRouter() {
518
581
  return this;
519
582
  }
@@ -559,26 +622,38 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
559
622
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
560
623
  */
561
624
  static async loadRuntime(params) {
562
- var _a, _b, _c, _d, _e, _f;
563
- const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
625
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
626
+ const initializeEntryPoint = params.initializeEntryPoint ??
627
+ (async (containerRuntime) => ({
628
+ get IFluidRouter() {
629
+ return this;
630
+ },
631
+ async request(req) {
632
+ return containerRuntime.request(req);
633
+ },
634
+ }));
564
635
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
565
636
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
566
637
  const backCompatContext = context;
567
- const passLogger = (_a = backCompatContext.taggedLogger) !== null && _a !== void 0 ? _a : new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
568
- const logger = telemetry_utils_1.ChildLogger.create(passLogger, undefined, {
569
- all: {
570
- runtimeVersion: packageVersion_1.pkgVersion,
638
+ const passLogger = backCompatContext.taggedLogger ??
639
+ // eslint-disable-next-line import/no-deprecated
640
+ new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
641
+ const logger = (0, telemetry_utils_1.createChildLogger)({
642
+ logger: passLogger,
643
+ properties: {
644
+ all: {
645
+ runtimeVersion: packageVersion_1.pkgVersion,
646
+ },
571
647
  },
572
648
  });
573
649
  const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
574
650
  const registry = new dataStoreRegistry_1.FluidDataStoreRegistry(registryEntries);
575
651
  const tryFetchBlob = async (blobName) => {
576
- var _a;
577
- const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
652
+ const blobId = context.baseSnapshot?.blobs[blobName];
578
653
  if (context.baseSnapshot && blobId) {
579
654
  // IContainerContext storage api return type still has undefined in 0.39 package version.
580
655
  // So once we release 0.40 container-defn package we can remove this check.
581
- (0, common_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
656
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
582
657
  return (0, driver_utils_1.readAndParse)(context.storage, blobId);
583
658
  }
584
659
  };
@@ -589,16 +664,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
589
664
  tryFetchBlob(summary_1.aliasBlobName),
590
665
  tryFetchBlob(summary_1.idCompressorBlobName),
591
666
  ]);
592
- const loadExisting = existing === true || context.existing === true;
593
667
  // read snapshot blobs needed for BlobManager to load
594
- const blobManagerSnapshot = await blobManager_1.BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[summary_1.blobsTreeName], async (id) => {
668
+ const blobManagerSnapshot = await blobManager_1.BlobManager.load(context.baseSnapshot?.trees[summary_1.blobsTreeName], async (id) => {
595
669
  // IContainerContext storage api return type still has undefined in 0.39 package version.
596
670
  // So once we release 0.40 container-defn package we can remove this check.
597
- (0, common_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
671
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
598
672
  return (0, driver_utils_1.readAndParse)(context.storage, id);
599
673
  });
600
674
  // Verify summary runtime sequence number matches protocol sequence number.
601
- const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
675
+ const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
602
676
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
603
677
  if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
604
678
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
@@ -606,29 +680,27 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
606
680
  if (loadSequenceNumberVerification !== "bypass" &&
607
681
  runtimeSequenceNumber !== protocolSequenceNumber) {
608
682
  // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
609
- const error = new container_utils_1.DataCorruptionError(
683
+ const error = new telemetry_utils_1.DataCorruptionError(
610
684
  // pre-0.58 error message: SummaryMetadataMismatch
611
685
  "Summary metadata mismatch", { runtimeVersion: packageVersion_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
612
686
  if (loadSequenceNumberVerification === "log") {
613
687
  logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
614
688
  }
615
689
  else {
616
- // Call both close and dispose as closeFn implementation will no longer dispose runtime in future
617
690
  context.closeFn(error);
618
- (_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
619
691
  }
620
692
  }
621
693
  }
622
- const idCompressorEnabled = (_f = (_e = metadata === null || metadata === void 0 ? void 0 : metadata.idCompressorEnabled) !== null && _e !== void 0 ? _e : runtimeOptions.enableRuntimeIdCompressor) !== null && _f !== void 0 ? _f : false;
694
+ const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
623
695
  let idCompressor;
624
696
  if (idCompressorEnabled) {
625
697
  const { IdCompressor, createSessionId } = await Promise.resolve().then(() => __importStar(require("./id-compressor")));
626
698
  idCompressor =
627
699
  serializedIdCompressor !== undefined
628
700
  ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
629
- : new IdCompressor(createSessionId(), logger);
701
+ : IdCompressor.create(logger);
630
702
  }
631
- const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks !== null && chunks !== void 0 ? chunks : [], aliases !== null && aliases !== void 0 ? aliases : [], {
703
+ const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
632
704
  summaryOptions,
633
705
  gcOptions,
634
706
  loadSequenceNumberVerification,
@@ -639,8 +711,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
639
711
  enableRuntimeIdCompressor,
640
712
  enableOpReentryCheck,
641
713
  enableGroupedBatching,
642
- }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
714
+ }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
643
715
  initializeEntryPoint);
716
+ await runtime.blobManager.processStashedChanges();
644
717
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
645
718
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
646
719
  await runtime.pendingStateManager.applyStashedOpsAt(0);
@@ -648,38 +721,16 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
648
721
  await runtime.initializeBaseState();
649
722
  return runtime;
650
723
  }
651
- get options() {
652
- return this.context.options;
653
- }
654
724
  get clientId() {
655
- return this.context.clientId;
656
- }
657
- get clientDetails() {
658
- return this.context.clientDetails;
725
+ return this._getClientId();
659
726
  }
660
727
  get storage() {
661
728
  return this._storage;
662
729
  }
730
+ /** @deprecated - The functionality is no longer exposed publicly */
663
731
  get reSubmitFn() {
664
- // eslint-disable-next-line @typescript-eslint/unbound-method
665
- return this.reSubmitCore;
666
- }
667
- get disposeFn() {
668
- var _a;
669
- // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
670
- return (_a = this.context.disposeFn) !== null && _a !== void 0 ? _a : this.context.closeFn;
671
- }
672
- get closeFn() {
673
- if (this._summarizer !== undefined) {
674
- // In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
675
- return this.disposeFn;
676
- }
677
- // Also call disposeFn to retain functionality of runtime being disposed on close
678
- return (error) => {
679
- var _a, _b;
680
- this.context.closeFn(error);
681
- (_b = (_a = this.context).disposeFn) === null || _b === void 0 ? void 0 : _b.call(_a, error);
682
- };
732
+ return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
733
+ // Note: compatDetails is not included in this deprecated API
683
734
  }
684
735
  get flushMode() {
685
736
  return this._flushMode;
@@ -691,7 +742,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
691
742
  return this.registry;
692
743
  }
693
744
  get attachState() {
694
- return this.context.attachState;
745
+ return this._getAttachState();
695
746
  }
696
747
  get IFluidHandleContext() {
697
748
  return this.handleContext;
@@ -718,14 +769,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
718
769
  }
719
770
  /** clientId of parent (non-summarizing) container that owns summarizer container */
720
771
  get summarizerClientId() {
721
- var _a;
722
- return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
772
+ return this.summarizerClientElection?.electedClientId;
723
773
  }
724
774
  get disposed() {
725
775
  return this._disposed;
726
776
  }
727
777
  get summarizer() {
728
- (0, common_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
778
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
729
779
  return this._summarizer;
730
780
  }
731
781
  isSummariesDisabled() {
@@ -756,12 +806,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
756
806
  await this.garbageCollector.initializeBaseState();
757
807
  }
758
808
  dispose(error) {
759
- var _a;
760
809
  if (this._disposed) {
761
810
  return;
762
811
  }
763
812
  this._disposed = true;
764
- this.logger.sendTelemetryEvent({
813
+ this.mc.logger.sendTelemetryEvent({
765
814
  eventName: "ContainerRuntimeDisposed",
766
815
  isDirty: this.isDirty,
767
816
  lastSequenceNumber: this.deltaManager.lastSequenceNumber,
@@ -771,7 +820,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
771
820
  this.summaryManager.dispose();
772
821
  }
773
822
  this.garbageCollector.dispose();
774
- (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.dispose();
823
+ this._summarizer?.dispose();
775
824
  this.dataStores.dispose();
776
825
  this.pendingStateManager.dispose();
777
826
  this.emit("dispose");
@@ -780,6 +829,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
780
829
  /**
781
830
  * Notifies this object about the request made to the container.
782
831
  * @param request - Request made to the handler.
832
+ * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
783
833
  */
784
834
  async request(request) {
785
835
  try {
@@ -830,8 +880,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
830
880
  const subRequest = requestParser.createSubRequest(1);
831
881
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
832
882
  // unintentionally modifying the url if that changes.
833
- (0, common_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
834
- return dataStore.IFluidRouter.request(subRequest);
883
+ (0, core_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
884
+ return dataStore.request(subRequest);
835
885
  }
836
886
  return (0, runtime_utils_1.create404Response)(request);
837
887
  }
@@ -846,19 +896,17 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
846
896
  return this.entryPoint;
847
897
  }
848
898
  internalId(maybeAlias) {
849
- var _a;
850
- return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
899
+ return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
851
900
  }
852
901
  async getDataStoreFromRequest(id, request) {
853
- var _a, _b, _c;
854
902
  const headerData = {};
855
- if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
903
+ if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
856
904
  headerData.wait = request.headers[RuntimeHeaders.wait];
857
905
  }
858
- if (typeof ((_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.viaHandle]) === "boolean") {
906
+ if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
859
907
  headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
860
908
  }
861
- if (typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[exports.AllowTombstoneRequestHeaderKey]) === "boolean") {
909
+ if (typeof request.headers?.[exports.AllowTombstoneRequestHeaderKey] === "boolean") {
862
910
  headerData.allowTombstone = request.headers[exports.AllowTombstoneRequestHeaderKey];
863
911
  }
864
912
  await this.dataStores.waitIfPendingAlias(id);
@@ -868,25 +916,30 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
868
916
  // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
869
917
  // the same as GC nodes id.
870
918
  const urlWithoutQuery = (0, gc_1.trimLeadingAndTrailingSlashes)(request.url.split("?")[0]);
871
- this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request === null || request === void 0 ? void 0 : request.headers);
919
+ this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request?.headers);
872
920
  return dataStoreChannel;
873
921
  }
874
922
  /** Adds the container's metadata to the given summary tree. */
875
923
  addMetadataToSummary(summaryTree) {
876
- var _a;
877
- const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
924
+ const metadata = {
925
+ ...this.createContainerMetadata,
878
926
  // Increment the summary number for the next summary that will be generated.
879
- summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
927
+ summaryNumber: this.nextSummaryNumber++,
928
+ summaryFormatVersion: 1,
929
+ ...this.garbageCollector.getMetadata(),
880
930
  // The last message processed at the time of summary. If there are no new messages, use the message from the
881
931
  // last summary.
882
- message: (_a = (0, summary_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId, idCompressorEnabled: this.idCompressorEnabled ? true : undefined });
932
+ message: (0, summary_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage) ??
933
+ this.messageAtLastSummary,
934
+ telemetryDocumentId: this.telemetryDocumentId,
935
+ idCompressorEnabled: this.idCompressorEnabled ? true : undefined,
936
+ };
883
937
  (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.metadataBlobName, JSON.stringify(metadata));
884
938
  }
885
939
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
886
- var _a;
887
940
  this.addMetadataToSummary(summaryTree);
888
941
  if (this.idCompressorEnabled) {
889
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
942
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
890
943
  const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
891
944
  (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.idCompressorBlobName, idCompressorState);
892
945
  }
@@ -899,7 +952,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
899
952
  (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.aliasBlobName, JSON.stringify([...dataStoreAliases]));
900
953
  }
901
954
  if (this.summarizerClientElection) {
902
- const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
955
+ const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
903
956
  (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.electedSummarizerBlobName, electedSummarizerContent);
904
957
  }
905
958
  const blobManagerSummary = this.blobManager.summarize();
@@ -936,7 +989,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
936
989
  this.mc.logger.sendTelemetryEvent({
937
990
  eventName: "ReconnectsWithNoProgress",
938
991
  attempts: this.consecutiveReconnects,
939
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
992
+ pendingMessages: this.pendingMessagesCount,
940
993
  });
941
994
  }
942
995
  return this.consecutiveReconnects < this.maxConsecutiveReconnects;
@@ -946,7 +999,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
946
999
  // in their own batches before the originating batch is sent.
947
1000
  // Therefore, receiving them while attempting to send the originating batch
948
1001
  // does not mean that the container is making any progress.
949
- if ((message === null || message === void 0 ? void 0 : message.type) !== ContainerMessageType.ChunkedOp) {
1002
+ if (message?.type !== ContainerMessageType.ChunkedOp) {
950
1003
  this.consecutiveReconnects = 0;
951
1004
  }
952
1005
  }
@@ -961,7 +1014,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
961
1014
  // Save the old state, reset to false, disable event emit
962
1015
  const oldState = this.dirtyContainer;
963
1016
  this.dirtyContainer = false;
964
- (0, common_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
1017
+ (0, core_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
965
1018
  this.emitDirtyDocumentEvent = false;
966
1019
  let newState;
967
1020
  try {
@@ -995,21 +1048,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
995
1048
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
996
1049
  */
997
1050
  parseOpContent(serializedContent) {
998
- (0, common_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
999
- const parsed = JSON.parse(serializedContent);
1000
- (0, common_utils_1.assert)(parsed.type !== undefined, 0x6d6 /* incorrect op content format */);
1001
- return { type: parsed.type, contents: parsed.contents };
1051
+ (0, core_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1052
+ const { type, contents, compatDetails } = JSON.parse(serializedContent);
1053
+ (0, core_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
1054
+ return { type, contents, compatDetails };
1002
1055
  }
1003
1056
  async applyStashedOp(op) {
1004
1057
  // Need to parse from string for back-compat
1005
- const { type, contents } = this.parseOpContent(op);
1058
+ const { type, contents, compatDetails } = this.parseOpContent(op);
1006
1059
  switch (type) {
1007
1060
  case ContainerMessageType.FluidDataStoreOp:
1008
1061
  return this.dataStores.applyStashedOp(contents);
1009
1062
  case ContainerMessageType.Attach:
1010
1063
  return this.dataStores.applyStashedAttachOp(contents);
1011
1064
  case ContainerMessageType.IdAllocation:
1012
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1065
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1013
1066
  return this.applyStashedIdAllocationOp(contents);
1014
1067
  case ContainerMessageType.Alias:
1015
1068
  case ContainerMessageType.BlobAttach:
@@ -1018,8 +1071,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1018
1071
  throw new Error("chunkedOp not expected here");
1019
1072
  case ContainerMessageType.Rejoin:
1020
1073
  throw new Error("rejoin not expected here");
1021
- default:
1022
- (0, common_utils_1.unreachableCase)(type, `Unknown ContainerMessageType: ${type}`);
1074
+ default: {
1075
+ // This should be extremely rare for stashed ops.
1076
+ // It would require a newer runtime stashing ops and then an older one applying them,
1077
+ // e.g. if an app rolled back its container version
1078
+ const compatBehavior = compatDetails?.behavior;
1079
+ if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
1080
+ const error = telemetry_utils_1.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1081
+ messageDetails: JSON.stringify({
1082
+ type,
1083
+ compatBehavior,
1084
+ }),
1085
+ });
1086
+ this.closeFn(error);
1087
+ throw error;
1088
+ }
1089
+ }
1023
1090
  }
1024
1091
  }
1025
1092
  setConnectionState(connected, clientId) {
@@ -1031,32 +1098,20 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1031
1098
  // Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
1032
1099
  return;
1033
1100
  }
1034
- // If attachment blobs were added while disconnected, we need to delay
1035
- // propagation of the "connected" event until we have uploaded them to
1036
- // ensure we don't submit ops referencing a blob that has not been uploaded
1037
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1038
- const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1039
- if (connecting && this.blobManager.hasPendingOfflineUploads) {
1040
- (0, common_utils_1.assert)(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
1041
- (0, common_utils_1.assert)(!!clientId, 0x393 /* Must have clientId when connecting */);
1042
- this.delayConnectClientId = clientId;
1043
- this.blobManager.onConnected().then(() => {
1044
- // make sure we didn't reconnect before the promise resolved
1045
- if (this.delayConnectClientId === clientId && !this.disposed) {
1046
- this.delayConnectClientId = undefined;
1047
- this.setConnectionStateCore(connected, clientId);
1048
- }
1049
- }, (error) => this.closeFn(error));
1050
- return;
1051
- }
1052
1101
  this.setConnectionStateCore(connected, clientId);
1053
1102
  }
1054
1103
  setConnectionStateCore(connected, clientId) {
1055
- (0, common_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1104
+ (0, core_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1056
1105
  this.verifyNotClosed();
1057
1106
  // There might be no change of state due to Container calling this API after loading runtime.
1058
1107
  const changeOfState = this._connected !== connected;
1059
1108
  const reconnection = changeOfState && !connected;
1109
+ // We need to flush the ops currently collected by Outbox to preserve original order.
1110
+ // This flush NEEDS to happen before we set the ContainerRuntime to "connected".
1111
+ // We want these ops to get to the PendingStateManager without sending to service and have them return to the Outbox upon calling "replayPendingStates".
1112
+ if (changeOfState && connected) {
1113
+ this.flush();
1114
+ }
1060
1115
  this._connected = connected;
1061
1116
  if (!connected) {
1062
1117
  this._perfSignalData.signalsLost = 0;
@@ -1064,16 +1119,16 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1064
1119
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1065
1120
  }
1066
1121
  else {
1067
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
1122
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
1068
1123
  }
1069
1124
  // Fail while disconnected
1070
1125
  if (reconnection) {
1071
1126
  this.consecutiveReconnects++;
1072
1127
  if (!this.shouldContinueReconnecting()) {
1073
- this.closeFn(container_utils_1.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
1128
+ this.closeFn(telemetry_utils_1.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
1074
1129
  dataLoss: 1,
1075
1130
  attempts: this.consecutiveReconnects,
1076
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1131
+ pendingMessages: this.pendingMessagesCount,
1077
1132
  }));
1078
1133
  return;
1079
1134
  }
@@ -1090,18 +1145,23 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1090
1145
  }
1091
1146
  process(messageArg, local) {
1092
1147
  this.verifyNotClosed();
1093
- // Whether or not the message is actually a runtime message.
1148
+ // Whether or not the message appears to be a runtime message from an up-to-date client.
1094
1149
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
1095
1150
  // or something different, like a system message.
1096
- const runtimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
1151
+ const modernRuntimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
1097
1152
  // Do shallow copy of message, as the processing flow will modify it.
1098
- const messageCopy = Object.assign({}, messageArg);
1153
+ const messageCopy = { ...messageArg };
1099
1154
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1100
- this.processCore(message, local, runtimeMessage);
1155
+ this.processCore(message, local, modernRuntimeMessage);
1101
1156
  }
1102
1157
  }
1103
- processCore(message, local, runtimeMessage) {
1104
- var _a;
1158
+ /**
1159
+ * Direct the message to the correct subsystem for processing, and implement other side effects
1160
+ * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
1161
+ * @param local - Did this client send the op?
1162
+ * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
1163
+ */
1164
+ processCore(message, local, modernRuntimeMessage) {
1105
1165
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1106
1166
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1107
1167
  // messages once a batch has been fully processed.
@@ -1109,7 +1169,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1109
1169
  this._processedClientSequenceNumber = message.clientSequenceNumber;
1110
1170
  try {
1111
1171
  let localOpMetadata;
1112
- if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1172
+ if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1113
1173
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
1114
1174
  }
1115
1175
  // If there are no more pending messages after processing a local message,
@@ -1117,45 +1177,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1117
1177
  if (!this.hasPendingMessages()) {
1118
1178
  this.updateDocumentDirtyState(false);
1119
1179
  }
1120
- const type = message.type;
1121
- switch (type) {
1122
- case ContainerMessageType.Attach:
1123
- this.dataStores.processAttachMessage(message, local);
1124
- break;
1125
- case ContainerMessageType.Alias:
1126
- this.processAliasMessage(message, localOpMetadata, local);
1127
- break;
1128
- case ContainerMessageType.FluidDataStoreOp:
1129
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1130
- break;
1131
- case ContainerMessageType.BlobAttach:
1132
- this.blobManager.processBlobAttachOp(message, local);
1133
- break;
1134
- case ContainerMessageType.IdAllocation:
1135
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1136
- this.idCompressor.finalizeCreationRange(message.contents);
1137
- break;
1138
- case ContainerMessageType.ChunkedOp:
1139
- case ContainerMessageType.Rejoin:
1140
- break;
1141
- default:
1142
- if (runtimeMessage) {
1143
- const error = container_utils_1.DataProcessingError.create(
1144
- // Former assert 0x3ce
1145
- "Runtime message of unknown type", "OpProcessing", message, {
1146
- local,
1147
- type: message.type,
1148
- contentType: typeof message.contents,
1149
- batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
1150
- compression: message.compression,
1151
- });
1152
- this.closeFn(error);
1153
- throw error;
1154
- }
1155
- }
1156
- if (runtimeMessage || this.groupedBatchingEnabled) {
1157
- this.emit("op", message, runtimeMessage);
1158
- }
1180
+ this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
1181
+ this.emit("op", message, modernRuntimeMessage);
1159
1182
  this.scheduleManager.afterOpProcessing(undefined, message);
1160
1183
  if (local) {
1161
1184
  // If we have processed a local op, this means that the container is
@@ -1169,8 +1192,59 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1169
1192
  throw e;
1170
1193
  }
1171
1194
  }
1172
- processAliasMessage(message, localOpMetadata, local) {
1173
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
1195
+ /**
1196
+ * Assuming the given message is also a ContainerRuntimeMessage,
1197
+ * checks its type and dispatches the message to the appropriate handler in the runtime.
1198
+ * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
1199
+ */
1200
+ validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
1201
+ // Optimistically extract ContainerRuntimeMessage-specific props from the message
1202
+ const { type: maybeContainerMessageType, compatDetails } = message;
1203
+ switch (maybeContainerMessageType) {
1204
+ case ContainerMessageType.Attach:
1205
+ this.dataStores.processAttachMessage(message, local);
1206
+ break;
1207
+ case ContainerMessageType.Alias:
1208
+ this.dataStores.processAliasMessage(message, localOpMetadata, local);
1209
+ break;
1210
+ case ContainerMessageType.FluidDataStoreOp:
1211
+ this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1212
+ break;
1213
+ case ContainerMessageType.BlobAttach:
1214
+ this.blobManager.processBlobAttachOp(message, local);
1215
+ break;
1216
+ case ContainerMessageType.IdAllocation:
1217
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1218
+ this.idCompressor.finalizeCreationRange(message.contents);
1219
+ break;
1220
+ case ContainerMessageType.ChunkedOp:
1221
+ case ContainerMessageType.Rejoin:
1222
+ break;
1223
+ default: {
1224
+ // If we didn't necessarily expect a runtime message type, then no worries - just return
1225
+ // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
1226
+ if (!expectRuntimeMessageType) {
1227
+ return;
1228
+ }
1229
+ const compatBehavior = compatDetails?.behavior;
1230
+ if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
1231
+ const error = telemetry_utils_1.DataProcessingError.create(
1232
+ // Former assert 0x3ce
1233
+ "Runtime message of unknown type", "OpProcessing", message, {
1234
+ local,
1235
+ messageDetails: JSON.stringify({
1236
+ type: message.type,
1237
+ contentType: typeof message.contents,
1238
+ compatBehavior,
1239
+ batch: message.metadata?.batch,
1240
+ compression: message.compression,
1241
+ }),
1242
+ });
1243
+ this.closeFn(error);
1244
+ throw error;
1245
+ }
1246
+ }
1247
+ }
1174
1248
  }
1175
1249
  /**
1176
1250
  * Emits the Signal event and update the perf signal data.
@@ -1178,7 +1252,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1178
1252
  */
1179
1253
  sendSignalTelemetryEvent(clientSignalSequenceNumber) {
1180
1254
  const duration = Date.now() - this._perfSignalData.signalTimestamp;
1181
- this.logger.sendPerformanceEvent({
1255
+ this.mc.logger.sendPerformanceEvent({
1182
1256
  eventName: "SignalLatency",
1183
1257
  duration,
1184
1258
  signalsLost: this._perfSignalData.signalsLost,
@@ -1201,7 +1275,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1201
1275
  this._perfSignalData.trackingSignalSequenceNumber) {
1202
1276
  this._perfSignalData.signalsLost++;
1203
1277
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1204
- this.logger.sendErrorEvent({
1278
+ this.mc.logger.sendErrorEvent({
1205
1279
  eventName: "SignalLost",
1206
1280
  type: envelope.contents.type,
1207
1281
  signalsLost: this._perfSignalData.signalsLost,
@@ -1225,6 +1299,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1225
1299
  }
1226
1300
  this.dataStores.processSignal(envelope.address, transformed, local);
1227
1301
  }
1302
+ /**
1303
+ * Returns the runtime of the data store.
1304
+ * @param id - Id supplied during creating the data store.
1305
+ * @param wait - True if you want to wait for it.
1306
+ * @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
1307
+ */
1228
1308
  async getRootDataStore(id, wait = true) {
1229
1309
  return this.getRootDataStoreChannel(id, wait);
1230
1310
  }
@@ -1232,7 +1312,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1232
1312
  await this.dataStores.waitIfPendingAlias(id);
1233
1313
  const internalId = this.internalId(id);
1234
1314
  const context = await this.dataStores.getDataStore(internalId, { wait });
1235
- (0, common_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1315
+ (0, core_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1236
1316
  return context.realize();
1237
1317
  }
1238
1318
  /**
@@ -1240,9 +1320,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1240
1320
  * This method is expected to be called at the end of a batch.
1241
1321
  */
1242
1322
  flush() {
1243
- (0, common_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1323
+ (0, core_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1244
1324
  this.outbox.flush();
1245
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
1325
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
1246
1326
  }
1247
1327
  orderSequentially(callback) {
1248
1328
  let checkpoint;
@@ -1265,7 +1345,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1265
1345
  }
1266
1346
  catch (err) {
1267
1347
  const error2 = (0, telemetry_utils_1.wrapError)(err, (message) => {
1268
- return container_utils_1.DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
1348
+ return telemetry_utils_1.DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
1269
1349
  });
1270
1350
  this.closeFn(error2);
1271
1351
  throw error2;
@@ -1273,7 +1353,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1273
1353
  }
1274
1354
  else {
1275
1355
  // pre-0.58 error message: orderSequentiallyCallbackException
1276
- this.closeFn(new container_utils_1.GenericError("orderSequentially callback exception", error));
1356
+ this.closeFn(new telemetry_utils_1.GenericError("orderSequentially callback exception", error));
1277
1357
  }
1278
1358
  throw error; // throw the original error for the consumer of the runtime
1279
1359
  }
@@ -1286,29 +1366,49 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1286
1366
  }
1287
1367
  return result;
1288
1368
  }
1289
- async createDataStore(pkg) {
1290
- const internalId = (0, uuid_1.v4)();
1291
- return (0, dataStore_1.channelToDataStore)(await this._createDataStore(pkg, internalId), internalId, this, this.dataStores, this.mc.logger);
1369
+ /**
1370
+ * Returns the aliased data store's entryPoint, given the alias.
1371
+ * @param alias - The alias for the data store.
1372
+ * @returns The data store's entry point ({@link @fluidframework/core-interfaces#IFluidHandle}) if it exists and is aliased.
1373
+ * Returns undefined if no data store has been assigned the given alias.
1374
+ */
1375
+ async getAliasedDataStoreEntryPoint(alias) {
1376
+ await this.dataStores.waitIfPendingAlias(alias);
1377
+ const internalId = this.internalId(alias);
1378
+ const context = await this.dataStores.getDataStoreIfAvailable(internalId, { wait: false });
1379
+ // If the data store is not available or not an alias, return undefined.
1380
+ if (context === undefined || !(await context.isRoot())) {
1381
+ return undefined;
1382
+ }
1383
+ const channel = await context.realize();
1384
+ if (channel.entryPoint === undefined) {
1385
+ throw new telemetry_utils_1.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1386
+ }
1387
+ return channel.entryPoint;
1292
1388
  }
1293
1389
  createDetachedRootDataStore(pkg, rootDataStoreId) {
1294
1390
  if (rootDataStoreId.includes("/")) {
1295
- throw new container_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1391
+ throw new telemetry_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1296
1392
  }
1297
1393
  return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
1298
1394
  }
1299
1395
  createDetachedDataStore(pkg) {
1300
1396
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1301
1397
  }
1302
- async _createDataStoreWithProps(pkg, props, id = (0, uuid_1.v4)()) {
1303
- const fluidDataStore = await this.dataStores
1304
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1305
- .realize();
1306
- return (0, dataStore_1.channelToDataStore)(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1398
+ async createDataStore(pkg) {
1399
+ const id = (0, uuid_1.v4)();
1400
+ return (0, dataStore_1.channelToDataStore)(await this.dataStores
1401
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
1402
+ .realize(), id, this, this.dataStores, this.mc.logger);
1307
1403
  }
1308
- async _createDataStore(pkg, id = (0, uuid_1.v4)(), props) {
1309
- return this.dataStores
1404
+ /**
1405
+ * @deprecated 0.16 Issue #1537, #3631
1406
+ * @internal
1407
+ */
1408
+ async _createDataStoreWithProps(pkg, props, id = (0, uuid_1.v4)()) {
1409
+ return (0, dataStore_1.channelToDataStore)(await this.dataStores
1310
1410
  ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1311
- .realize();
1411
+ .realize(), id, this, this.dataStores, this.mc.logger);
1312
1412
  }
1313
1413
  canSendOps() {
1314
1414
  // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
@@ -1322,11 +1422,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1322
1422
  return this.flushMode !== runtime_definitions_1.FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
1323
1423
  }
1324
1424
  getQuorum() {
1325
- return this.context.quorum;
1425
+ return this._quorum;
1326
1426
  }
1327
1427
  getAudience() {
1328
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1329
- return this.context.audience;
1428
+ return this._audience;
1330
1429
  }
1331
1430
  /**
1332
1431
  * Returns true of container is dirty, i.e. there are some pending local changes that
@@ -1335,7 +1434,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1335
1434
  get isDirty() {
1336
1435
  return this.dirtyContainer;
1337
1436
  }
1338
- isContainerMessageDirtyable(type, contents) {
1437
+ isContainerMessageDirtyable({ type, contents }) {
1339
1438
  // For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
1340
1439
  // Ultimately we should have no special-cases from the ContainerRuntime's perspective.
1341
1440
  if (type === ContainerMessageType.Attach) {
@@ -1375,18 +1474,18 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1375
1474
  submitSignal(type, content) {
1376
1475
  this.verifyNotClosed();
1377
1476
  const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
1378
- return this.context.submitSignalFn(envelope);
1477
+ return this.submitSignalFn(envelope);
1379
1478
  }
1380
1479
  submitDataStoreSignal(address, type, content) {
1381
1480
  const envelope = this.createNewSignalEnvelope(address, type, content);
1382
- return this.context.submitSignalFn(envelope);
1481
+ return this.submitSignalFn(envelope);
1383
1482
  }
1384
1483
  setAttachState(attachState) {
1385
1484
  if (attachState === container_definitions_1.AttachState.Attaching) {
1386
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1485
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1387
1486
  }
1388
1487
  else {
1389
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1488
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1390
1489
  this.emit("attached");
1391
1490
  }
1392
1491
  if (attachState === container_definitions_1.AttachState.Attached && !this.hasPendingMessages()) {
@@ -1412,22 +1511,17 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1412
1511
  this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
1413
1512
  return summarizeResult.summary;
1414
1513
  }
1415
- async getAbsoluteUrl(relativeUrl) {
1416
- if (this.context.getAbsoluteUrl === undefined) {
1417
- throw new Error("Driver does not implement getAbsoluteUrl");
1418
- }
1419
- if (this.attachState !== container_definitions_1.AttachState.Attached) {
1420
- return undefined;
1421
- }
1422
- return this.context.getAbsoluteUrl(relativeUrl);
1423
- }
1424
1514
  async summarizeInternal(fullTree, trackState, telemetryContext) {
1425
1515
  const summarizeResult = await this.dataStores.summarize(fullTree, trackState, telemetryContext);
1426
1516
  // Wrap data store summaries in .channels subtree.
1427
1517
  (0, summary_1.wrapSummaryInChannelsTree)(summarizeResult);
1428
1518
  const pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
1429
1519
  this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
1430
- return Object.assign(Object.assign({}, summarizeResult), { id: "", pathPartsForChildren });
1520
+ return {
1521
+ ...summarizeResult,
1522
+ id: "",
1523
+ pathPartsForChildren,
1524
+ };
1431
1525
  }
1432
1526
  /**
1433
1527
  * Returns a summary of the runtime at the current sequence number.
@@ -1445,16 +1539,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1445
1539
  runSweep,
1446
1540
  });
1447
1541
  try {
1448
- let gcStats;
1449
1542
  if (runGC) {
1450
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1543
+ await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1451
1544
  }
1452
1545
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1453
- (0, common_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1454
- return { stats, summary, gcStats };
1546
+ (0, core_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1547
+ return { stats, summary };
1455
1548
  }
1456
1549
  finally {
1457
- this.logger.sendTelemetryEvent({
1550
+ this.mc.logger.sendTelemetryEvent({
1458
1551
  eventName: "SummarizeTelemetry",
1459
1552
  details: telemetryContext.serialize(),
1460
1553
  });
@@ -1516,7 +1609,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1516
1609
  /**
1517
1610
  * After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
1518
1611
  * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
1519
- * @returns - The routes of nodes that were deleted.
1612
+ * @returns The routes of nodes that were deleted.
1520
1613
  */
1521
1614
  deleteSweepReadyNodes(sweepReadyRoutes) {
1522
1615
  const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
@@ -1536,21 +1629,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1536
1629
  * Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
1537
1630
  */
1538
1631
  getCurrentReferenceTimestampMs() {
1539
- var _a, _b, _c;
1540
1632
  // Use the timestamp of the last message seen by this client as that is server generated. If no messages have
1541
1633
  // been processed, use the timestamp of the message from the last summary.
1542
- return (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : (_c = this.messageAtLastSummary) === null || _c === void 0 ? void 0 : _c.timestamp;
1634
+ return this.deltaManager.lastMessage?.timestamp ?? this.messageAtLastSummary?.timestamp;
1543
1635
  }
1544
1636
  /**
1545
1637
  * Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
1546
1638
  * blob manager.
1547
1639
  */
1548
1640
  getNodeType(nodePath) {
1549
- var _a;
1550
1641
  if (this.isBlobPath(nodePath)) {
1551
1642
  return gc_1.GCNodeType.Blob;
1552
1643
  }
1553
- return (_a = this.dataStores.getGCNodeType(nodePath)) !== null && _a !== void 0 ? _a : gc_1.GCNodeType.Other;
1644
+ return this.dataStores.getGCNodeType(nodePath) ?? gc_1.GCNodeType.Other;
1554
1645
  }
1555
1646
  /**
1556
1647
  * Called by GC to retrieve the package path of the node with the given path. The node should belong to a
@@ -1564,7 +1655,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1564
1655
  case gc_1.GCNodeType.SubDataStore:
1565
1656
  return this.dataStores.getDataStorePackagePath(nodePath);
1566
1657
  default:
1567
- (0, common_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
1658
+ (0, core_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
1568
1659
  }
1569
1660
  }
1570
1661
  /**
@@ -1580,7 +1671,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1580
1671
  /**
1581
1672
  * From a given list of routes, separate and return routes that belong to blob manager and data stores.
1582
1673
  * @param routes - A list of routes that can belong to data stores or blob manager.
1583
- * @returns - Two route lists - One that contains routes for blob manager and another one that contains routes
1674
+ * @returns Two route lists - One that contains routes for blob manager and another one that contains routes
1584
1675
  * for data stores.
1585
1676
  */
1586
1677
  getDataStoreAndBlobManagerRoutes(routes) {
@@ -1621,23 +1712,62 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1621
1712
  * @param options - options controlling how the summary is generated or submitted
1622
1713
  */
1623
1714
  async submitSummary(options) {
1624
- var _a, _b, _c;
1625
- const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1715
+ const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
1626
1716
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1627
1717
  // use it for all events logged during this summary.
1628
1718
  const summaryNumber = this.nextSummaryNumber;
1629
- const summaryNumberLogger = telemetry_utils_1.ChildLogger.create(summaryLogger, undefined, {
1630
- all: { summaryNumber },
1719
+ const summaryNumberLogger = (0, telemetry_utils_1.createChildLogger)({
1720
+ logger: summaryLogger,
1721
+ properties: {
1722
+ all: { summaryNumber },
1723
+ },
1631
1724
  });
1632
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1725
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1633
1726
  let latestSnapshotVersionId;
1634
1727
  if (refreshLatestAck) {
1635
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(telemetry_utils_1.ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1728
+ const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer((0, telemetry_utils_1.createChildLogger)({
1729
+ logger: summaryNumberLogger,
1730
+ properties: { all: { safeSummary: true } },
1731
+ }));
1636
1732
  const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1637
1733
  latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1638
1734
  // We might need to catch up to the latest summary's reference sequence number before pausing.
1639
1735
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1640
1736
  }
1737
+ // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
1738
+ // incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
1739
+ // within the timeout, check if it should be failed or can continue.
1740
+ if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
1741
+ const countBefore = this.pendingMessagesCount;
1742
+ // The timeout for waiting for pending ops can be overridden via configurations.
1743
+ const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
1744
+ exports.defaultPendingOpsWaitTimeoutMs;
1745
+ await new Promise((resolve, reject) => {
1746
+ const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
1747
+ this.once("saved", () => {
1748
+ clearTimeout(timeoutId);
1749
+ resolve();
1750
+ });
1751
+ this.once("dispose", () => {
1752
+ clearTimeout(timeoutId);
1753
+ reject(new Error("Runtime is disposed while summarizing"));
1754
+ });
1755
+ });
1756
+ // Log that there are pending ops while summarizing. This will help us gather data on how often this
1757
+ // happens, whether we attempted to wait for these ops to be acked and what was the result.
1758
+ summaryNumberLogger.sendTelemetryEvent({
1759
+ eventName: "PendingOpsWhileSummarizing",
1760
+ saved: this.hasPendingMessages() ? false : true,
1761
+ timeout: pendingOpsTimeout,
1762
+ countBefore,
1763
+ countAfter: this.pendingMessagesCount,
1764
+ });
1765
+ // There could still be pending ops. Check if summary should fail or continue.
1766
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, this.deltaManager.lastSequenceNumber, this.deltaManager.minimumSequenceNumber, finalAttempt, true /* beforeSummaryGeneration */);
1767
+ if (pendingMessagesFailResult !== undefined) {
1768
+ return pendingMessagesFailResult;
1769
+ }
1770
+ }
1641
1771
  const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
1642
1772
  let summaryRefSeqNum;
1643
1773
  try {
@@ -1652,7 +1782,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1652
1782
  this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
1653
1783
  // Helper function to check whether we should still continue between each async step.
1654
1784
  const checkContinue = () => {
1655
- var _a;
1656
1785
  // Do not check for loss of connectivity directly! Instead leave it up to
1657
1786
  // RunWhileConnectedCoordinator to control policy in a single place.
1658
1787
  // This will allow easier change of design if we chose to. For example, we may chose to allow
@@ -1665,7 +1794,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1665
1794
  // That said, we rely on submitSystemMessage() that today only works in connected state.
1666
1795
  // So if we fail here, it either means that RunWhileConnectedCoordinator does not work correctly,
1667
1796
  // OR that design changed and we need to remove this check and fix submitSystemMessage.
1668
- (0, common_utils_1.assert)(this.connected, 0x258 /* "connected" */);
1797
+ (0, core_utils_1.assert)(this.connected, 0x258 /* "connected" */);
1669
1798
  // Ensure that lastSequenceNumber has not changed after pausing.
1670
1799
  // We need the summary op's reference sequence number to match our summary sequence number,
1671
1800
  // otherwise we'll get the wrong sequence number stamped on the summary's .protocol attributes.
@@ -1675,7 +1804,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1675
1804
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1676
1805
  };
1677
1806
  }
1678
- (0, common_utils_1.assert)(summaryRefSeqNum === ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber), 0x395 /* it's one and the same thing */);
1807
+ (0, core_utils_1.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
1679
1808
  if (lastAck !== this.summaryCollection.latestAck) {
1680
1809
  return {
1681
1810
  continue: false,
@@ -1693,7 +1822,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1693
1822
  error: continueResult.error,
1694
1823
  };
1695
1824
  }
1696
- const trace = common_utils_1.Trace.start();
1825
+ const trace = client_utils_1.Trace.start();
1697
1826
  let summarizeResult;
1698
1827
  // If the GC state needs to be reset, we need to force a full tree summary and update the unreferenced
1699
1828
  // state of all the nodes.
@@ -1714,6 +1843,25 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1714
1843
  error,
1715
1844
  };
1716
1845
  }
1846
+ // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
1847
+ if (this.validateSummaryBeforeUpload) {
1848
+ // Validate that the summaries generated by summarize nodes is correct.
1849
+ const validateResult = this.summarizerNode.validateSummary();
1850
+ if (!validateResult.success) {
1851
+ const { success, ...loggingProps } = validateResult;
1852
+ const error = new summary_1.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
1853
+ return {
1854
+ stage: "base",
1855
+ referenceSequenceNumber: summaryRefSeqNum,
1856
+ minimumSequenceNumber,
1857
+ error,
1858
+ };
1859
+ }
1860
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
1861
+ if (pendingMessagesFailResult !== undefined) {
1862
+ return pendingMessagesFailResult;
1863
+ }
1864
+ }
1717
1865
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
1718
1866
  // Now that we have generated the summary, update the message at last summary to the last message processed.
1719
1867
  this.messageAtLastSummary = this.deltaManager.lastMessage;
@@ -1721,12 +1869,20 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1721
1869
  // Because handles are unchanged dataStores in the current logic,
1722
1870
  // summarized dataStore count is total dataStore count minus handle count
1723
1871
  const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
1724
- (0, common_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1872
+ (0, core_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1725
1873
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
1726
1874
  const gcSummaryTreeStats = summaryTree.tree[runtime_definitions_1.gcTreeKey]
1727
1875
  ? (0, runtime_utils_1.calculateStats)(summaryTree.tree[runtime_definitions_1.gcTreeKey])
1728
1876
  : undefined;
1729
- const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, summaryNumber }, partialStats);
1877
+ const summaryStats = {
1878
+ dataStoreCount: this.dataStores.size,
1879
+ summarizedDataStoreCount: this.dataStores.size - handleCount,
1880
+ gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
1881
+ gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
1882
+ gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
1883
+ summaryNumber,
1884
+ ...partialStats,
1885
+ };
1730
1886
  const generateSummaryData = {
1731
1887
  referenceSequenceNumber: summaryRefSeqNum,
1732
1888
  minimumSequenceNumber,
@@ -1735,19 +1891,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1735
1891
  generateDuration: trace.trace().duration,
1736
1892
  forcedFullTree,
1737
1893
  };
1738
- // If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
1739
- // correct before this summary is uploaded.
1740
- if (this.validateSummaryBeforeUpload) {
1741
- const validateResult = this.summarizerNode.validateSummary();
1742
- if (!validateResult.success) {
1743
- const { success } = validateResult, loggingProps = __rest(validateResult, ["success"]);
1744
- const error = new summary_1.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, Object.assign({}, loggingProps));
1745
- return Object.assign(Object.assign({ stage: "base" }, generateSummaryData), { error });
1746
- }
1747
- }
1748
1894
  continueResult = checkContinue();
1749
1895
  if (!continueResult.continue) {
1750
- return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
1896
+ return { stage: "generate", ...generateSummaryData, error: continueResult.error };
1751
1897
  }
1752
1898
  // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
1753
1899
  // summary. So if the previous summarizer closes just after submitting the summary and before
@@ -1755,7 +1901,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1755
1901
  // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1756
1902
  // the one fetched from storage as parent as that is the latest.
1757
1903
  let summaryContext;
1758
- if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId &&
1904
+ if (lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId &&
1759
1905
  latestSnapshotVersionId !== undefined) {
1760
1906
  summaryContext = {
1761
1907
  proposalHandle: undefined,
@@ -1766,7 +1912,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1766
1912
  else if (lastAck === undefined) {
1767
1913
  summaryContext = {
1768
1914
  proposalHandle: undefined,
1769
- ackHandle: (_a = this.context.getLoadedFromVersion()) === null || _a === void 0 ? void 0 : _a.id,
1915
+ ackHandle: this.loadedFromVersionId,
1770
1916
  referenceSequenceNumber: summaryRefSeqNum,
1771
1917
  };
1772
1918
  }
@@ -1782,7 +1928,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1782
1928
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
1783
1929
  }
1784
1930
  catch (error) {
1785
- return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error });
1931
+ return { stage: "generate", ...generateSummaryData, error };
1786
1932
  }
1787
1933
  const parent = summaryContext.ackHandle;
1788
1934
  const summaryMessage = {
@@ -1792,25 +1938,34 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1792
1938
  message,
1793
1939
  parents: parent ? [parent] : [],
1794
1940
  };
1795
- const uploadData = Object.assign(Object.assign({}, generateSummaryData), { handle, uploadDuration: trace.trace().duration });
1941
+ const uploadData = {
1942
+ ...generateSummaryData,
1943
+ handle,
1944
+ uploadDuration: trace.trace().duration,
1945
+ };
1796
1946
  continueResult = checkContinue();
1797
1947
  if (!continueResult.continue) {
1798
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error: continueResult.error });
1948
+ return { stage: "upload", ...uploadData, error: continueResult.error };
1799
1949
  }
1800
1950
  let clientSequenceNumber;
1801
1951
  try {
1802
1952
  clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
1803
1953
  }
1804
1954
  catch (error) {
1805
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
1955
+ return { stage: "upload", ...uploadData, error };
1806
1956
  }
1807
- const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
1957
+ const submitData = {
1958
+ stage: "submit",
1959
+ ...uploadData,
1960
+ clientSequenceNumber,
1961
+ submitOpDuration: trace.trace().duration,
1962
+ };
1808
1963
  try {
1809
1964
  // If validateSummaryBeforeUpload is false, the summary should be validated in this step.
1810
1965
  this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
1811
1966
  }
1812
1967
  catch (error) {
1813
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
1968
+ return { stage: "upload", ...uploadData, error };
1814
1969
  }
1815
1970
  return submitData;
1816
1971
  }
@@ -1818,7 +1973,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1818
1973
  // Cleanup wip summary in case of failure
1819
1974
  this.summarizerNode.clearSummary();
1820
1975
  // ! This needs to happen before we resume inbound queues to ensure heuristics are tracked correctly
1821
- (_c = (_b = this._summarizer) === null || _b === void 0 ? void 0 : _b.recordSummaryAttempt) === null || _c === void 0 ? void 0 : _c.call(_b, summaryRefSeqNum);
1976
+ this._summarizer?.recordSummaryAttempt?.(summaryRefSeqNum);
1822
1977
  // Restart the delta manager
1823
1978
  this.deltaManager.inbound.resume();
1824
1979
  if (shouldPauseInboundSignal) {
@@ -1826,16 +1981,63 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1826
1981
  }
1827
1982
  }
1828
1983
  }
1984
+ /**
1985
+ * This helper is called during summarization. If there are pending ops, it will return a failed summarize result
1986
+ * (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
1987
+ * @param logger - The logger to be used for sending telemetry.
1988
+ * @param referenceSequenceNumber - The reference sequence number of the summary attempt.
1989
+ * @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
1990
+ * @param finalAttempt - Whether this is the final summary attempt.
1991
+ * @param beforeSummaryGeneration - Whether this is called before summary generation or after.
1992
+ * @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
1993
+ */
1994
+ async shouldFailSummaryOnPendingOps(logger, referenceSequenceNumber, minimumSequenceNumber, finalAttempt, beforeSummaryGeneration) {
1995
+ if (!this.hasPendingMessages()) {
1996
+ return;
1997
+ }
1998
+ // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
1999
+ // This is a fallback to make progress in documents where there are consistently pending ops in
2000
+ // the summarizer.
2001
+ if (finalAttempt &&
2002
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
2003
+ const error = telemetry_utils_1.DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
2004
+ logger.sendErrorEvent({
2005
+ eventName: "SkipFailingIncorrectSummary",
2006
+ referenceSequenceNumber,
2007
+ minimumSequenceNumber,
2008
+ beforeGenerate: beforeSummaryGeneration,
2009
+ }, error);
2010
+ }
2011
+ else {
2012
+ // The retry delay when there are pending ops can be overridden via config so that we can adjust it
2013
+ // based on telemetry while we decide on a stable number.
2014
+ const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
2015
+ exports.defaultPendingOpsRetryDelayMs;
2016
+ const error = new summary_1.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
2017
+ count: this.pendingMessagesCount,
2018
+ beforeGenerate: beforeSummaryGeneration,
2019
+ });
2020
+ return {
2021
+ stage: "base",
2022
+ referenceSequenceNumber,
2023
+ minimumSequenceNumber,
2024
+ error,
2025
+ };
2026
+ }
2027
+ }
2028
+ get pendingMessagesCount() {
2029
+ return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
2030
+ }
1829
2031
  hasPendingMessages() {
1830
- return this.pendingStateManager.hasPendingMessages() || !this.outbox.isEmpty;
2032
+ return this.pendingMessagesCount !== 0;
1831
2033
  }
1832
2034
  updateDocumentDirtyState(dirty) {
1833
2035
  if (this.attachState !== container_definitions_1.AttachState.Attached) {
1834
- (0, common_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
2036
+ (0, core_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
1835
2037
  }
1836
2038
  else {
1837
2039
  // Other way is not true = see this.isContainerMessageDirtyable()
1838
- (0, common_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
2040
+ (0, core_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
1839
2041
  }
1840
2042
  if (this.dirtyContainer === dirty) {
1841
2043
  return;
@@ -1843,7 +2045,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1843
2045
  this.dirtyContainer = dirty;
1844
2046
  if (this.emitDirtyDocumentEvent) {
1845
2047
  this.emit(dirty ? "dirty" : "saved");
1846
- this.context.updateDirtyContainerState(dirty);
1847
2048
  }
1848
2049
  }
1849
2050
  submitDataStoreOp(id, contents, localOpMetadata = undefined) {
@@ -1851,29 +2052,28 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1851
2052
  address: id,
1852
2053
  contents,
1853
2054
  };
1854
- this.submit(ContainerMessageType.FluidDataStoreOp, envelope, localOpMetadata);
2055
+ this.submit({ type: ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
1855
2056
  }
1856
2057
  submitDataStoreAliasOp(contents, localOpMetadata) {
1857
2058
  const aliasMessage = contents;
1858
2059
  if (!(0, dataStore_1.isDataStoreAliasMessage)(aliasMessage)) {
1859
- throw new container_utils_1.UsageError("malformedDataStoreAliasMessage");
2060
+ throw new telemetry_utils_1.UsageError("malformedDataStoreAliasMessage");
1860
2061
  }
1861
- this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
2062
+ this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
1862
2063
  }
1863
- async uploadBlob(blob) {
2064
+ async uploadBlob(blob, signal) {
1864
2065
  this.verifyNotClosed();
1865
- return this.blobManager.createBlob(blob);
2066
+ return this.blobManager.createBlob(blob, signal);
1866
2067
  }
1867
2068
  maybeSubmitIdAllocationOp(type) {
1868
- var _a, _b;
1869
2069
  if (type !== ContainerMessageType.IdAllocation) {
1870
2070
  let idAllocationBatchMessage;
1871
2071
  let idRange;
1872
2072
  if (this.idCompressorEnabled) {
1873
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
2073
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
1874
2074
  idRange = this.idCompressor.takeNextCreationRange();
1875
2075
  // Don't include the idRange if there weren't any Ids allocated
1876
- idRange = ((_a = idRange === null || idRange === void 0 ? void 0 : idRange.ids) === null || _a === void 0 ? void 0 : _a.first) !== undefined ? idRange : undefined;
2076
+ idRange = idRange?.ids !== undefined ? idRange : undefined;
1877
2077
  }
1878
2078
  if (idRange !== undefined) {
1879
2079
  const idAllocationMessage = {
@@ -1884,7 +2084,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1884
2084
  contents: JSON.stringify(idAllocationMessage),
1885
2085
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
1886
2086
  metadata: undefined,
1887
- localOpMetadata: (_b = this.idCompressor) === null || _b === void 0 ? void 0 : _b.serialize(true),
2087
+ localOpMetadata: this.idCompressor?.serialize(true),
1888
2088
  type: ContainerMessageType.IdAllocation,
1889
2089
  };
1890
2090
  }
@@ -1893,20 +2093,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1893
2093
  }
1894
2094
  }
1895
2095
  }
1896
- submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
2096
+ submit(containerRuntimeMessage, localOpMetadata = undefined, metadata = undefined) {
1897
2097
  this.verifyNotClosed();
1898
2098
  this.verifyCanSubmitOps();
1899
2099
  // There should be no ops in detached container state!
1900
- (0, common_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1901
- const serializedContent = JSON.stringify({ type, contents });
2100
+ (0, core_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2101
+ const serializedContent = JSON.stringify(containerRuntimeMessage);
1902
2102
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
1903
2103
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
1904
2104
  if (this.innerDeltaManager.readOnlyInfo.readonly) {
1905
- this.logger.sendTelemetryEvent({
2105
+ this.mc.logger.sendTelemetryEvent({
1906
2106
  eventName: "SubmitOpInReadonly",
1907
2107
  connected: this.connected,
1908
2108
  });
1909
2109
  }
2110
+ const type = containerRuntimeMessage.type;
1910
2111
  const message = {
1911
2112
  contents: serializedContent,
1912
2113
  type,
@@ -1963,7 +2164,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1963
2164
  this.closeFn(error);
1964
2165
  throw error;
1965
2166
  }
1966
- if (this.isContainerMessageDirtyable(type, contents)) {
2167
+ if (this.isContainerMessageDirtyable(containerRuntimeMessage)) {
1967
2168
  this.updateDocumentDirtyState(true);
1968
2169
  }
1969
2170
  }
@@ -1996,19 +2197,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1996
2197
  setTimeout(flush, 0);
1997
2198
  break;
1998
2199
  default:
1999
- (0, common_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
2200
+ (0, core_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
2000
2201
  break;
2001
2202
  }
2002
2203
  }
2003
2204
  submitSummaryMessage(contents, referenceSequenceNumber) {
2004
2205
  this.verifyNotClosed();
2005
- (0, common_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
2206
+ (0, core_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
2006
2207
  // System message should not be sent in the middle of the batch.
2007
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
2208
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
2008
2209
  // back-compat: ADO #1385: Make this call unconditional in the future
2009
- return this.context.submitSummaryFn !== undefined
2010
- ? this.context.submitSummaryFn(contents, referenceSequenceNumber)
2011
- : this.context.submitFn(protocol_definitions_1.MessageType.Summarize, contents, false);
2210
+ return this.submitSummaryFn !== undefined
2211
+ ? this.submitSummaryFn(contents, referenceSequenceNumber)
2212
+ : this.submitFn(protocol_definitions_1.MessageType.Summarize, contents, false);
2012
2213
  }
2013
2214
  /**
2014
2215
  * Throw an error if the runtime is closed. Methods that are expected to potentially
@@ -2025,7 +2226,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2025
2226
  if (this.opReentryCallsToReport > 0) {
2026
2227
  this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
2027
2228
  // We need to capture the call stack in order to inspect the source of this usage pattern
2028
- (0, opLifecycle_1.getLongStack)(() => new container_utils_1.UsageError(errorMessage)));
2229
+ (0, opLifecycle_1.getLongStack)(() => new telemetry_utils_1.UsageError(errorMessage)));
2029
2230
  this.opReentryCallsToReport--;
2030
2231
  }
2031
2232
  // Creating ops while processing ops can lead
@@ -2041,7 +2242,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2041
2242
  // The runtime must enforce op coherence by not allowing ops to be submitted
2042
2243
  // while ops are being processed.
2043
2244
  if (this.enableOpReentryCheck) {
2044
- throw new container_utils_1.UsageError(errorMessage);
2245
+ throw new telemetry_utils_1.UsageError(errorMessage);
2045
2246
  }
2046
2247
  }
2047
2248
  }
@@ -2055,32 +2256,33 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2055
2256
  }
2056
2257
  reSubmit(message) {
2057
2258
  // Need to parse from string for back-compat
2058
- const { contents, type } = this.parseOpContent(message.content);
2059
- this.reSubmitCore(type, contents, message.localOpMetadata, message.opMetadata);
2259
+ const containerRuntimeMessage = this.parseOpContent(message.content);
2260
+ this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
2060
2261
  }
2061
2262
  /**
2062
2263
  * Finds the right store and asks it to resubmit the message. This typically happens when we
2063
2264
  * reconnect and there are pending messages.
2064
- * @param content - The content of the original message.
2265
+ * @param message - The original ContainerRuntimeMessage.
2065
2266
  * @param localOpMetadata - The local metadata associated with the original message.
2066
2267
  */
2067
- reSubmitCore(type, content, localOpMetadata, opMetadata) {
2068
- switch (type) {
2268
+ reSubmitCore(message, localOpMetadata, opMetadata) {
2269
+ const contents = message.contents;
2270
+ switch (message.type) {
2069
2271
  case ContainerMessageType.FluidDataStoreOp:
2070
2272
  // For Operations, call resubmitDataStoreOp which will find the right store
2071
2273
  // and trigger resubmission on it.
2072
- this.dataStores.resubmitDataStoreOp(content, localOpMetadata);
2274
+ this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
2073
2275
  break;
2074
2276
  case ContainerMessageType.Attach:
2075
2277
  case ContainerMessageType.Alias:
2076
- this.submit(type, content, localOpMetadata);
2278
+ this.submit(message, localOpMetadata);
2077
2279
  break;
2078
2280
  case ContainerMessageType.IdAllocation:
2079
2281
  // Remove the stashedState from the op if it's a stashed op
2080
- if (content.stashedState !== undefined) {
2081
- delete content.stashedState;
2282
+ if (contents.stashedState !== undefined) {
2283
+ delete contents.stashedState;
2082
2284
  }
2083
- this.submit(type, content, localOpMetadata);
2285
+ this.submit(message, localOpMetadata);
2084
2286
  break;
2085
2287
  case ContainerMessageType.ChunkedOp:
2086
2288
  throw new Error(`chunkedOp not expected here`);
@@ -2088,10 +2290,29 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2088
2290
  this.blobManager.reSubmit(opMetadata);
2089
2291
  break;
2090
2292
  case ContainerMessageType.Rejoin:
2091
- this.submit(type, content);
2293
+ this.submit(message);
2092
2294
  break;
2093
- default:
2094
- (0, common_utils_1.unreachableCase)(type, `Unknown ContainerMessageType: ${type}`);
2295
+ default: {
2296
+ // This case should be very rare - it would imply an op was stashed from a
2297
+ // future version of runtime code and now is being applied on an older version
2298
+ const compatBehavior = message.compatDetails?.behavior;
2299
+ if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
2300
+ this.logger.sendTelemetryEvent({
2301
+ eventName: "resubmitUnrecognizedMessageTypeAllowed",
2302
+ messageDetails: { type: message.type, compatBehavior },
2303
+ });
2304
+ }
2305
+ else {
2306
+ const error = telemetry_utils_1.DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
2307
+ messageDetails: JSON.stringify({
2308
+ type: message.type,
2309
+ compatBehavior,
2310
+ }),
2311
+ });
2312
+ this.closeFn(error);
2313
+ throw error;
2314
+ }
2315
+ }
2095
2316
  }
2096
2317
  }
2097
2318
  rollback(content, localOpMetadata) {
@@ -2104,6 +2325,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2104
2325
  this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
2105
2326
  break;
2106
2327
  default:
2328
+ // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
2107
2329
  throw new Error(`Can't rollback ${type}`);
2108
2330
  }
2109
2331
  }
@@ -2121,29 +2343,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2121
2343
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2122
2344
  async refreshLatestSummaryAck(options) {
2123
2345
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
2346
+ // proposalHandle is always passed from RunningSummarizer.
2347
+ (0, core_utils_1.assert)(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
2124
2348
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2125
- // The call to fetch the snapshot is very expensive and not always needed.
2126
- // It should only be done by the summarizerNode, if required.
2127
- // When fetching from storage we will always get the latest version and do not use the ackHandle.
2128
- const fetchLatestSnapshot = async () => {
2129
- let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2349
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
2350
+ /**
2351
+ * When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
2352
+ * current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
2353
+ * it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
2354
+ * and then close as the current main client is likely to be re-elected as the parent summarizer again.
2355
+ */
2356
+ if (!result.isSummaryTracked && result.isSummaryNewer) {
2357
+ const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2130
2358
  eventName: "RefreshLatestSummaryAckFetch",
2131
2359
  ackHandle,
2132
2360
  targetSequenceNumber: summaryRefSeq,
2133
- }, readAndParseBlob);
2134
- /**
2135
- * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
2136
- * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
2137
- * these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
2138
- * change that started fetching latest snapshot always.
2139
- */
2140
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2141
- fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2142
- eventName: "RefreshLatestSummaryAckFetchBackCompat",
2143
- ackHandle,
2144
- targetSequenceNumber: summaryRefSeq,
2145
- }, readAndParseBlob, ackHandle);
2146
- }
2361
+ }, readAndParseBlob, null);
2147
2362
  /**
2148
2363
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
2149
2364
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -2155,25 +2370,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2155
2370
  * state.
2156
2371
  */
2157
2372
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2158
- const error = container_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
2373
+ const error = telemetry_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
2159
2374
  ackHandle,
2160
2375
  summaryRefSeq,
2161
2376
  fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
2162
2377
  });
2163
- this.closeFn(error);
2378
+ this.disposeFn(error);
2164
2379
  throw error;
2165
2380
  }
2166
- // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
2167
- // wait for the delta manager to catch up before refreshing the latest Summary.
2168
- await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
2169
- return {
2170
- snapshotTree: fetchResult.snapshotTree,
2171
- snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
2172
- };
2173
- };
2174
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
2381
+ await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
2382
+ return;
2383
+ }
2175
2384
  // Notify the garbage collector so it can update its latest summary state.
2176
- await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
2385
+ await this.garbageCollector.refreshLatestSummary(result);
2177
2386
  }
2178
2387
  /**
2179
2388
  * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
@@ -2183,31 +2392,38 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2183
2392
  */
2184
2393
  async refreshLatestSummaryAckFromServer(summaryLogger) {
2185
2394
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2186
- const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2395
+ const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
2187
2396
  eventName: "RefreshLatestSummaryFromServerFetch",
2188
- }, readAndParseBlob);
2189
- const fetchLatestSnapshot = {
2190
- snapshotTree,
2191
- snapshotRefSeq: latestSnapshotRefSeq,
2192
- };
2193
- const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
2194
- // Notify the garbage collector so it can update its latest summary state.
2195
- await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
2397
+ }, readAndParseBlob, null);
2398
+ await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
2196
2399
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2197
2400
  }
2198
- async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2199
- return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
2401
+ async closeStaleSummarizer(codePath) {
2402
+ this.mc.logger.sendTelemetryEvent({
2403
+ eventName: "ClosingSummarizerOnSummaryStale",
2404
+ codePath,
2405
+ message: "Stopping fetch from storage",
2406
+ closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2407
+ }, new telemetry_utils_1.GenericError("Restarting summarizer instead of refreshing"));
2408
+ // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2409
+ await (0, core_utils_1.delay)(this.closeSummarizerDelayMs);
2410
+ this._summarizer?.stop("latestSummaryStateStale");
2411
+ this.disposeFn();
2200
2412
  }
2413
+ /**
2414
+ * Downloads snapshot from storage with the given versionId or latest if versionId is null.
2415
+ * By default, it also closes the container after downloading the snapshot. However, this may be
2416
+ * overridden via options.
2417
+ */
2201
2418
  async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
2202
- var _a;
2203
- const snapshotResults = await telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2419
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2204
2420
  const stats = {};
2205
- const trace = common_utils_1.Trace.start();
2421
+ const trace = client_utils_1.Trace.start();
2206
2422
  const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
2207
- (0, common_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2423
+ (0, core_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2208
2424
  stats.getVersionDuration = trace.trace().duration;
2209
2425
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
2210
- (0, common_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2426
+ (0, core_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2211
2427
  stats.getSnapshotDuration = trace.trace().duration;
2212
2428
  const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(maybeSnapshot, readAndParseBlob);
2213
2429
  stats.snapshotRefSeq = latestSnapshotRefSeq;
@@ -2219,33 +2435,65 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2219
2435
  latestSnapshotRefSeq,
2220
2436
  };
2221
2437
  });
2222
- // We choose to close the summarizer after the snapshot cache is updated to avoid
2223
- // situations which the main client (which is likely to be re-elected as the leader again)
2224
- // loads the summarizer from cache.
2225
- if (this.summaryStateUpdateMethod === "restart") {
2226
- const error = new container_utils_1.GenericError("Restarting summarizer instead of refreshing");
2227
- this.mc.logger.sendTelemetryEvent(Object.assign(Object.assign({}, event), { eventName: "ClosingSummarizerOnSummaryStale", codePath: event.eventName, message: "Stopping fetch from storage", versionId: versionId != null ? versionId : undefined, closeSummarizerDelayMs: this.closeSummarizerDelayMs }), error);
2228
- // Delay 10 seconds before restarting summarizer to prevent the summarizer from restarting too frequently.
2229
- await (0, common_utils_1.delay)(this.closeSummarizerDelayMs);
2230
- (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.stop("latestSummaryStateStale");
2231
- this.closeFn();
2232
- throw error;
2233
- }
2234
- return snapshotResults;
2235
2438
  }
2236
2439
  notifyAttaching() { } // do nothing (deprecated method)
2237
- getPendingLocalState() {
2238
- if (this._orderSequentiallyCalls !== 0) {
2239
- throw new container_utils_1.UsageError("can't get state during orderSequentially");
2440
+ async getPendingLocalState(props) {
2441
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
2442
+ eventName: "getPendingLocalState",
2443
+ notifyImminentClosure: props?.notifyImminentClosure,
2444
+ }, async (event) => {
2445
+ this.verifyNotClosed();
2446
+ const waitBlobsToAttach = props?.notifyImminentClosure;
2447
+ if (this._orderSequentiallyCalls !== 0) {
2448
+ throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
2449
+ }
2450
+ const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2451
+ const pending = this.pendingStateManager.getLocalState();
2452
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2453
+ return; // no pending state to save
2454
+ }
2455
+ // Flush pending batch.
2456
+ // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2457
+ // to close current batch.
2458
+ this.flush();
2459
+ const pendingState = {
2460
+ pending,
2461
+ pendingAttachmentBlobs,
2462
+ };
2463
+ event.end({
2464
+ attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
2465
+ pendingOpsSize: pending?.pendingStates.length,
2466
+ });
2467
+ return pendingState;
2468
+ });
2469
+ }
2470
+ summarizeOnDemand(options) {
2471
+ if (this.isSummarizerClient) {
2472
+ return this.summarizer.summarizeOnDemand(options);
2473
+ }
2474
+ else if (this.summaryManager !== undefined) {
2475
+ return this.summaryManager.summarizeOnDemand(options);
2476
+ }
2477
+ else {
2478
+ // If we're not the summarizer, and we don't have a summaryManager, we expect that
2479
+ // disableSummaries is turned on. We are throwing instead of returning a failure here,
2480
+ // because it is a misuse of the API rather than an expected failure.
2481
+ throw new telemetry_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
2482
+ }
2483
+ }
2484
+ enqueueSummarize(options) {
2485
+ if (this.isSummarizerClient) {
2486
+ return this.summarizer.enqueueSummarize(options);
2487
+ }
2488
+ else if (this.summaryManager !== undefined) {
2489
+ return this.summaryManager.enqueueSummarize(options);
2490
+ }
2491
+ else {
2492
+ // If we're not the summarizer, and we don't have a summaryManager, we expect that
2493
+ // generateSummaries is turned off. We are throwing instead of returning a failure here,
2494
+ // because it is a misuse of the API rather than an expected failure.
2495
+ throw new telemetry_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
2240
2496
  }
2241
- // Flush pending batch.
2242
- // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2243
- // to close current batch.
2244
- this.flush();
2245
- return {
2246
- pending: this.pendingStateManager.getLocalState(),
2247
- pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
2248
- };
2249
2497
  }
2250
2498
  /**
2251
2499
  * * Forms a function that will request a Summarizer.
@@ -2268,7 +2516,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2268
2516
  const fluidObject = await (0, runtime_utils_1.requestFluidObject)(loaderRouter, request);
2269
2517
  const summarizer = fluidObject.ISummarizer;
2270
2518
  if (!summarizer) {
2271
- throw new container_utils_1.UsageError("Fluid object does not implement ISummarizer");
2519
+ throw new telemetry_utils_1.UsageError("Fluid object does not implement ISummarizer");
2272
2520
  }
2273
2521
  return summarizer;
2274
2522
  };
@@ -2277,11 +2525,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2277
2525
  // eslint-disable-next-line no-restricted-syntax
2278
2526
  for (const prop in configuration) {
2279
2527
  if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
2280
- throw new container_utils_1.UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
2528
+ throw new telemetry_utils_1.UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
2281
2529
  }
2282
2530
  }
2283
2531
  if (configuration.minIdleTime > configuration.maxIdleTime) {
2284
- throw new container_utils_1.UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
2532
+ throw new telemetry_utils_1.UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
2285
2533
  }
2286
2534
  }
2287
2535
  get groupedBatchingEnabled() {