@fluidframework/container-runtime 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.204906

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 (345) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/api-extractor.json +1 -1
  3. package/api-report/container-runtime.api.md +866 -0
  4. package/dist/blobManager.d.ts +4 -6
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +56 -78
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/connectionTelemetry.d.ts.map +1 -1
  9. package/dist/connectionTelemetry.js +75 -42
  10. package/dist/connectionTelemetry.js.map +1 -1
  11. package/dist/container-runtime-alpha.d.ts +1744 -0
  12. package/dist/container-runtime-beta.d.ts +1744 -0
  13. package/dist/container-runtime-public.d.ts +1744 -0
  14. package/dist/container-runtime-untrimmed.d.ts +1805 -0
  15. package/dist/containerHandleContext.js +3 -3
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +94 -102
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +478 -454
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.js +11 -11
  22. package/dist/dataStore.js.map +1 -1
  23. package/dist/dataStoreContext.d.ts +2 -4
  24. package/dist/dataStoreContext.d.ts.map +1 -1
  25. package/dist/dataStoreContext.js +56 -59
  26. package/dist/dataStoreContext.js.map +1 -1
  27. package/dist/dataStoreRegistry.d.ts +3 -0
  28. package/dist/dataStoreRegistry.d.ts.map +1 -1
  29. package/dist/dataStoreRegistry.js +6 -3
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.d.ts +0 -2
  32. package/dist/dataStores.d.ts.map +1 -1
  33. package/dist/dataStores.js +3 -8
  34. package/dist/dataStores.js.map +1 -1
  35. package/dist/deltaManagerProxyBase.js +4 -4
  36. package/dist/deltaManagerProxyBase.js.map +1 -1
  37. package/dist/deltaManagerSummarizerProxy.js +6 -6
  38. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  39. package/dist/deltaScheduler.js.map +1 -1
  40. package/dist/error.d.ts.map +1 -1
  41. package/dist/error.js.map +1 -1
  42. package/dist/gc/garbageCollection.d.ts +6 -0
  43. package/dist/gc/garbageCollection.d.ts.map +1 -1
  44. package/dist/gc/garbageCollection.js +36 -25
  45. package/dist/gc/garbageCollection.js.map +1 -1
  46. package/dist/gc/gcConfigs.d.ts +1 -0
  47. package/dist/gc/gcConfigs.d.ts.map +1 -1
  48. package/dist/gc/gcConfigs.js +13 -3
  49. package/dist/gc/gcConfigs.js.map +1 -1
  50. package/dist/gc/gcDefinitions.d.ts +48 -28
  51. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  52. package/dist/gc/gcDefinitions.js +10 -7
  53. package/dist/gc/gcDefinitions.js.map +1 -1
  54. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  55. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  56. package/dist/gc/gcTelemetry.d.ts +3 -4
  57. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  58. package/dist/gc/gcTelemetry.js +7 -8
  59. package/dist/gc/gcTelemetry.js.map +1 -1
  60. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  61. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  62. package/dist/gc/index.d.ts +2 -2
  63. package/dist/gc/index.d.ts.map +1 -1
  64. package/dist/gc/index.js +3 -7
  65. package/dist/gc/index.js.map +1 -1
  66. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  67. package/dist/id-compressor/idCompressor.js.map +1 -1
  68. package/dist/id-compressor/identifiers.d.ts +3 -3
  69. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  70. package/dist/id-compressor/utilities.d.ts +3 -0
  71. package/dist/id-compressor/utilities.d.ts.map +1 -1
  72. package/dist/id-compressor/utilities.js +3 -0
  73. package/dist/id-compressor/utilities.js.map +1 -1
  74. package/dist/index.d.ts +5 -3
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +6 -2
  77. package/dist/index.js.map +1 -1
  78. package/dist/messageTypes.d.ts +137 -0
  79. package/dist/messageTypes.d.ts.map +1 -0
  80. package/dist/messageTypes.js +32 -0
  81. package/dist/messageTypes.js.map +1 -0
  82. package/dist/opLifecycle/batchManager.js +6 -6
  83. package/dist/opLifecycle/batchManager.js.map +1 -1
  84. package/dist/opLifecycle/definitions.d.ts +7 -3
  85. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  86. package/dist/opLifecycle/definitions.js.map +1 -1
  87. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  88. package/dist/opLifecycle/opDecompressor.js +0 -4
  89. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  90. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  91. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  92. package/dist/opLifecycle/opSplitter.js +3 -3
  93. package/dist/opLifecycle/opSplitter.js.map +1 -1
  94. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  95. package/dist/opLifecycle/outbox.js +7 -2
  96. package/dist/opLifecycle/outbox.js.map +1 -1
  97. package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  98. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  99. package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
  100. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  101. package/dist/packageVersion.d.ts +1 -1
  102. package/dist/packageVersion.js +1 -1
  103. package/dist/packageVersion.js.map +1 -1
  104. package/dist/pendingStateManager.d.ts +4 -20
  105. package/dist/pendingStateManager.d.ts.map +1 -1
  106. package/dist/pendingStateManager.js +36 -46
  107. package/dist/pendingStateManager.js.map +1 -1
  108. package/dist/scheduleManager.js +6 -2
  109. package/dist/scheduleManager.js.map +1 -1
  110. package/dist/summary/orderedClientElection.d.ts +7 -4
  111. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  112. package/dist/summary/orderedClientElection.js +54 -54
  113. package/dist/summary/orderedClientElection.js.map +1 -1
  114. package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
  115. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  116. package/dist/summary/runWhileConnectedCoordinator.js +7 -6
  117. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  118. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  119. package/dist/summary/runningSummarizer.js +40 -38
  120. package/dist/summary/runningSummarizer.js.map +1 -1
  121. package/dist/summary/summarizer.d.ts +2 -0
  122. package/dist/summary/summarizer.d.ts.map +1 -1
  123. package/dist/summary/summarizer.js +18 -8
  124. package/dist/summary/summarizer.js.map +1 -1
  125. package/dist/summary/summarizerClientElection.js +6 -6
  126. package/dist/summary/summarizerClientElection.js.map +1 -1
  127. package/dist/summary/summarizerHeuristics.js +9 -9
  128. package/dist/summary/summarizerHeuristics.js.map +1 -1
  129. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
  130. package/dist/summary/summarizerNode/summarizerNode.js +8 -8
  131. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  132. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  133. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  134. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  135. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  136. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  137. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  138. package/dist/summary/summarizerTypes.d.ts +107 -22
  139. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  140. package/dist/summary/summarizerTypes.js.map +1 -1
  141. package/dist/summary/summaryCollection.d.ts +18 -2
  142. package/dist/summary/summaryCollection.d.ts.map +1 -1
  143. package/dist/summary/summaryCollection.js +23 -21
  144. package/dist/summary/summaryCollection.js.map +1 -1
  145. package/dist/summary/summaryFormat.d.ts +15 -6
  146. package/dist/summary/summaryFormat.d.ts.map +1 -1
  147. package/dist/summary/summaryFormat.js.map +1 -1
  148. package/dist/summary/summaryGenerator.d.ts +3 -3
  149. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  150. package/dist/summary/summaryGenerator.js.map +1 -1
  151. package/dist/summary/summaryManager.d.ts +2 -2
  152. package/dist/summary/summaryManager.d.ts.map +1 -1
  153. package/dist/summary/summaryManager.js +10 -10
  154. package/dist/summary/summaryManager.js.map +1 -1
  155. package/dist/throttler.js +16 -16
  156. package/dist/throttler.js.map +1 -1
  157. package/dist/tsdoc-metadata.json +1 -1
  158. package/lib/blobManager.d.ts +4 -6
  159. package/lib/blobManager.d.ts.map +1 -1
  160. package/lib/blobManager.js +58 -80
  161. package/lib/blobManager.js.map +1 -1
  162. package/lib/connectionTelemetry.d.ts.map +1 -1
  163. package/lib/connectionTelemetry.js +76 -43
  164. package/lib/connectionTelemetry.js.map +1 -1
  165. package/lib/containerHandleContext.js +3 -3
  166. package/lib/containerHandleContext.js.map +1 -1
  167. package/lib/containerRuntime.d.ts +94 -102
  168. package/lib/containerRuntime.d.ts.map +1 -1
  169. package/lib/containerRuntime.js +437 -418
  170. package/lib/containerRuntime.js.map +1 -1
  171. package/lib/dataStore.js +11 -11
  172. package/lib/dataStore.js.map +1 -1
  173. package/lib/dataStoreContext.d.ts +2 -4
  174. package/lib/dataStoreContext.d.ts.map +1 -1
  175. package/lib/dataStoreContext.js +57 -60
  176. package/lib/dataStoreContext.js.map +1 -1
  177. package/lib/dataStoreRegistry.d.ts +3 -0
  178. package/lib/dataStoreRegistry.d.ts.map +1 -1
  179. package/lib/dataStoreRegistry.js +6 -3
  180. package/lib/dataStoreRegistry.js.map +1 -1
  181. package/lib/dataStores.d.ts +0 -2
  182. package/lib/dataStores.d.ts.map +1 -1
  183. package/lib/dataStores.js +4 -9
  184. package/lib/dataStores.js.map +1 -1
  185. package/lib/deltaManagerProxyBase.js +4 -4
  186. package/lib/deltaManagerProxyBase.js.map +1 -1
  187. package/lib/deltaManagerSummarizerProxy.js +6 -6
  188. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  189. package/lib/deltaScheduler.js.map +1 -1
  190. package/lib/error.d.ts.map +1 -1
  191. package/lib/error.js.map +1 -1
  192. package/lib/gc/garbageCollection.d.ts +6 -0
  193. package/lib/gc/garbageCollection.d.ts.map +1 -1
  194. package/lib/gc/garbageCollection.js +36 -25
  195. package/lib/gc/garbageCollection.js.map +1 -1
  196. package/lib/gc/gcConfigs.d.ts +1 -0
  197. package/lib/gc/gcConfigs.d.ts.map +1 -1
  198. package/lib/gc/gcConfigs.js +15 -5
  199. package/lib/gc/gcConfigs.js.map +1 -1
  200. package/lib/gc/gcDefinitions.d.ts +48 -28
  201. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  202. package/lib/gc/gcDefinitions.js +9 -6
  203. package/lib/gc/gcDefinitions.js.map +1 -1
  204. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  205. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  206. package/lib/gc/gcTelemetry.d.ts +3 -4
  207. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  208. package/lib/gc/gcTelemetry.js +7 -8
  209. package/lib/gc/gcTelemetry.js.map +1 -1
  210. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  211. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  212. package/lib/gc/index.d.ts +2 -2
  213. package/lib/gc/index.d.ts.map +1 -1
  214. package/lib/gc/index.js +2 -2
  215. package/lib/gc/index.js.map +1 -1
  216. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  217. package/lib/id-compressor/idCompressor.js.map +1 -1
  218. package/lib/id-compressor/identifiers.d.ts +3 -3
  219. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  220. package/lib/id-compressor/utilities.d.ts +3 -0
  221. package/lib/id-compressor/utilities.d.ts.map +1 -1
  222. package/lib/id-compressor/utilities.js +3 -0
  223. package/lib/id-compressor/utilities.js.map +1 -1
  224. package/lib/index.d.ts +5 -3
  225. package/lib/index.d.ts.map +1 -1
  226. package/lib/index.js +3 -1
  227. package/lib/index.js.map +1 -1
  228. package/lib/messageTypes.d.ts +137 -0
  229. package/lib/messageTypes.d.ts.map +1 -0
  230. package/lib/messageTypes.js +29 -0
  231. package/lib/messageTypes.js.map +1 -0
  232. package/lib/opLifecycle/batchManager.js +6 -6
  233. package/lib/opLifecycle/batchManager.js.map +1 -1
  234. package/lib/opLifecycle/definitions.d.ts +7 -3
  235. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  236. package/lib/opLifecycle/definitions.js.map +1 -1
  237. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  238. package/lib/opLifecycle/opDecompressor.js +0 -4
  239. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  240. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  241. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  242. package/lib/opLifecycle/opSplitter.js +1 -1
  243. package/lib/opLifecycle/opSplitter.js.map +1 -1
  244. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  245. package/lib/opLifecycle/outbox.js +7 -2
  246. package/lib/opLifecycle/outbox.js.map +1 -1
  247. package/lib/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  248. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  249. package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
  250. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  251. package/lib/packageVersion.d.ts +1 -1
  252. package/lib/packageVersion.js +1 -1
  253. package/lib/packageVersion.js.map +1 -1
  254. package/lib/pendingStateManager.d.ts +4 -20
  255. package/lib/pendingStateManager.d.ts.map +1 -1
  256. package/lib/pendingStateManager.js +35 -45
  257. package/lib/pendingStateManager.js.map +1 -1
  258. package/lib/scheduleManager.js +6 -2
  259. package/lib/scheduleManager.js.map +1 -1
  260. package/lib/summary/orderedClientElection.d.ts +7 -4
  261. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  262. package/lib/summary/orderedClientElection.js +54 -54
  263. package/lib/summary/orderedClientElection.js.map +1 -1
  264. package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
  265. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  266. package/lib/summary/runWhileConnectedCoordinator.js +7 -6
  267. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  268. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  269. package/lib/summary/runningSummarizer.js +40 -38
  270. package/lib/summary/runningSummarizer.js.map +1 -1
  271. package/lib/summary/summarizer.d.ts +2 -0
  272. package/lib/summary/summarizer.d.ts.map +1 -1
  273. package/lib/summary/summarizer.js +19 -9
  274. package/lib/summary/summarizer.js.map +1 -1
  275. package/lib/summary/summarizerClientElection.js +6 -6
  276. package/lib/summary/summarizerClientElection.js.map +1 -1
  277. package/lib/summary/summarizerHeuristics.js +9 -9
  278. package/lib/summary/summarizerHeuristics.js.map +1 -1
  279. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
  280. package/lib/summary/summarizerNode/summarizerNode.js +8 -8
  281. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  282. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  283. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  284. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  285. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  286. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  287. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  288. package/lib/summary/summarizerTypes.d.ts +107 -22
  289. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  290. package/lib/summary/summarizerTypes.js.map +1 -1
  291. package/lib/summary/summaryCollection.d.ts +18 -2
  292. package/lib/summary/summaryCollection.d.ts.map +1 -1
  293. package/lib/summary/summaryCollection.js +23 -21
  294. package/lib/summary/summaryCollection.js.map +1 -1
  295. package/lib/summary/summaryFormat.d.ts +15 -6
  296. package/lib/summary/summaryFormat.d.ts.map +1 -1
  297. package/lib/summary/summaryFormat.js.map +1 -1
  298. package/lib/summary/summaryGenerator.d.ts +3 -3
  299. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  300. package/lib/summary/summaryGenerator.js.map +1 -1
  301. package/lib/summary/summaryManager.d.ts +2 -2
  302. package/lib/summary/summaryManager.d.ts.map +1 -1
  303. package/lib/summary/summaryManager.js +9 -9
  304. package/lib/summary/summaryManager.js.map +1 -1
  305. package/lib/throttler.js +16 -16
  306. package/lib/throttler.js.map +1 -1
  307. package/package.json +32 -29
  308. package/src/blobManager.ts +67 -92
  309. package/src/connectionTelemetry.ts +97 -52
  310. package/src/containerRuntime.ts +351 -351
  311. package/src/dataStore.ts +3 -3
  312. package/src/dataStoreContext.ts +9 -13
  313. package/src/dataStoreRegistry.ts +3 -0
  314. package/src/dataStores.ts +5 -17
  315. package/src/error.ts +4 -1
  316. package/src/gc/garbageCollection.ts +25 -12
  317. package/src/gc/gcConfigs.ts +25 -7
  318. package/src/gc/gcDefinitions.ts +49 -29
  319. package/src/gc/gcSummaryDefinitions.ts +1 -1
  320. package/src/gc/gcTelemetry.ts +8 -8
  321. package/src/gc/index.ts +2 -6
  322. package/src/id-compressor/utilities.ts +3 -0
  323. package/src/index.ts +21 -5
  324. package/src/messageTypes.ts +228 -0
  325. package/src/opLifecycle/README.md +93 -68
  326. package/src/opLifecycle/definitions.ts +5 -1
  327. package/src/opLifecycle/opDecompressor.ts +0 -8
  328. package/src/opLifecycle/opGroupingManager.ts +2 -4
  329. package/src/opLifecycle/opSplitter.ts +2 -2
  330. package/src/opLifecycle/outbox.ts +3 -0
  331. package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
  332. package/src/packageVersion.ts +1 -1
  333. package/src/pendingStateManager.ts +31 -52
  334. package/src/scheduleManager.ts +2 -0
  335. package/src/summary/orderedClientElection.ts +4 -1
  336. package/src/summary/runWhileConnectedCoordinator.ts +5 -1
  337. package/src/summary/runningSummarizer.ts +3 -1
  338. package/src/summary/summarizer.ts +21 -7
  339. package/src/summary/summarizerNode/summarizerNode.ts +1 -1
  340. package/src/summary/summarizerTypes.ts +96 -11
  341. package/src/summary/summaryCollection.ts +19 -1
  342. package/src/summary/summaryFormat.ts +11 -1
  343. package/src/summary/summaryGenerator.ts +3 -3
  344. package/src/summary/summaryManager.ts +2 -2
  345. package/src/gc/gcEarlyAdoption.md +0 -145
@@ -8,9 +8,11 @@ import {
8
8
  FluidObject,
9
9
  IFluidHandle,
10
10
  IFluidHandleContext,
11
+ // eslint-disable-next-line import/no-deprecated
11
12
  IFluidRouter,
12
13
  IRequest,
13
14
  IResponse,
15
+ IProvideFluidHandleContext,
14
16
  } from "@fluidframework/core-interfaces";
15
17
  import {
16
18
  IAudience,
@@ -21,6 +23,7 @@ import {
21
23
  ICriticalContainerError,
22
24
  AttachState,
23
25
  ILoaderOptions,
26
+ ILoader,
24
27
  LoaderHeader,
25
28
  } from "@fluidframework/container-definitions";
26
29
  import {
@@ -88,7 +91,6 @@ import {
88
91
  IIdCompressorCore,
89
92
  IdCreationRange,
90
93
  IdCreationRangeWithStashedState,
91
- IAttachMessage,
92
94
  } from "@fluidframework/runtime-definitions";
93
95
  import {
94
96
  addBlobToSummary,
@@ -98,11 +100,11 @@ import {
98
100
  create404Response,
99
101
  exceptionToResponse,
100
102
  GCDataBuilder,
101
- requestFluidObject,
102
103
  seqFromTree,
103
104
  calculateStats,
104
105
  TelemetryContext,
105
106
  ReadAndParseBlob,
107
+ responseToException,
106
108
  } from "@fluidframework/runtime-utils";
107
109
  import { v4 as uuid } from "uuid";
108
110
  import { ContainerFluidHandleContext } from "./containerHandleContext";
@@ -142,7 +144,6 @@ import {
142
144
  IConnectableRuntime,
143
145
  IGeneratedSummaryStats,
144
146
  ISubmitSummaryOptions,
145
- ISummarizer,
146
147
  ISummarizerInternalsProvider,
147
148
  ISummarizerRuntime,
148
149
  IRefreshSummaryAckOptions,
@@ -155,6 +156,7 @@ import {
155
156
  EnqueueSummarizeResult,
156
157
  ISummarizerEvents,
157
158
  IBaseSummarizeResult,
159
+ ISummarizer,
158
160
  } from "./summary";
159
161
  import { formExponentialFn, Throttler } from "./throttler";
160
162
  import {
@@ -164,7 +166,6 @@ import {
164
166
  IGarbageCollector,
165
167
  IGCRuntimeOptions,
166
168
  IGCStats,
167
- shouldAllowGcTombstoneEnforcement,
168
169
  trimLeadingAndTrailingSlashes,
169
170
  } from "./gc";
170
171
  import { channelToDataStore, IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
@@ -184,92 +185,45 @@ import {
184
185
  } from "./opLifecycle";
185
186
  import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
186
187
  import { IBatchMetadata } from "./metadata";
187
-
188
- export enum ContainerMessageType {
189
- // An op to be delivered to store
190
- FluidDataStoreOp = "component",
191
-
192
- // Creates a new store
193
- Attach = "attach",
194
-
195
- // Chunked operation.
196
- ChunkedOp = "chunkedOp",
197
-
198
- // Signifies that a blob has been attached and should not be garbage collected by storage
199
- BlobAttach = "blobAttach",
200
-
201
- // Ties our new clientId to our old one on reconnect
202
- Rejoin = "rejoin",
203
-
204
- // Sets the alias of a root data store
205
- Alias = "alias",
206
-
207
- /**
208
- * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
209
- * the last allocation op was sent.
210
- * See the [IdCompressor README](./id-compressor/README.md) for more details.
211
- */
212
- IdAllocation = "idAllocation",
213
- }
214
-
215
- /**
216
- * How should an older client handle an unrecognized remote op type?
217
- *
218
- * @internal
219
- */
220
- export type CompatModeBehavior =
221
- /** Ignore the op. It won't be persisted if this client summarizes */
222
- | "Ignore"
223
- /** Fail processing immediately. (The container will close) */
224
- | "FailToProcess";
225
-
226
- /**
227
- * All the info an older client would need to know how to handle an unrecognized remote op type
228
- *
229
- * @internal
230
- */
231
- export interface IContainerRuntimeMessageCompatDetails {
232
- /** How should an older client handle an unrecognized remote op type? */
233
- behavior: CompatModeBehavior;
234
- }
188
+ import {
189
+ ContainerMessageType,
190
+ type InboundSequencedContainerRuntimeMessage,
191
+ type InboundSequencedContainerRuntimeMessageOrSystemMessage,
192
+ type ContainerRuntimeIdAllocationMessage,
193
+ type LocalContainerRuntimeIdAllocationMessage,
194
+ type LocalContainerRuntimeMessage,
195
+ type OutboundContainerRuntimeMessage,
196
+ type UnknownContainerRuntimeMessage,
197
+ } from "./messageTypes";
235
198
 
236
199
  /**
237
200
  * Utility to implement compat behaviors given an unknown message type
238
201
  * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
239
202
  *
240
- * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
203
+ * @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
241
204
  * handled before calling this function (e.g. in a switch statement).
242
205
  * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
243
206
  */
244
207
  function compatBehaviorAllowsMessageType(
245
- _unknownContainerRuntimeMessageType: never,
208
+ _unknownContainerRuntimeMessageType: UnknownContainerRuntimeMessage["type"],
246
209
  compatBehavior: "Ignore" | "FailToProcess" | undefined,
247
210
  ): boolean {
248
211
  // undefined defaults to same behavior as "FailToProcess"
249
212
  return compatBehavior === "Ignore";
250
213
  }
251
214
 
252
- /**
253
- * The unpacked runtime message / details to be handled or dispatched by the ContainerRuntime
254
- *
255
- * IMPORTANT: when creating one to be serialized, set the properties in the order they appear here.
256
- * This way stringified values can be compared.
257
- */
258
- export interface ContainerRuntimeMessage {
259
- /** Type of the op, within the ContainerRuntime's domain */
260
- type: ContainerMessageType;
261
- /** Domain-specific contents, interpreted according to the type */
262
- contents: any;
263
- /** Info describing how to handle this op in case the type is unrecognized (default: fail to process) */
264
- compatDetails?: IContainerRuntimeMessageCompatDetails;
215
+ function prepareLocalContainerRuntimeIdAllocationMessageForTransit(
216
+ message: LocalContainerRuntimeIdAllocationMessage | ContainerRuntimeIdAllocationMessage,
217
+ ): asserts message is ContainerRuntimeIdAllocationMessage {
218
+ // Remove the stashedState from the op if it's a stashed op
219
+ if ("stashedState" in message.contents) {
220
+ delete message.contents.stashedState;
221
+ }
265
222
  }
266
223
 
267
224
  /**
268
- * An unpacked ISequencedDocumentMessage with the inner ContainerRuntimeMessage type/contents/etc
269
- * promoted up to the outer object
225
+ * @public
270
226
  */
271
- export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
272
-
273
227
  export interface ISummaryBaseConfiguration {
274
228
  /**
275
229
  * Delay before first attempt to spawn summarizing container.
@@ -289,6 +243,9 @@ export interface ISummaryBaseConfiguration {
289
243
  maxOpsSinceLastSummary: number;
290
244
  }
291
245
 
246
+ /**
247
+ * @public
248
+ */
292
249
  export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfiguration {
293
250
  state: "enabled";
294
251
  /**
@@ -349,19 +306,31 @@ export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfigurati
349
306
  nonRuntimeHeuristicThreshold?: number;
350
307
  }
351
308
 
309
+ /**
310
+ * @public
311
+ */
352
312
  export interface ISummaryConfigurationDisableSummarizer {
353
313
  state: "disabled";
354
314
  }
355
315
 
316
+ /**
317
+ * @public
318
+ */
356
319
  export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConfiguration {
357
320
  state: "disableHeuristics";
358
321
  }
359
322
 
323
+ /**
324
+ * @public
325
+ */
360
326
  export type ISummaryConfiguration =
361
327
  | ISummaryConfigurationDisableSummarizer
362
328
  | ISummaryConfigurationDisableHeuristics
363
329
  | ISummaryConfigurationHeuristics;
364
330
 
331
+ /**
332
+ * @public
333
+ */
365
334
  export const DefaultSummaryConfiguration: ISummaryConfiguration = {
366
335
  state: "enabled",
367
336
 
@@ -388,6 +357,9 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
388
357
  nonRuntimeHeuristicThreshold: 20,
389
358
  };
390
359
 
360
+ /**
361
+ * @public
362
+ */
391
363
  export interface ISummaryRuntimeOptions {
392
364
  /** Override summary configurations set by the server. */
393
365
  summaryConfigOverrides?: ISummaryConfiguration;
@@ -403,22 +375,25 @@ export interface ISummaryRuntimeOptions {
403
375
 
404
376
  /**
405
377
  * Options for op compression.
406
- * @experimental - Not ready for use
378
+ * @public
407
379
  */
408
380
  export interface ICompressionRuntimeOptions {
409
381
  /**
410
- * The minimum size the batch's payload must exceed before the batch's contents will be compressed.
382
+ * The value the batch's content size must exceed for the batch to be compressed.
383
+ * By default the value is 600 * 1024 = 614400 bytes. If the value is set to `Infinity`, compression will be disabled.
411
384
  */
412
385
  readonly minimumBatchSizeInBytes: number;
413
386
 
414
387
  /**
415
388
  * The compression algorithm that will be used to compress the op.
389
+ * By default the value is `lz4` which is the only compression algorithm currently supported.
416
390
  */
417
391
  readonly compressionAlgorithm: CompressionAlgorithms;
418
392
  }
419
393
 
420
394
  /**
421
395
  * Options for container runtime.
396
+ * @public
422
397
  */
423
398
  export interface IContainerRuntimeOptions {
424
399
  readonly summaryOptions?: ISummaryRuntimeOptions;
@@ -440,8 +415,7 @@ export interface IContainerRuntimeOptions {
440
415
  */
441
416
  readonly flushMode?: FlushMode;
442
417
  /**
443
- * Enables the runtime to compress ops. Compression is disabled when undefined.
444
- * @experimental Not ready for use.
418
+ * Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}.
445
419
  */
446
420
  readonly compressionOptions?: ICompressionRuntimeOptions;
447
421
  /**
@@ -458,12 +432,15 @@ export interface IContainerRuntimeOptions {
458
432
  /**
459
433
  * If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
460
434
  * how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
461
- * batch size exceeds this value, it will be chunked into smaller ops of this size.
435
+ * batch content size exceeds this value, it will be chunked into smaller ops of this exact size.
462
436
  *
463
- * If unspecified, if a batch exceeds `maxBatchSizeInBytes` after compression, the container will close with an instance
464
- * of `GenericError` with the `BatchTooLarge` message.
437
+ * This value is a trade-off between having many small chunks vs fewer larger chunks and by default, the runtime is configured to use
438
+ * 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link IContainerRuntimeOptions.maxBatchSizeInBytes}
439
+ * regardless of the overhead of an individual op.
465
440
  *
466
- * @experimental Not ready for use.
441
+ * Any value of `chunkSizeInBytes` exceeding {@link IContainerRuntimeOptions.maxBatchSizeInBytes} will disable this feature, therefore if a compressed batch's content
442
+ * size exceeds {@link IContainerRuntimeOptions.maxBatchSizeInBytes} after compression, the container will close with an instance of `GenericError` with
443
+ * the `BatchTooLarge` message.
467
444
  */
468
445
  readonly chunkSizeInBytes?: number;
469
446
 
@@ -498,6 +475,7 @@ export interface IContainerRuntimeOptions {
498
475
 
499
476
  /**
500
477
  * Accepted header keys for requests coming to the runtime.
478
+ * @public
501
479
  */
502
480
  export enum RuntimeHeaders {
503
481
  /** True to wait for a data store to be created and loaded before returning it. */
@@ -506,14 +484,25 @@ export enum RuntimeHeaders {
506
484
  viaHandle = "viaHandle",
507
485
  }
508
486
 
509
- /** True if a tombstoned object should be returned without erroring */
487
+ /** True if a tombstoned object should be returned without erroring
488
+ * @public
489
+ */
510
490
  export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
511
- /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
491
+ /**
492
+ * [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
493
+ * @public
494
+ */
512
495
  export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
513
496
 
514
- /** Tombstone error responses will have this header set to true */
497
+ /**
498
+ * Tombstone error responses will have this header set to true
499
+ * @public
500
+ */
515
501
  export const TombstoneResponseHeaderKey = "isTombstoned";
516
- /** Inactive error responses will have this header set to true */
502
+ /**
503
+ * Inactive error responses will have this header set to true
504
+ * @public
505
+ */
517
506
  export const InactiveResponseHeaderKey = "isInactive";
518
507
 
519
508
  /**
@@ -534,6 +523,7 @@ export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
534
523
 
535
524
  /**
536
525
  * Available compression algorithms for op compression.
526
+ * @public
537
527
  */
538
528
  export enum CompressionAlgorithms {
539
529
  lz4 = "lz4",
@@ -597,7 +587,8 @@ export const defaultPendingOpsRetryDelayMs = 1000;
597
587
  const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
598
588
 
599
589
  /**
600
- * @deprecated - use ContainerRuntimeMessage instead
590
+ * @deprecated use ContainerRuntimeMessageType instead
591
+ * @public
601
592
  */
602
593
  export enum RuntimeMessage {
603
594
  FluidDataStoreOp = "component",
@@ -610,7 +601,8 @@ export enum RuntimeMessage {
610
601
  }
611
602
 
612
603
  /**
613
- * @deprecated - please use version in driver-utils
604
+ * @deprecated please use version in driver-utils
605
+ * @public
614
606
  */
615
607
  export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
616
608
  return (Object.values(RuntimeMessage) as string[]).includes(message.type);
@@ -620,6 +612,7 @@ export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
620
612
  * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
621
613
  * special-case for document dirty state. Ultimately we should have no special-cases from the
622
614
  * ContainerRuntime's perspective.
615
+ * @public
623
616
  */
624
617
  export const agentSchedulerId = "_scheduler";
625
618
 
@@ -660,23 +653,94 @@ export const makeLegacySendBatchFn =
660
653
  deltaManager.flush();
661
654
  };
662
655
 
656
+ /** Helper type for type constraints passed through several functions.
657
+ * message - The unpacked message. Likely a TypedContainerRuntimeMessage, but could also be a system op
658
+ * modernRuntimeMessage - Does this appear like a current TypedContainerRuntimeMessage?
659
+ * local - Did this client send the op?
660
+ */
661
+ type MessageWithContext =
662
+ | {
663
+ message: InboundSequencedContainerRuntimeMessage;
664
+ modernRuntimeMessage: true;
665
+ local: boolean;
666
+ }
667
+ | {
668
+ message: InboundSequencedContainerRuntimeMessageOrSystemMessage;
669
+ modernRuntimeMessage: false;
670
+ local: boolean;
671
+ };
672
+
673
+ const summarizerRequestUrl = "_summarizer";
674
+
675
+ /**
676
+ * Create and retrieve the summmarizer
677
+ */
678
+ async function createSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
679
+ const request: IRequest = {
680
+ headers: {
681
+ [LoaderHeader.cache]: false,
682
+ [LoaderHeader.clientDetails]: {
683
+ capabilities: { interactive: false },
684
+ type: summarizerClientType,
685
+ },
686
+ [DriverHeader.summarizingClient]: true,
687
+ [LoaderHeader.reconnect]: false,
688
+ },
689
+ url,
690
+ };
691
+
692
+ const resolvedContainer = await loader.resolve(request);
693
+ let fluidObject: FluidObject<ISummarizer> | undefined;
694
+
695
+ // Older containers may not have the "getEntryPoint" API
696
+ // ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
697
+ if (resolvedContainer.getEntryPoint !== undefined) {
698
+ fluidObject = await resolvedContainer.getEntryPoint();
699
+ } else {
700
+ const response = await resolvedContainer.request({ url: `/${summarizerRequestUrl}` });
701
+ if (response.status !== 200 || response.mimeType !== "fluid/object") {
702
+ throw responseToException(response, request);
703
+ }
704
+ fluidObject = response.value;
705
+ }
706
+
707
+ if (fluidObject?.ISummarizer === undefined) {
708
+ throw new UsageError("Fluid object does not implement ISummarizer");
709
+ }
710
+ return fluidObject.ISummarizer;
711
+ }
712
+
713
+ /**
714
+ * This function is not supported publicly and exists for e2e testing
715
+ * @internal
716
+ */
717
+ export async function TEST_requestSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
718
+ return createSummarizer(loader, url);
719
+ }
720
+
663
721
  /**
664
722
  * Represents the runtime of the container. Contains helper functions/state of the container.
665
723
  * It will define the store level mappings.
724
+ * @public
666
725
  */
667
726
  export class ContainerRuntime
668
727
  extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
669
- implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
728
+ implements
729
+ IContainerRuntime,
730
+ IRuntime,
731
+ ISummarizerRuntime,
732
+ ISummarizerInternalsProvider,
733
+ IProvideFluidHandleContext
670
734
  {
671
735
  /**
672
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
736
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
673
737
  */
674
738
  public get IFluidRouter() {
675
739
  return this;
676
740
  }
677
741
 
678
742
  /**
679
- * @deprecated - use loadRuntime instead.
743
+ * @deprecated use loadRuntime instead.
680
744
  * Load the stores from a snapshot and returns the runtime.
681
745
  * @param context - Context of the container.
682
746
  * @param registryEntries - Mapping to the stores.
@@ -703,10 +767,15 @@ export class ContainerRuntime
703
767
  context,
704
768
  registryEntries,
705
769
  existing: existingFlag,
706
- requestHandler,
707
770
  runtimeOptions,
708
771
  containerScope,
709
772
  containerRuntimeCtor,
773
+ requestHandler,
774
+ provideEntryPoint: () => {
775
+ throw new UsageError(
776
+ "ContainerRuntime.load is deprecated and should no longer be used",
777
+ );
778
+ },
710
779
  });
711
780
  }
712
781
 
@@ -722,7 +791,7 @@ export class ContainerRuntime
722
791
  * - containerScope - runtime services provided with context
723
792
  * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
724
793
  * This allows mixin classes to leverage this method to define their own async initializer.
725
- * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
794
+ * - provideEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
726
795
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
727
796
  */
728
797
  public static async loadRuntime(params: {
@@ -732,30 +801,21 @@ export class ContainerRuntime
732
801
  runtimeOptions?: IContainerRuntimeOptions;
733
802
  containerScope?: FluidObject;
734
803
  containerRuntimeCtor?: typeof ContainerRuntime;
804
+ /** @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md */
735
805
  requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
736
- initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
806
+ provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
737
807
  }): Promise<ContainerRuntime> {
738
808
  const {
739
809
  context,
740
810
  registryEntries,
741
811
  existing,
742
812
  requestHandler,
813
+ provideEntryPoint,
743
814
  runtimeOptions = {},
744
815
  containerScope = {},
745
816
  containerRuntimeCtor = ContainerRuntime,
746
817
  } = params;
747
818
 
748
- const initializeEntryPoint =
749
- params.initializeEntryPoint ??
750
- (async (containerRuntime: IContainerRuntime) => ({
751
- get IFluidRouter() {
752
- return this;
753
- },
754
- async request(req) {
755
- return containerRuntime.request(req);
756
- },
757
- }));
758
-
759
819
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
760
820
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
761
821
  const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
@@ -884,15 +944,14 @@ export class ContainerRuntime
884
944
  blobManagerSnapshot,
885
945
  context.storage,
886
946
  idCompressor,
947
+ provideEntryPoint,
887
948
  requestHandler,
888
949
  undefined, // summaryConfiguration
889
- initializeEntryPoint,
890
950
  );
891
951
 
892
- await runtime.blobManager.processStashedChanges();
893
- // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
894
- // at 1, so we won't see a replayed saved op with a sequence number of 0.
895
- await runtime.pendingStateManager.applyStashedOpsAt(0);
952
+ // Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
953
+ // or zero. This must be done before Container replays saved ops.
954
+ await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
896
955
 
897
956
  // Initialize the base state of the runtime before it's returned.
898
957
  await runtime.initializeBaseState();
@@ -913,17 +972,6 @@ export class ContainerRuntime
913
972
  return this._storage;
914
973
  }
915
974
 
916
- /** @deprecated - The functionality is no longer exposed publicly */
917
- public get reSubmitFn() {
918
- return (
919
- type: ContainerMessageType,
920
- contents: any,
921
- localOpMetadata: unknown,
922
- opMetadata: Record<string, unknown> | undefined,
923
- ) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
924
- // Note: compatDetails is not included in this deprecated API
925
- }
926
-
927
975
  private readonly submitFn: (
928
976
  type: MessageType,
929
977
  contents: any,
@@ -1132,10 +1180,20 @@ export class ContainerRuntime
1132
1180
  */
1133
1181
  private nextSummaryNumber: number;
1134
1182
 
1135
- /**
1136
- * If false, loading or using a Tombstoned object should merely log, not fail
1137
- */
1138
- public readonly gcTombstoneEnforcementAllowed: boolean;
1183
+ /** If false, loading or using a Tombstoned object should merely log, not fail */
1184
+ public get gcTombstoneEnforcementAllowed(): boolean {
1185
+ return this.garbageCollector.tombstoneEnforcementAllowed;
1186
+ }
1187
+
1188
+ /** If true, throw an error when a tombstone data store is retrieved */
1189
+ public get gcThrowOnTombstoneLoad(): boolean {
1190
+ return this.garbageCollector.throwOnTombstoneLoad;
1191
+ }
1192
+
1193
+ /** If true, throw an error when a tombstone data store is used. */
1194
+ public get gcThrowOnTombstoneUsage(): boolean {
1195
+ return this.garbageCollector.throwOnTombstoneUsage;
1196
+ }
1139
1197
 
1140
1198
  /**
1141
1199
  * GUID to identify a document in telemetry
@@ -1175,6 +1233,7 @@ export class ContainerRuntime
1175
1233
  blobManagerSnapshot: IBlobManagerLoadInfo,
1176
1234
  private readonly _storage: IDocumentStorageService,
1177
1235
  idCompressor: (IIdCompressor & IIdCompressorCore) | undefined,
1236
+ provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1178
1237
  private readonly requestHandler?: (
1179
1238
  request: IRequest,
1180
1239
  runtime: IContainerRuntime,
@@ -1185,7 +1244,6 @@ export class ContainerRuntime
1185
1244
  // the runtime configuration overrides
1186
1245
  ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
1187
1246
  },
1188
- initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1189
1247
  ) {
1190
1248
  super();
1191
1249
 
@@ -1282,11 +1340,6 @@ export class ContainerRuntime
1282
1340
  // Later updates come through calls to setConnectionState.
1283
1341
  this._connected = connected;
1284
1342
 
1285
- this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
1286
- metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */,
1287
- this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */,
1288
- );
1289
-
1290
1343
  this.mc.logger.sendTelemetryEvent({
1291
1344
  eventName: "GCFeatureMatrix",
1292
1345
  metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
@@ -1619,7 +1672,7 @@ export class ContainerRuntime
1619
1672
  this, // IConnectedState
1620
1673
  this.summaryCollection,
1621
1674
  this.logger,
1622
- this.formRequestSummarizerFn(loader),
1675
+ this.formCreateSummarizerFn(loader),
1623
1676
  new Throttler(
1624
1677
  60 * 1000, // 60 sec delay window
1625
1678
  30 * 1000, // 30 sec max delay
@@ -1638,35 +1691,6 @@ export class ContainerRuntime
1638
1691
  }
1639
1692
  }
1640
1693
 
1641
- this.deltaManager.on("readonly", (readonly: boolean) => {
1642
- // we accumulate ops while being in read-only state.
1643
- // once user gets write permissions and we have active connection, flush all pending ops.
1644
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1645
- assert(
1646
- readonly === this.innerDeltaManager.readOnlyInfo.readonly,
1647
- 0x124 /* "inconsistent readonly property/event state" */,
1648
- );
1649
-
1650
- // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
1651
- // when we either never send an op, or attempted to send it but we know for sure it was not
1652
- // sequenced by server and will never be sequenced (i.e. was lost)
1653
- // For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
1654
- // ops that made it from previous connection, before switching clientId and raising "connected" event
1655
- // But with read-only permissions, if we transition between read-only and r/w states while on same
1656
- // connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
1657
- // being in read-only state.
1658
- // For that reason, we support getting to read-only state only when disconnected. This ensures that we
1659
- // can rely on same safety mechanism and resend ops only when we establish new connection.
1660
- // This is applicable for read-only permissions (event is raised before connection is properly registered),
1661
- // but it's an extra requirement for Container.forceReadonly() API
1662
- assert(
1663
- !readonly || !this.connected,
1664
- 0x125 /* "Unsafe to transition to read-only state!" */,
1665
- );
1666
-
1667
- this.replayPendingStates();
1668
- });
1669
-
1670
1694
  // logging hardware telemetry
1671
1695
  logger.sendTelemetryEvent({
1672
1696
  eventName: "DeviceSpec",
@@ -1706,7 +1730,7 @@ export class ContainerRuntime
1706
1730
  );
1707
1731
  return this._summarizer;
1708
1732
  }
1709
- return initializeEntryPoint?.(this);
1733
+ return provideEntryPoint(this);
1710
1734
  });
1711
1735
  }
1712
1736
 
@@ -1747,14 +1771,14 @@ export class ContainerRuntime
1747
1771
  /**
1748
1772
  * Notifies this object about the request made to the container.
1749
1773
  * @param request - Request made to the handler.
1750
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
1774
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
1751
1775
  */
1752
1776
  public async request(request: IRequest): Promise<IResponse> {
1753
1777
  try {
1754
1778
  const parser = RequestParser.create(request);
1755
1779
  const id = parser.pathParts[0];
1756
1780
 
1757
- if (id === "_summarizer" && parser.pathParts.length === 1) {
1781
+ if (id === summarizerRequestUrl && parser.pathParts.length === 1) {
1758
1782
  if (this._summarizer !== undefined) {
1759
1783
  return {
1760
1784
  status: 200,
@@ -1765,6 +1789,7 @@ export class ContainerRuntime
1765
1789
  return create404Response(request);
1766
1790
  }
1767
1791
  if (this.requestHandler !== undefined) {
1792
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1768
1793
  return this.requestHandler(parser, this);
1769
1794
  }
1770
1795
 
@@ -1784,6 +1809,7 @@ export class ContainerRuntime
1784
1809
  const id = requestParser.pathParts[0];
1785
1810
 
1786
1811
  if (id === "_channels") {
1812
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1787
1813
  return this.resolveHandle(requestParser.createSubRequest(1));
1788
1814
  }
1789
1815
 
@@ -1797,7 +1823,10 @@ export class ContainerRuntime
1797
1823
  }
1798
1824
  : create404Response(request);
1799
1825
  } else if (requestParser.pathParts.length > 0) {
1800
- const dataStore = await this.getDataStoreFromRequest(id, request);
1826
+ // Differentiate between requesting the dataStore directly, or one of its children
1827
+ const requestForChild = !requestParser.isLeaf(1);
1828
+ const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
1829
+
1801
1830
  const subRequest = requestParser.createSubRequest(1);
1802
1831
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
1803
1832
  // unintentionally modifying the url if that changes.
@@ -1805,6 +1834,7 @@ export class ContainerRuntime
1805
1834
  subRequest.url.startsWith("/"),
1806
1835
  0x126 /* "Expected createSubRequest url to include a leading slash" */,
1807
1836
  );
1837
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1808
1838
  return dataStore.request(subRequest);
1809
1839
  }
1810
1840
 
@@ -1817,16 +1847,20 @@ export class ContainerRuntime
1817
1847
  /**
1818
1848
  * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
1819
1849
  */
1820
- public async getEntryPoint?(): Promise<FluidObject | undefined> {
1850
+ public async getEntryPoint(): Promise<FluidObject> {
1821
1851
  return this.entryPoint;
1822
1852
  }
1823
- private readonly entryPoint: LazyPromise<FluidObject | undefined>;
1853
+ private readonly entryPoint: LazyPromise<FluidObject>;
1824
1854
 
1825
1855
  private internalId(maybeAlias: string): string {
1826
1856
  return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
1827
1857
  }
1828
1858
 
1829
- private async getDataStoreFromRequest(id: string, request: IRequest): Promise<IFluidRouter> {
1859
+ private async getDataStoreFromRequest(
1860
+ id: string,
1861
+ request: IRequest,
1862
+ requestForChild: boolean,
1863
+ ): Promise<IFluidDataStoreChannel> {
1830
1864
  const headerData: RuntimeHeaderData = {};
1831
1865
  if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
1832
1866
  headerData.wait = request.headers[RuntimeHeaders.wait];
@@ -1838,6 +1872,11 @@ export class ContainerRuntime
1838
1872
  headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
1839
1873
  }
1840
1874
 
1875
+ // We allow Tombstone requests for sub-DataStore objects
1876
+ if (requestForChild) {
1877
+ headerData.allowTombstone = true;
1878
+ }
1879
+
1841
1880
  await this.dataStores.waitIfPendingAlias(id);
1842
1881
  const internalId = this.internalId(id);
1843
1882
  const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
@@ -2015,28 +2054,28 @@ export class ContainerRuntime
2015
2054
  * Parse an op's type and actual content from given serialized content
2016
2055
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
2017
2056
  */
2018
- private parseOpContent(serializedContent?: string): ContainerRuntimeMessage {
2019
- assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
2020
- const { type, contents, compatDetails }: ContainerRuntimeMessage =
2021
- JSON.parse(serializedContent);
2022
- assert(type !== undefined, 0x6d6 /* incorrect op content format */);
2023
- return { type, contents, compatDetails };
2057
+ // TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
2058
+ private parseLocalOpContent(serializedContents?: string): LocalContainerRuntimeMessage {
2059
+ assert(serializedContents !== undefined, 0x6d5 /* content must be defined */);
2060
+ const message: LocalContainerRuntimeMessage = JSON.parse(serializedContents);
2061
+ assert(message.type !== undefined, 0x6d6 /* incorrect op content format */);
2062
+ return message;
2024
2063
  }
2025
2064
 
2026
- private async applyStashedOp(op: string): Promise<unknown> {
2065
+ private async applyStashedOp(serializedOpContent: string): Promise<unknown> {
2027
2066
  // Need to parse from string for back-compat
2028
- const { type, contents, compatDetails } = this.parseOpContent(op);
2029
- switch (type) {
2067
+ const opContents = this.parseLocalOpContent(serializedOpContent);
2068
+ switch (opContents.type) {
2030
2069
  case ContainerMessageType.FluidDataStoreOp:
2031
- return this.dataStores.applyStashedOp(contents as IEnvelope);
2070
+ return this.dataStores.applyStashedOp(opContents.contents);
2032
2071
  case ContainerMessageType.Attach:
2033
- return this.dataStores.applyStashedAttachOp(contents as IAttachMessage);
2072
+ return this.dataStores.applyStashedAttachOp(opContents.contents);
2034
2073
  case ContainerMessageType.IdAllocation:
2035
2074
  assert(
2036
2075
  this.idCompressor !== undefined,
2037
2076
  0x67b /* IdCompressor should be defined if enabled */,
2038
2077
  );
2039
- return this.applyStashedIdAllocationOp(contents as IdCreationRangeWithStashedState);
2078
+ return this.applyStashedIdAllocationOp(opContents.contents);
2040
2079
  case ContainerMessageType.Alias:
2041
2080
  case ContainerMessageType.BlobAttach:
2042
2081
  return;
@@ -2048,15 +2087,15 @@ export class ContainerRuntime
2048
2087
  // This should be extremely rare for stashed ops.
2049
2088
  // It would require a newer runtime stashing ops and then an older one applying them,
2050
2089
  // e.g. if an app rolled back its container version
2051
- const compatBehavior = compatDetails?.behavior;
2052
- if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
2090
+ const compatBehavior = opContents.compatDetails?.behavior;
2091
+ if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
2053
2092
  const error = DataProcessingError.create(
2054
2093
  "Stashed runtime message of unknown type",
2055
2094
  "applyStashedOp",
2056
2095
  undefined /* sequencedMessage */,
2057
2096
  {
2058
2097
  messageDetails: JSON.stringify({
2059
- type,
2098
+ type: opContents.type,
2060
2099
  compatBehavior,
2061
2100
  }),
2062
2101
  },
@@ -2078,6 +2117,30 @@ export class ContainerRuntime
2078
2117
  return;
2079
2118
  }
2080
2119
 
2120
+ // If there are stashed blobs in the pending state, we need to delay
2121
+ // propagation of the "connected" event until we have uploaded them to
2122
+ // ensure we don't submit ops referencing a blob that has not been uploaded
2123
+ const connecting = connected && !this._connected;
2124
+ if (connecting && this.blobManager.hasPendingStashedBlobs()) {
2125
+ assert(
2126
+ !this.delayConnectClientId,
2127
+ 0x791 /* Connect event delay must be canceled before subsequent connect event */,
2128
+ );
2129
+ assert(!!clientId, 0x792 /* Must have clientId when connecting */);
2130
+ this.delayConnectClientId = clientId;
2131
+ this.blobManager.processStashedChanges().then(
2132
+ () => {
2133
+ // make sure we didn't reconnect before the promise resolved
2134
+ if (this.delayConnectClientId === clientId && !this.disposed) {
2135
+ this.delayConnectClientId = undefined;
2136
+ this.setConnectionStateCore(connected, clientId);
2137
+ }
2138
+ },
2139
+ (error) => this.closeFn(error),
2140
+ );
2141
+ return;
2142
+ }
2143
+
2081
2144
  this.setConnectionStateCore(connected, clientId);
2082
2145
  }
2083
2146
 
@@ -2156,9 +2219,25 @@ export class ContainerRuntime
2156
2219
  const modernRuntimeMessage = messageArg.type === MessageType.Operation;
2157
2220
 
2158
2221
  // Do shallow copy of message, as the processing flow will modify it.
2222
+ // There might be multiple container instances receiving the same message.
2223
+ // We do not need to make a deep copy. Each layer will just replace message.contents itself,
2224
+ // but will not modify the contents object (likely it will replace it on the message).
2159
2225
  const messageCopy = { ...messageArg };
2160
2226
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
2161
- this.processCore(message, local, modernRuntimeMessage);
2227
+ if (modernRuntimeMessage) {
2228
+ this.processCore({
2229
+ // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
2230
+ // There is nothing really ensuring that anytime original message.type is Operation that
2231
+ // the result messages will be so. In the end modern bool being true only directs to
2232
+ // throw error if ultimately unrecognized without compat details saying otherwise.
2233
+ message: message as InboundSequencedContainerRuntimeMessage,
2234
+ local,
2235
+ modernRuntimeMessage,
2236
+ });
2237
+ } else {
2238
+ // Unrecognized message will be ignored.
2239
+ this.processCore({ message, local, modernRuntimeMessage });
2240
+ }
2162
2241
  }
2163
2242
  }
2164
2243
 
@@ -2166,15 +2245,9 @@ export class ContainerRuntime
2166
2245
 
2167
2246
  /**
2168
2247
  * Direct the message to the correct subsystem for processing, and implement other side effects
2169
- * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
2170
- * @param local - Did this client send the op?
2171
- * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
2172
- */
2173
- private processCore(
2174
- message: ISequencedDocumentMessage | SequencedContainerRuntimeMessage,
2175
- local: boolean,
2176
- modernRuntimeMessage: boolean,
2177
- ) {
2248
+ */
2249
+ private processCore(messageWithContext: MessageWithContext) {
2250
+ const { message, local } = messageWithContext;
2178
2251
  // Surround the actual processing of the operation with messages to the schedule manager indicating
2179
2252
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
2180
2253
  // messages once a batch has been fully processed.
@@ -2184,9 +2257,13 @@ export class ContainerRuntime
2184
2257
 
2185
2258
  try {
2186
2259
  let localOpMetadata: unknown;
2187
- if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
2260
+ if (
2261
+ local &&
2262
+ messageWithContext.modernRuntimeMessage &&
2263
+ message.type !== ContainerMessageType.ChunkedOp
2264
+ ) {
2188
2265
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
2189
- message as SequencedContainerRuntimeMessage,
2266
+ messageWithContext.message,
2190
2267
  );
2191
2268
  }
2192
2269
 
@@ -2196,14 +2273,9 @@ export class ContainerRuntime
2196
2273
  this.updateDocumentDirtyState(false);
2197
2274
  }
2198
2275
 
2199
- this.validateAndProcessRuntimeMessage(
2200
- message,
2201
- localOpMetadata,
2202
- local,
2203
- modernRuntimeMessage,
2204
- );
2276
+ this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
2205
2277
 
2206
- this.emit("op", message, modernRuntimeMessage);
2278
+ this.emit("op", message, messageWithContext.modernRuntimeMessage);
2207
2279
 
2208
2280
  this.scheduleManager.afterOpProcessing(undefined, message);
2209
2281
 
@@ -2219,39 +2291,43 @@ export class ContainerRuntime
2219
2291
  }
2220
2292
  }
2221
2293
  /**
2222
- * Assuming the given message is also a ContainerRuntimeMessage,
2294
+ * Assuming the given message is also a TypedContainerRuntimeMessage,
2223
2295
  * checks its type and dispatches the message to the appropriate handler in the runtime.
2224
- * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
2296
+ * Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
2225
2297
  */
2226
2298
  private validateAndProcessRuntimeMessage(
2227
- message: ISequencedDocumentMessage,
2299
+ messageWithContext: MessageWithContext,
2228
2300
  localOpMetadata: unknown,
2229
- local: boolean,
2230
- expectRuntimeMessageType: boolean,
2231
- ): asserts message is SequencedContainerRuntimeMessage {
2232
- // Optimistically extract ContainerRuntimeMessage-specific props from the message
2233
- const { type: maybeContainerMessageType, compatDetails } =
2234
- message as ContainerRuntimeMessage;
2235
-
2236
- switch (maybeContainerMessageType) {
2301
+ ): void {
2302
+ // TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
2303
+ const { local } = messageWithContext;
2304
+ switch (messageWithContext.message.type) {
2237
2305
  case ContainerMessageType.Attach:
2238
- this.dataStores.processAttachMessage(message, local);
2306
+ this.dataStores.processAttachMessage(messageWithContext.message, local);
2239
2307
  break;
2240
2308
  case ContainerMessageType.Alias:
2241
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
2309
+ this.dataStores.processAliasMessage(
2310
+ messageWithContext.message,
2311
+ localOpMetadata,
2312
+ local,
2313
+ );
2242
2314
  break;
2243
2315
  case ContainerMessageType.FluidDataStoreOp:
2244
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
2316
+ this.dataStores.processFluidDataStoreOp(
2317
+ messageWithContext.message,
2318
+ local,
2319
+ localOpMetadata,
2320
+ );
2245
2321
  break;
2246
2322
  case ContainerMessageType.BlobAttach:
2247
- this.blobManager.processBlobAttachOp(message, local);
2323
+ this.blobManager.processBlobAttachOp(messageWithContext.message, local);
2248
2324
  break;
2249
2325
  case ContainerMessageType.IdAllocation:
2250
2326
  assert(
2251
2327
  this.idCompressor !== undefined,
2252
2328
  0x67c /* IdCompressor should be defined if enabled */,
2253
2329
  );
2254
- this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
2330
+ this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
2255
2331
  break;
2256
2332
  case ContainerMessageType.ChunkedOp:
2257
2333
  case ContainerMessageType.Rejoin:
@@ -2259,12 +2335,18 @@ export class ContainerRuntime
2259
2335
  default: {
2260
2336
  // If we didn't necessarily expect a runtime message type, then no worries - just return
2261
2337
  // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
2262
- if (!expectRuntimeMessageType) {
2338
+ if (!messageWithContext.modernRuntimeMessage) {
2263
2339
  return;
2264
2340
  }
2265
2341
 
2266
- const compatBehavior = compatDetails?.behavior;
2267
- if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
2342
+ const compatBehavior = messageWithContext.message.compatDetails?.behavior;
2343
+ if (
2344
+ !compatBehaviorAllowsMessageType(
2345
+ messageWithContext.message.type,
2346
+ compatBehavior,
2347
+ )
2348
+ ) {
2349
+ const { message } = messageWithContext;
2268
2350
  const error = DataProcessingError.create(
2269
2351
  // Former assert 0x3ce
2270
2352
  "Runtime message of unknown type",
@@ -2354,8 +2436,9 @@ export class ContainerRuntime
2354
2436
  * Returns the runtime of the data store.
2355
2437
  * @param id - Id supplied during creating the data store.
2356
2438
  * @param wait - True if you want to wait for it.
2357
- * @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
2439
+ * @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
2358
2440
  */
2441
+ // eslint-disable-next-line import/no-deprecated
2359
2442
  public async getRootDataStore(id: string, wait = true): Promise<IFluidRouter> {
2360
2443
  return this.getRootDataStoreChannel(id, wait);
2361
2444
  }
@@ -2535,7 +2618,7 @@ export class ContainerRuntime
2535
2618
  return this.dirtyContainer;
2536
2619
  }
2537
2620
 
2538
- private isContainerMessageDirtyable({ type, contents }: ContainerRuntimeMessage) {
2621
+ private isContainerMessageDirtyable({ type, contents }: OutboundContainerRuntimeMessage) {
2539
2622
  // For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
2540
2623
  // Ultimately we should have no special-cases from the ContainerRuntime's perspective.
2541
2624
  if (type === ContainerMessageType.Attach) {
@@ -2544,7 +2627,7 @@ export class ContainerRuntime
2544
2627
  return false;
2545
2628
  }
2546
2629
  } else if (type === ContainerMessageType.FluidDataStoreOp) {
2547
- const envelope = contents as IEnvelope;
2630
+ const envelope = contents;
2548
2631
  if (envelope.address === agentSchedulerId) {
2549
2632
  return false;
2550
2633
  }
@@ -2788,7 +2871,7 @@ export class ContainerRuntime
2788
2871
  }
2789
2872
 
2790
2873
  /**
2791
- * @deprecated - Replaced by deleteSweepReadyNodes.
2874
+ * @deprecated Replaced by deleteSweepReadyNodes.
2792
2875
  */
2793
2876
  public deleteUnusedNodes(unusedRoutes: string[]): string[] {
2794
2877
  throw new Error("deleteUnusedRoutes should not be called");
@@ -2937,19 +3020,15 @@ export class ContainerRuntime
2937
3020
 
2938
3021
  assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
2939
3022
 
3023
+ // We close the summarizer and download a new snapshot and reload the container
2940
3024
  let latestSnapshotVersionId: string | undefined;
2941
- if (refreshLatestAck) {
2942
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(
3025
+ if (refreshLatestAck === true) {
3026
+ return this.prefetchLatestSummaryThenClose(
2943
3027
  createChildLogger({
2944
3028
  logger: summaryNumberLogger,
2945
3029
  properties: { all: { safeSummary: true } },
2946
3030
  }),
2947
3031
  );
2948
- const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
2949
- latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
2950
-
2951
- // We might need to catch up to the latest summary's reference sequence number before pausing.
2952
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
2953
3032
  }
2954
3033
 
2955
3034
  // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
@@ -3397,7 +3476,7 @@ export class ContainerRuntime
3397
3476
  }
3398
3477
 
3399
3478
  if (idRange !== undefined) {
3400
- const idAllocationMessage: ContainerRuntimeMessage = {
3479
+ const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
3401
3480
  type: ContainerMessageType.IdAllocation,
3402
3481
  contents: idRange,
3403
3482
  };
@@ -3417,7 +3496,7 @@ export class ContainerRuntime
3417
3496
  }
3418
3497
 
3419
3498
  private submit(
3420
- containerRuntimeMessage: ContainerRuntimeMessage,
3499
+ containerRuntimeMessage: OutboundContainerRuntimeMessage,
3421
3500
  localOpMetadata: unknown = undefined,
3422
3501
  metadata: Record<string, unknown> | undefined = undefined,
3423
3502
  ): void {
@@ -3613,39 +3692,36 @@ export class ContainerRuntime
3613
3692
 
3614
3693
  private reSubmit(message: IPendingBatchMessage) {
3615
3694
  // Need to parse from string for back-compat
3616
- const containerRuntimeMessage = this.parseOpContent(message.content);
3695
+ const containerRuntimeMessage = this.parseLocalOpContent(message.content);
3617
3696
  this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
3618
3697
  }
3619
3698
 
3620
3699
  /**
3621
3700
  * Finds the right store and asks it to resubmit the message. This typically happens when we
3622
3701
  * reconnect and there are pending messages.
3623
- * @param message - The original ContainerRuntimeMessage.
3702
+ * @param message - The original LocalContainerRuntimeMessage.
3624
3703
  * @param localOpMetadata - The local metadata associated with the original message.
3625
3704
  */
3626
3705
  private reSubmitCore(
3627
- message: ContainerRuntimeMessage,
3706
+ message: LocalContainerRuntimeMessage,
3628
3707
  localOpMetadata: unknown,
3629
3708
  opMetadata: Record<string, unknown> | undefined,
3630
3709
  ) {
3631
- const contents = message.contents;
3632
3710
  switch (message.type) {
3633
3711
  case ContainerMessageType.FluidDataStoreOp:
3634
3712
  // For Operations, call resubmitDataStoreOp which will find the right store
3635
3713
  // and trigger resubmission on it.
3636
- this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
3714
+ this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
3637
3715
  break;
3638
3716
  case ContainerMessageType.Attach:
3639
3717
  case ContainerMessageType.Alias:
3640
3718
  this.submit(message, localOpMetadata);
3641
3719
  break;
3642
- case ContainerMessageType.IdAllocation:
3643
- // Remove the stashedState from the op if it's a stashed op
3644
- if (contents.stashedState !== undefined) {
3645
- delete contents.stashedState;
3646
- }
3720
+ case ContainerMessageType.IdAllocation: {
3721
+ prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
3647
3722
  this.submit(message, localOpMetadata);
3648
3723
  break;
3724
+ }
3649
3725
  case ContainerMessageType.ChunkedOp:
3650
3726
  throw new Error(`chunkedOp not expected here`);
3651
3727
  case ContainerMessageType.BlobAttach:
@@ -3684,12 +3760,12 @@ export class ContainerRuntime
3684
3760
 
3685
3761
  private rollback(content: string | undefined, localOpMetadata: unknown) {
3686
3762
  // Need to parse from string for back-compat
3687
- const { type, contents } = this.parseOpContent(content);
3763
+ const { type, contents } = this.parseLocalOpContent(content);
3688
3764
  switch (type) {
3689
3765
  case ContainerMessageType.FluidDataStoreOp:
3690
3766
  // For operations, call rollbackDataStoreOp which will find the right store
3691
3767
  // and trigger rollback on it.
3692
- this.dataStores.rollbackDataStoreOp(contents as IEnvelope, localOpMetadata);
3768
+ this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
3693
3769
  break;
3694
3770
  default:
3695
3771
  // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
@@ -3697,26 +3773,6 @@ export class ContainerRuntime
3697
3773
  }
3698
3774
  }
3699
3775
 
3700
- private async waitForDeltaManagerToCatchup(
3701
- latestSnapshotRefSeq: number,
3702
- summaryLogger: ITelemetryLoggerExt,
3703
- ): Promise<void> {
3704
- if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
3705
- // We need to catch up to the latest summary's reference sequence number before proceeding.
3706
- await PerformanceEvent.timedExecAsync(
3707
- summaryLogger,
3708
- {
3709
- eventName: "WaitingForSeq",
3710
- lastSequenceNumber: this.deltaManager.lastSequenceNumber,
3711
- targetSequenceNumber: latestSnapshotRefSeq,
3712
- lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
3713
- },
3714
- async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq),
3715
- { start: true, end: true, cancel: "error" }, // definitely want start event
3716
- );
3717
- }
3718
- }
3719
-
3720
3776
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
3721
3777
  public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions) {
3722
3778
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
@@ -3735,7 +3791,7 @@ export class ContainerRuntime
3735
3791
  * and then close as the current main client is likely to be re-elected as the parent summarizer again.
3736
3792
  */
3737
3793
  if (!result.isSummaryTracked && result.isSummaryNewer) {
3738
- const fetchResult = await this.fetchSnapshotFromStorage(
3794
+ const fetchResult = await this.fetchLatestSnapshotFromStorage(
3739
3795
  summaryLogger,
3740
3796
  {
3741
3797
  eventName: "RefreshLatestSummaryAckFetch",
@@ -3743,7 +3799,6 @@ export class ContainerRuntime
3743
3799
  targetSequenceNumber: summaryRefSeq,
3744
3800
  },
3745
3801
  readAndParseBlob,
3746
- null,
3747
3802
  );
3748
3803
 
3749
3804
  /**
@@ -3780,40 +3835,37 @@ export class ContainerRuntime
3780
3835
  }
3781
3836
 
3782
3837
  /**
3783
- * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
3784
- * internal state as it should be considered the latest summary ack.
3838
+ * Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
3839
+ * summarizer to reload from new state.
3785
3840
  * @param summaryLogger - logger to use when fetching snapshot from storage
3786
- * @returns downloaded snapshot's reference sequence number
3841
+ * @returns a generic summarization error
3787
3842
  */
3788
- private async refreshLatestSummaryAckFromServer(
3843
+ private async prefetchLatestSummaryThenClose(
3789
3844
  summaryLogger: ITelemetryLoggerExt,
3790
- ): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
3845
+ ): Promise<IBaseSummarizeResult> {
3791
3846
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3792
- const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(
3847
+
3848
+ // This is a performance optimization as the same parent is likely to be elected again, and would use its
3849
+ // cache to fetch the snapshot instead of the network.
3850
+ await this.fetchLatestSnapshotFromStorage(
3793
3851
  summaryLogger,
3794
3852
  {
3795
3853
  eventName: "RefreshLatestSummaryFromServerFetch",
3796
3854
  },
3797
3855
  readAndParseBlob,
3798
- null,
3799
3856
  );
3800
3857
 
3801
3858
  await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
3802
3859
 
3803
- return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
3860
+ return {
3861
+ stage: "base",
3862
+ error: "summary state stale - Unsupported option 'refreshLatestAck'",
3863
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
3864
+ minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
3865
+ };
3804
3866
  }
3805
3867
 
3806
3868
  private async closeStaleSummarizer(codePath: string): Promise<void> {
3807
- this.mc.logger.sendTelemetryEvent(
3808
- {
3809
- eventName: "ClosingSummarizerOnSummaryStale",
3810
- codePath,
3811
- message: "Stopping fetch from storage",
3812
- closeSummarizerDelayMs: this.closeSummarizerDelayMs,
3813
- },
3814
- new GenericError("Restarting summarizer instead of refreshing"),
3815
- );
3816
-
3817
3869
  // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
3818
3870
  await delay(this.closeSummarizerDelayMs);
3819
3871
  this._summarizer?.stop("latestSummaryStateStale");
@@ -3821,15 +3873,14 @@ export class ContainerRuntime
3821
3873
  }
3822
3874
 
3823
3875
  /**
3824
- * Downloads snapshot from storage with the given versionId or latest if versionId is null.
3876
+ * Downloads the latest snapshot from storage.
3825
3877
  * By default, it also closes the container after downloading the snapshot. However, this may be
3826
3878
  * overridden via options.
3827
3879
  */
3828
- private async fetchSnapshotFromStorage(
3880
+ private async fetchLatestSnapshotFromStorage(
3829
3881
  logger: ITelemetryLoggerExt,
3830
3882
  event: ITelemetryGenericEvent,
3831
3883
  readAndParseBlob: ReadAndParseBlob,
3832
- versionId: string | null,
3833
3884
  ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3834
3885
  return PerformanceEvent.timedExecAsync(
3835
3886
  logger,
@@ -3851,10 +3902,10 @@ export class ContainerRuntime
3851
3902
  const trace = Trace.start();
3852
3903
 
3853
3904
  const versions = await this.storage.getVersions(
3854
- versionId,
3905
+ null,
3855
3906
  1,
3856
- "refreshLatestSummaryAckFromServer",
3857
- versionId === null ? FetchSource.noCache : undefined,
3907
+ "prefetchLatestSummaryBeforeClose",
3908
+ FetchSource.noCache,
3858
3909
  );
3859
3910
  assert(
3860
3911
  !!versions && !!versions[0],
@@ -3896,17 +3947,17 @@ export class ContainerRuntime
3896
3947
  if (this._orderSequentiallyCalls !== 0) {
3897
3948
  throw new UsageError("can't get state during orderSequentially");
3898
3949
  }
3899
- const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(
3900
- waitBlobsToAttach,
3901
- );
3902
- const pending = this.pendingStateManager.getLocalState();
3903
- if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
3904
- return; // no pending state to save
3905
- }
3906
3950
  // Flush pending batch.
3907
3951
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
3908
3952
  // to close current batch.
3909
3953
  this.flush();
3954
+ const pendingAttachmentBlobs = waitBlobsToAttach
3955
+ ? await this.blobManager.attachAndGetPendingBlobs()
3956
+ : undefined;
3957
+ const pending = this.pendingStateManager.getLocalState();
3958
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
3959
+ return; // no pending state to save
3960
+ }
3910
3961
 
3911
3962
  const pendingState: IPendingRuntimeState = {
3912
3963
  pending,
@@ -3948,35 +3999,11 @@ export class ContainerRuntime
3948
3999
  }
3949
4000
 
3950
4001
  /**
3951
- * * Forms a function that will request a Summarizer.
3952
- * @param loaderRouter - the loader acting as an IFluidRouter
3953
- * */
3954
- private formRequestSummarizerFn(loaderRouter: IFluidRouter) {
4002
+ * Forms a function that will create and retrieve a Summarizer.
4003
+ */
4004
+ private formCreateSummarizerFn(loader: ILoader) {
3955
4005
  return async () => {
3956
- const request: IRequest = {
3957
- headers: {
3958
- [LoaderHeader.cache]: false,
3959
- [LoaderHeader.clientDetails]: {
3960
- capabilities: { interactive: false },
3961
- type: summarizerClientType,
3962
- },
3963
- [DriverHeader.summarizingClient]: true,
3964
- [LoaderHeader.reconnect]: false,
3965
- },
3966
- url: "/_summarizer",
3967
- };
3968
-
3969
- const fluidObject = await requestFluidObject<FluidObject<ISummarizer>>(
3970
- loaderRouter,
3971
- request,
3972
- );
3973
- const summarizer = fluidObject.ISummarizer;
3974
-
3975
- if (!summarizer) {
3976
- throw new UsageError("Fluid object does not implement ISummarizer");
3977
- }
3978
-
3979
- return summarizer;
4006
+ return createSummarizer(loader, `/${summarizerRequestUrl}`);
3980
4007
  };
3981
4008
  }
3982
4009
 
@@ -4003,30 +4030,3 @@ export class ContainerRuntime
4003
4030
  return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
4004
4031
  }
4005
4032
  }
4006
-
4007
- /**
4008
- * Wait for a specific sequence number. Promise should resolve when we reach that number,
4009
- * or reject if closed.
4010
- */
4011
- const waitForSeq = async (
4012
- deltaManager: IDeltaManager<Pick<ISequencedDocumentMessage, "sequenceNumber">, unknown>,
4013
- targetSeq: number,
4014
- ): Promise<void> =>
4015
- new Promise<void>((resolve, reject) => {
4016
- // TODO: remove cast to any when actual event is determined
4017
- deltaManager.on("closed" as any, reject);
4018
- deltaManager.on("disposed" as any, reject);
4019
-
4020
- // If we already reached target sequence number, simply resolve the promise.
4021
- if (deltaManager.lastSequenceNumber >= targetSeq) {
4022
- resolve();
4023
- } else {
4024
- const handleOp = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
4025
- if (message.sequenceNumber >= targetSeq) {
4026
- resolve();
4027
- deltaManager.off("op", handleOp);
4028
- }
4029
- };
4030
- deltaManager.on("op", handleOp);
4031
- }
4032
- });