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

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 (335) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/api-extractor.json +1 -1
  3. package/api-report/container-runtime.api.md +864 -0
  4. package/dist/blobManager.d.ts +4 -4
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +55 -71
  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 +1742 -0
  12. package/dist/container-runtime-beta.d.ts +1742 -0
  13. package/dist/container-runtime-public.d.ts +1742 -0
  14. package/dist/container-runtime-untrimmed.d.ts +1803 -0
  15. package/dist/containerHandleContext.js +3 -3
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +88 -98
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +466 -453
  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 +60 -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.js +1 -1
  32. package/dist/dataStores.js.map +1 -1
  33. package/dist/deltaManagerProxyBase.js +4 -4
  34. package/dist/deltaManagerProxyBase.js.map +1 -1
  35. package/dist/deltaManagerSummarizerProxy.js +6 -6
  36. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  37. package/dist/deltaScheduler.js.map +1 -1
  38. package/dist/error.d.ts.map +1 -1
  39. package/dist/error.js.map +1 -1
  40. package/dist/gc/garbageCollection.d.ts.map +1 -1
  41. package/dist/gc/garbageCollection.js +23 -24
  42. package/dist/gc/garbageCollection.js.map +1 -1
  43. package/dist/gc/gcConfigs.js +1 -1
  44. package/dist/gc/gcConfigs.js.map +1 -1
  45. package/dist/gc/gcDefinitions.d.ts +34 -24
  46. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  47. package/dist/gc/gcDefinitions.js +10 -7
  48. package/dist/gc/gcDefinitions.js.map +1 -1
  49. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  50. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  51. package/dist/gc/gcTelemetry.d.ts +2 -2
  52. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  53. package/dist/gc/gcTelemetry.js +5 -5
  54. package/dist/gc/gcTelemetry.js.map +1 -1
  55. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  56. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  57. package/dist/gc/index.d.ts +1 -1
  58. package/dist/gc/index.d.ts.map +1 -1
  59. package/dist/gc/index.js +3 -3
  60. package/dist/gc/index.js.map +1 -1
  61. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  62. package/dist/id-compressor/idCompressor.js.map +1 -1
  63. package/dist/id-compressor/identifiers.d.ts +3 -3
  64. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  65. package/dist/id-compressor/utilities.d.ts +3 -0
  66. package/dist/id-compressor/utilities.d.ts.map +1 -1
  67. package/dist/id-compressor/utilities.js +3 -0
  68. package/dist/id-compressor/utilities.js.map +1 -1
  69. package/dist/index.d.ts +5 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +6 -2
  72. package/dist/index.js.map +1 -1
  73. package/dist/messageTypes.d.ts +137 -0
  74. package/dist/messageTypes.d.ts.map +1 -0
  75. package/dist/messageTypes.js +32 -0
  76. package/dist/messageTypes.js.map +1 -0
  77. package/dist/opLifecycle/batchManager.js +6 -6
  78. package/dist/opLifecycle/batchManager.js.map +1 -1
  79. package/dist/opLifecycle/definitions.d.ts +7 -3
  80. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  81. package/dist/opLifecycle/definitions.js.map +1 -1
  82. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  83. package/dist/opLifecycle/opDecompressor.js +0 -4
  84. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  85. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  86. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  87. package/dist/opLifecycle/opSplitter.js +3 -3
  88. package/dist/opLifecycle/opSplitter.js.map +1 -1
  89. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  90. package/dist/opLifecycle/outbox.js +7 -2
  91. package/dist/opLifecycle/outbox.js.map +1 -1
  92. package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  93. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  94. package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
  95. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  96. package/dist/packageVersion.d.ts +1 -1
  97. package/dist/packageVersion.js +1 -1
  98. package/dist/packageVersion.js.map +1 -1
  99. package/dist/pendingStateManager.d.ts +4 -20
  100. package/dist/pendingStateManager.d.ts.map +1 -1
  101. package/dist/pendingStateManager.js +36 -46
  102. package/dist/pendingStateManager.js.map +1 -1
  103. package/dist/scheduleManager.js +6 -2
  104. package/dist/scheduleManager.js.map +1 -1
  105. package/dist/summary/orderedClientElection.d.ts +7 -4
  106. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  107. package/dist/summary/orderedClientElection.js +54 -54
  108. package/dist/summary/orderedClientElection.js.map +1 -1
  109. package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
  110. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  111. package/dist/summary/runWhileConnectedCoordinator.js +7 -6
  112. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  113. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  114. package/dist/summary/runningSummarizer.js +40 -38
  115. package/dist/summary/runningSummarizer.js.map +1 -1
  116. package/dist/summary/summarizer.d.ts +2 -0
  117. package/dist/summary/summarizer.d.ts.map +1 -1
  118. package/dist/summary/summarizer.js +18 -8
  119. package/dist/summary/summarizer.js.map +1 -1
  120. package/dist/summary/summarizerClientElection.js +6 -6
  121. package/dist/summary/summarizerClientElection.js.map +1 -1
  122. package/dist/summary/summarizerHeuristics.js +9 -9
  123. package/dist/summary/summarizerHeuristics.js.map +1 -1
  124. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
  125. package/dist/summary/summarizerNode/summarizerNode.js +8 -8
  126. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  127. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  128. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  129. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  130. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  131. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  132. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  133. package/dist/summary/summarizerTypes.d.ts +107 -22
  134. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  135. package/dist/summary/summarizerTypes.js.map +1 -1
  136. package/dist/summary/summaryCollection.d.ts +18 -2
  137. package/dist/summary/summaryCollection.d.ts.map +1 -1
  138. package/dist/summary/summaryCollection.js +23 -21
  139. package/dist/summary/summaryCollection.js.map +1 -1
  140. package/dist/summary/summaryFormat.d.ts +15 -6
  141. package/dist/summary/summaryFormat.d.ts.map +1 -1
  142. package/dist/summary/summaryFormat.js.map +1 -1
  143. package/dist/summary/summaryGenerator.d.ts +3 -3
  144. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  145. package/dist/summary/summaryGenerator.js.map +1 -1
  146. package/dist/summary/summaryManager.d.ts +2 -2
  147. package/dist/summary/summaryManager.d.ts.map +1 -1
  148. package/dist/summary/summaryManager.js +10 -10
  149. package/dist/summary/summaryManager.js.map +1 -1
  150. package/dist/throttler.js +16 -16
  151. package/dist/throttler.js.map +1 -1
  152. package/dist/tsdoc-metadata.json +1 -1
  153. package/lib/blobManager.d.ts +4 -4
  154. package/lib/blobManager.d.ts.map +1 -1
  155. package/lib/blobManager.js +56 -72
  156. package/lib/blobManager.js.map +1 -1
  157. package/lib/connectionTelemetry.d.ts.map +1 -1
  158. package/lib/connectionTelemetry.js +76 -43
  159. package/lib/connectionTelemetry.js.map +1 -1
  160. package/lib/containerHandleContext.js +3 -3
  161. package/lib/containerHandleContext.js.map +1 -1
  162. package/lib/containerRuntime.d.ts +88 -98
  163. package/lib/containerRuntime.d.ts.map +1 -1
  164. package/lib/containerRuntime.js +424 -416
  165. package/lib/containerRuntime.js.map +1 -1
  166. package/lib/dataStore.js +11 -11
  167. package/lib/dataStore.js.map +1 -1
  168. package/lib/dataStoreContext.d.ts +2 -4
  169. package/lib/dataStoreContext.d.ts.map +1 -1
  170. package/lib/dataStoreContext.js +60 -59
  171. package/lib/dataStoreContext.js.map +1 -1
  172. package/lib/dataStoreRegistry.d.ts +3 -0
  173. package/lib/dataStoreRegistry.d.ts.map +1 -1
  174. package/lib/dataStoreRegistry.js +6 -3
  175. package/lib/dataStoreRegistry.js.map +1 -1
  176. package/lib/dataStores.js +1 -1
  177. package/lib/dataStores.js.map +1 -1
  178. package/lib/deltaManagerProxyBase.js +4 -4
  179. package/lib/deltaManagerProxyBase.js.map +1 -1
  180. package/lib/deltaManagerSummarizerProxy.js +6 -6
  181. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  182. package/lib/deltaScheduler.js.map +1 -1
  183. package/lib/error.d.ts.map +1 -1
  184. package/lib/error.js.map +1 -1
  185. package/lib/gc/garbageCollection.d.ts.map +1 -1
  186. package/lib/gc/garbageCollection.js +23 -24
  187. package/lib/gc/garbageCollection.js.map +1 -1
  188. package/lib/gc/gcConfigs.js +2 -2
  189. package/lib/gc/gcConfigs.js.map +1 -1
  190. package/lib/gc/gcDefinitions.d.ts +34 -24
  191. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  192. package/lib/gc/gcDefinitions.js +9 -6
  193. package/lib/gc/gcDefinitions.js.map +1 -1
  194. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  195. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  196. package/lib/gc/gcTelemetry.d.ts +2 -2
  197. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  198. package/lib/gc/gcTelemetry.js +5 -5
  199. package/lib/gc/gcTelemetry.js.map +1 -1
  200. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  201. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  202. package/lib/gc/index.d.ts +1 -1
  203. package/lib/gc/index.d.ts.map +1 -1
  204. package/lib/gc/index.js +1 -1
  205. package/lib/gc/index.js.map +1 -1
  206. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  207. package/lib/id-compressor/idCompressor.js.map +1 -1
  208. package/lib/id-compressor/identifiers.d.ts +3 -3
  209. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  210. package/lib/id-compressor/utilities.d.ts +3 -0
  211. package/lib/id-compressor/utilities.d.ts.map +1 -1
  212. package/lib/id-compressor/utilities.js +3 -0
  213. package/lib/id-compressor/utilities.js.map +1 -1
  214. package/lib/index.d.ts +5 -3
  215. package/lib/index.d.ts.map +1 -1
  216. package/lib/index.js +3 -1
  217. package/lib/index.js.map +1 -1
  218. package/lib/messageTypes.d.ts +137 -0
  219. package/lib/messageTypes.d.ts.map +1 -0
  220. package/lib/messageTypes.js +29 -0
  221. package/lib/messageTypes.js.map +1 -0
  222. package/lib/opLifecycle/batchManager.js +6 -6
  223. package/lib/opLifecycle/batchManager.js.map +1 -1
  224. package/lib/opLifecycle/definitions.d.ts +7 -3
  225. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  226. package/lib/opLifecycle/definitions.js.map +1 -1
  227. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  228. package/lib/opLifecycle/opDecompressor.js +0 -4
  229. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  230. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  231. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  232. package/lib/opLifecycle/opSplitter.js +1 -1
  233. package/lib/opLifecycle/opSplitter.js.map +1 -1
  234. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  235. package/lib/opLifecycle/outbox.js +7 -2
  236. package/lib/opLifecycle/outbox.js.map +1 -1
  237. package/lib/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  238. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  239. package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
  240. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  241. package/lib/packageVersion.d.ts +1 -1
  242. package/lib/packageVersion.js +1 -1
  243. package/lib/packageVersion.js.map +1 -1
  244. package/lib/pendingStateManager.d.ts +4 -20
  245. package/lib/pendingStateManager.d.ts.map +1 -1
  246. package/lib/pendingStateManager.js +35 -45
  247. package/lib/pendingStateManager.js.map +1 -1
  248. package/lib/scheduleManager.js +6 -2
  249. package/lib/scheduleManager.js.map +1 -1
  250. package/lib/summary/orderedClientElection.d.ts +7 -4
  251. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  252. package/lib/summary/orderedClientElection.js +54 -54
  253. package/lib/summary/orderedClientElection.js.map +1 -1
  254. package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
  255. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  256. package/lib/summary/runWhileConnectedCoordinator.js +7 -6
  257. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  258. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  259. package/lib/summary/runningSummarizer.js +40 -38
  260. package/lib/summary/runningSummarizer.js.map +1 -1
  261. package/lib/summary/summarizer.d.ts +2 -0
  262. package/lib/summary/summarizer.d.ts.map +1 -1
  263. package/lib/summary/summarizer.js +19 -9
  264. package/lib/summary/summarizer.js.map +1 -1
  265. package/lib/summary/summarizerClientElection.js +6 -6
  266. package/lib/summary/summarizerClientElection.js.map +1 -1
  267. package/lib/summary/summarizerHeuristics.js +9 -9
  268. package/lib/summary/summarizerHeuristics.js.map +1 -1
  269. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
  270. package/lib/summary/summarizerNode/summarizerNode.js +8 -8
  271. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  272. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  273. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  274. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  275. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  276. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  277. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  278. package/lib/summary/summarizerTypes.d.ts +107 -22
  279. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  280. package/lib/summary/summarizerTypes.js.map +1 -1
  281. package/lib/summary/summaryCollection.d.ts +18 -2
  282. package/lib/summary/summaryCollection.d.ts.map +1 -1
  283. package/lib/summary/summaryCollection.js +23 -21
  284. package/lib/summary/summaryCollection.js.map +1 -1
  285. package/lib/summary/summaryFormat.d.ts +15 -6
  286. package/lib/summary/summaryFormat.d.ts.map +1 -1
  287. package/lib/summary/summaryFormat.js.map +1 -1
  288. package/lib/summary/summaryGenerator.d.ts +3 -3
  289. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  290. package/lib/summary/summaryGenerator.js.map +1 -1
  291. package/lib/summary/summaryManager.d.ts +2 -2
  292. package/lib/summary/summaryManager.d.ts.map +1 -1
  293. package/lib/summary/summaryManager.js +9 -9
  294. package/lib/summary/summaryManager.js.map +1 -1
  295. package/lib/throttler.js +16 -16
  296. package/lib/throttler.js.map +1 -1
  297. package/package.json +27 -28
  298. package/src/blobManager.ts +64 -77
  299. package/src/connectionTelemetry.ts +97 -52
  300. package/src/containerRuntime.ts +337 -341
  301. package/src/dataStore.ts +3 -3
  302. package/src/dataStoreContext.ts +7 -7
  303. package/src/dataStoreRegistry.ts +3 -0
  304. package/src/dataStores.ts +1 -1
  305. package/src/error.ts +4 -1
  306. package/src/gc/garbageCollection.ts +12 -11
  307. package/src/gc/gcConfigs.ts +3 -3
  308. package/src/gc/gcDefinitions.ts +35 -25
  309. package/src/gc/gcSummaryDefinitions.ts +1 -1
  310. package/src/gc/gcTelemetry.ts +6 -5
  311. package/src/gc/index.ts +2 -2
  312. package/src/id-compressor/utilities.ts +3 -0
  313. package/src/index.ts +21 -5
  314. package/src/messageTypes.ts +228 -0
  315. package/src/opLifecycle/README.md +93 -68
  316. package/src/opLifecycle/definitions.ts +5 -1
  317. package/src/opLifecycle/opDecompressor.ts +0 -8
  318. package/src/opLifecycle/opGroupingManager.ts +2 -4
  319. package/src/opLifecycle/opSplitter.ts +2 -2
  320. package/src/opLifecycle/outbox.ts +3 -0
  321. package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
  322. package/src/packageVersion.ts +1 -1
  323. package/src/pendingStateManager.ts +31 -52
  324. package/src/scheduleManager.ts +2 -0
  325. package/src/summary/orderedClientElection.ts +4 -1
  326. package/src/summary/runWhileConnectedCoordinator.ts +5 -1
  327. package/src/summary/runningSummarizer.ts +3 -1
  328. package/src/summary/summarizer.ts +21 -7
  329. package/src/summary/summarizerNode/summarizerNode.ts +1 -1
  330. package/src/summary/summarizerTypes.ts +96 -11
  331. package/src/summary/summaryCollection.ts +19 -1
  332. package/src/summary/summaryFormat.ts +11 -1
  333. package/src/summary/summaryGenerator.ts +3 -3
  334. package/src/summary/summaryManager.ts +2 -2
  335. 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 {
@@ -184,92 +186,45 @@ import {
184
186
  } from "./opLifecycle";
185
187
  import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
186
188
  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
- }
189
+ import {
190
+ ContainerMessageType,
191
+ type InboundSequencedContainerRuntimeMessage,
192
+ type InboundSequencedContainerRuntimeMessageOrSystemMessage,
193
+ type ContainerRuntimeIdAllocationMessage,
194
+ type LocalContainerRuntimeIdAllocationMessage,
195
+ type LocalContainerRuntimeMessage,
196
+ type OutboundContainerRuntimeMessage,
197
+ type UnknownContainerRuntimeMessage,
198
+ } from "./messageTypes";
235
199
 
236
200
  /**
237
201
  * Utility to implement compat behaviors given an unknown message type
238
202
  * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
239
203
  *
240
- * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
204
+ * @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
241
205
  * handled before calling this function (e.g. in a switch statement).
242
206
  * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
243
207
  */
244
208
  function compatBehaviorAllowsMessageType(
245
- _unknownContainerRuntimeMessageType: never,
209
+ _unknownContainerRuntimeMessageType: UnknownContainerRuntimeMessage["type"],
246
210
  compatBehavior: "Ignore" | "FailToProcess" | undefined,
247
211
  ): boolean {
248
212
  // undefined defaults to same behavior as "FailToProcess"
249
213
  return compatBehavior === "Ignore";
250
214
  }
251
215
 
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;
216
+ function prepareLocalContainerRuntimeIdAllocationMessageForTransit(
217
+ message: LocalContainerRuntimeIdAllocationMessage | ContainerRuntimeIdAllocationMessage,
218
+ ): asserts message is ContainerRuntimeIdAllocationMessage {
219
+ // Remove the stashedState from the op if it's a stashed op
220
+ if ("stashedState" in message.contents) {
221
+ delete message.contents.stashedState;
222
+ }
265
223
  }
266
224
 
267
225
  /**
268
- * An unpacked ISequencedDocumentMessage with the inner ContainerRuntimeMessage type/contents/etc
269
- * promoted up to the outer object
226
+ * @public
270
227
  */
271
- export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
272
-
273
228
  export interface ISummaryBaseConfiguration {
274
229
  /**
275
230
  * Delay before first attempt to spawn summarizing container.
@@ -289,6 +244,9 @@ export interface ISummaryBaseConfiguration {
289
244
  maxOpsSinceLastSummary: number;
290
245
  }
291
246
 
247
+ /**
248
+ * @public
249
+ */
292
250
  export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfiguration {
293
251
  state: "enabled";
294
252
  /**
@@ -349,19 +307,31 @@ export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfigurati
349
307
  nonRuntimeHeuristicThreshold?: number;
350
308
  }
351
309
 
310
+ /**
311
+ * @public
312
+ */
352
313
  export interface ISummaryConfigurationDisableSummarizer {
353
314
  state: "disabled";
354
315
  }
355
316
 
317
+ /**
318
+ * @public
319
+ */
356
320
  export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConfiguration {
357
321
  state: "disableHeuristics";
358
322
  }
359
323
 
324
+ /**
325
+ * @public
326
+ */
360
327
  export type ISummaryConfiguration =
361
328
  | ISummaryConfigurationDisableSummarizer
362
329
  | ISummaryConfigurationDisableHeuristics
363
330
  | ISummaryConfigurationHeuristics;
364
331
 
332
+ /**
333
+ * @public
334
+ */
365
335
  export const DefaultSummaryConfiguration: ISummaryConfiguration = {
366
336
  state: "enabled",
367
337
 
@@ -388,6 +358,9 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
388
358
  nonRuntimeHeuristicThreshold: 20,
389
359
  };
390
360
 
361
+ /**
362
+ * @public
363
+ */
391
364
  export interface ISummaryRuntimeOptions {
392
365
  /** Override summary configurations set by the server. */
393
366
  summaryConfigOverrides?: ISummaryConfiguration;
@@ -403,22 +376,25 @@ export interface ISummaryRuntimeOptions {
403
376
 
404
377
  /**
405
378
  * Options for op compression.
406
- * @experimental - Not ready for use
379
+ * @public
407
380
  */
408
381
  export interface ICompressionRuntimeOptions {
409
382
  /**
410
- * The minimum size the batch's payload must exceed before the batch's contents will be compressed.
383
+ * The value the batch's content size must exceed for the batch to be compressed.
384
+ * By default the value is 600 * 1024 = 614400 bytes. If the value is set to `Infinity`, compression will be disabled.
411
385
  */
412
386
  readonly minimumBatchSizeInBytes: number;
413
387
 
414
388
  /**
415
389
  * The compression algorithm that will be used to compress the op.
390
+ * By default the value is `lz4` which is the only compression algorithm currently supported.
416
391
  */
417
392
  readonly compressionAlgorithm: CompressionAlgorithms;
418
393
  }
419
394
 
420
395
  /**
421
396
  * Options for container runtime.
397
+ * @public
422
398
  */
423
399
  export interface IContainerRuntimeOptions {
424
400
  readonly summaryOptions?: ISummaryRuntimeOptions;
@@ -440,8 +416,7 @@ export interface IContainerRuntimeOptions {
440
416
  */
441
417
  readonly flushMode?: FlushMode;
442
418
  /**
443
- * Enables the runtime to compress ops. Compression is disabled when undefined.
444
- * @experimental Not ready for use.
419
+ * Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}.
445
420
  */
446
421
  readonly compressionOptions?: ICompressionRuntimeOptions;
447
422
  /**
@@ -458,12 +433,15 @@ export interface IContainerRuntimeOptions {
458
433
  /**
459
434
  * If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
460
435
  * 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.
436
+ * batch content size exceeds this value, it will be chunked into smaller ops of this exact size.
462
437
  *
463
- * If unspecified, if a batch exceeds `maxBatchSizeInBytes` after compression, the container will close with an instance
464
- * of `GenericError` with the `BatchTooLarge` message.
438
+ * This value is a trade-off between having many small chunks vs fewer larger chunks and by default, the runtime is configured to use
439
+ * 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link IContainerRuntimeOptions.maxBatchSizeInBytes}
440
+ * regardless of the overhead of an individual op.
465
441
  *
466
- * @experimental Not ready for use.
442
+ * Any value of `chunkSizeInBytes` exceeding {@link IContainerRuntimeOptions.maxBatchSizeInBytes} will disable this feature, therefore if a compressed batch's content
443
+ * size exceeds {@link IContainerRuntimeOptions.maxBatchSizeInBytes} after compression, the container will close with an instance of `GenericError` with
444
+ * the `BatchTooLarge` message.
467
445
  */
468
446
  readonly chunkSizeInBytes?: number;
469
447
 
@@ -498,6 +476,7 @@ export interface IContainerRuntimeOptions {
498
476
 
499
477
  /**
500
478
  * Accepted header keys for requests coming to the runtime.
479
+ * @public
501
480
  */
502
481
  export enum RuntimeHeaders {
503
482
  /** True to wait for a data store to be created and loaded before returning it. */
@@ -506,14 +485,25 @@ export enum RuntimeHeaders {
506
485
  viaHandle = "viaHandle",
507
486
  }
508
487
 
509
- /** True if a tombstoned object should be returned without erroring */
488
+ /** True if a tombstoned object should be returned without erroring
489
+ * @public
490
+ */
510
491
  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 */
492
+ /**
493
+ * [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
494
+ * @public
495
+ */
512
496
  export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
513
497
 
514
- /** Tombstone error responses will have this header set to true */
498
+ /**
499
+ * Tombstone error responses will have this header set to true
500
+ * @public
501
+ */
515
502
  export const TombstoneResponseHeaderKey = "isTombstoned";
516
- /** Inactive error responses will have this header set to true */
503
+ /**
504
+ * Inactive error responses will have this header set to true
505
+ * @public
506
+ */
517
507
  export const InactiveResponseHeaderKey = "isInactive";
518
508
 
519
509
  /**
@@ -534,6 +524,7 @@ export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
534
524
 
535
525
  /**
536
526
  * Available compression algorithms for op compression.
527
+ * @public
537
528
  */
538
529
  export enum CompressionAlgorithms {
539
530
  lz4 = "lz4",
@@ -597,7 +588,8 @@ export const defaultPendingOpsRetryDelayMs = 1000;
597
588
  const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
598
589
 
599
590
  /**
600
- * @deprecated - use ContainerRuntimeMessage instead
591
+ * @deprecated use ContainerRuntimeMessageType instead
592
+ * @public
601
593
  */
602
594
  export enum RuntimeMessage {
603
595
  FluidDataStoreOp = "component",
@@ -610,7 +602,8 @@ export enum RuntimeMessage {
610
602
  }
611
603
 
612
604
  /**
613
- * @deprecated - please use version in driver-utils
605
+ * @deprecated please use version in driver-utils
606
+ * @public
614
607
  */
615
608
  export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
616
609
  return (Object.values(RuntimeMessage) as string[]).includes(message.type);
@@ -620,6 +613,7 @@ export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
620
613
  * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
621
614
  * special-case for document dirty state. Ultimately we should have no special-cases from the
622
615
  * ContainerRuntime's perspective.
616
+ * @public
623
617
  */
624
618
  export const agentSchedulerId = "_scheduler";
625
619
 
@@ -660,23 +654,94 @@ export const makeLegacySendBatchFn =
660
654
  deltaManager.flush();
661
655
  };
662
656
 
657
+ /** Helper type for type constraints passed through several functions.
658
+ * message - The unpacked message. Likely a TypedContainerRuntimeMessage, but could also be a system op
659
+ * modernRuntimeMessage - Does this appear like a current TypedContainerRuntimeMessage?
660
+ * local - Did this client send the op?
661
+ */
662
+ type MessageWithContext =
663
+ | {
664
+ message: InboundSequencedContainerRuntimeMessage;
665
+ modernRuntimeMessage: true;
666
+ local: boolean;
667
+ }
668
+ | {
669
+ message: InboundSequencedContainerRuntimeMessageOrSystemMessage;
670
+ modernRuntimeMessage: false;
671
+ local: boolean;
672
+ };
673
+
674
+ const summarizerRequestUrl = "_summarizer";
675
+
676
+ /**
677
+ * Create and retrieve the summmarizer
678
+ */
679
+ async function createSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
680
+ const request: IRequest = {
681
+ headers: {
682
+ [LoaderHeader.cache]: false,
683
+ [LoaderHeader.clientDetails]: {
684
+ capabilities: { interactive: false },
685
+ type: summarizerClientType,
686
+ },
687
+ [DriverHeader.summarizingClient]: true,
688
+ [LoaderHeader.reconnect]: false,
689
+ },
690
+ url,
691
+ };
692
+
693
+ const resolvedContainer = await loader.resolve(request);
694
+ let fluidObject: FluidObject<ISummarizer> | undefined;
695
+
696
+ // Older containers may not have the "getEntryPoint" API
697
+ // ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
698
+ if (resolvedContainer.getEntryPoint !== undefined) {
699
+ fluidObject = await resolvedContainer.getEntryPoint();
700
+ } else {
701
+ const response = await resolvedContainer.request({ url: `/${summarizerRequestUrl}` });
702
+ if (response.status !== 200 || response.mimeType !== "fluid/object") {
703
+ throw responseToException(response, request);
704
+ }
705
+ fluidObject = response.value;
706
+ }
707
+
708
+ if (fluidObject?.ISummarizer === undefined) {
709
+ throw new UsageError("Fluid object does not implement ISummarizer");
710
+ }
711
+ return fluidObject.ISummarizer;
712
+ }
713
+
714
+ /**
715
+ * This function is not supported publicly and exists for e2e testing
716
+ * @internal
717
+ */
718
+ export async function TEST_requestSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
719
+ return createSummarizer(loader, url);
720
+ }
721
+
663
722
  /**
664
723
  * Represents the runtime of the container. Contains helper functions/state of the container.
665
724
  * It will define the store level mappings.
725
+ * @public
666
726
  */
667
727
  export class ContainerRuntime
668
728
  extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
669
- implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
729
+ implements
730
+ IContainerRuntime,
731
+ IRuntime,
732
+ ISummarizerRuntime,
733
+ ISummarizerInternalsProvider,
734
+ IProvideFluidHandleContext
670
735
  {
671
736
  /**
672
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
737
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
673
738
  */
674
739
  public get IFluidRouter() {
675
740
  return this;
676
741
  }
677
742
 
678
743
  /**
679
- * @deprecated - use loadRuntime instead.
744
+ * @deprecated use loadRuntime instead.
680
745
  * Load the stores from a snapshot and returns the runtime.
681
746
  * @param context - Context of the container.
682
747
  * @param registryEntries - Mapping to the stores.
@@ -703,10 +768,15 @@ export class ContainerRuntime
703
768
  context,
704
769
  registryEntries,
705
770
  existing: existingFlag,
706
- requestHandler,
707
771
  runtimeOptions,
708
772
  containerScope,
709
773
  containerRuntimeCtor,
774
+ requestHandler,
775
+ provideEntryPoint: () => {
776
+ throw new UsageError(
777
+ "ContainerRuntime.load is deprecated and should no longer be used",
778
+ );
779
+ },
710
780
  });
711
781
  }
712
782
 
@@ -722,7 +792,7 @@ export class ContainerRuntime
722
792
  * - containerScope - runtime services provided with context
723
793
  * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
724
794
  * 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.
795
+ * - provideEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
726
796
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
727
797
  */
728
798
  public static async loadRuntime(params: {
@@ -732,30 +802,21 @@ export class ContainerRuntime
732
802
  runtimeOptions?: IContainerRuntimeOptions;
733
803
  containerScope?: FluidObject;
734
804
  containerRuntimeCtor?: typeof ContainerRuntime;
805
+ /** @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md */
735
806
  requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
736
- initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
807
+ provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
737
808
  }): Promise<ContainerRuntime> {
738
809
  const {
739
810
  context,
740
811
  registryEntries,
741
812
  existing,
742
813
  requestHandler,
814
+ provideEntryPoint,
743
815
  runtimeOptions = {},
744
816
  containerScope = {},
745
817
  containerRuntimeCtor = ContainerRuntime,
746
818
  } = params;
747
819
 
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
820
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
760
821
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
761
822
  const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
@@ -884,15 +945,14 @@ export class ContainerRuntime
884
945
  blobManagerSnapshot,
885
946
  context.storage,
886
947
  idCompressor,
948
+ provideEntryPoint,
887
949
  requestHandler,
888
950
  undefined, // summaryConfiguration
889
- initializeEntryPoint,
890
951
  );
891
952
 
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);
953
+ // Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
954
+ // or zero. This must be done before Container replays saved ops.
955
+ await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
896
956
 
897
957
  // Initialize the base state of the runtime before it's returned.
898
958
  await runtime.initializeBaseState();
@@ -913,17 +973,6 @@ export class ContainerRuntime
913
973
  return this._storage;
914
974
  }
915
975
 
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
976
  private readonly submitFn: (
928
977
  type: MessageType,
929
978
  contents: any,
@@ -1175,6 +1224,7 @@ export class ContainerRuntime
1175
1224
  blobManagerSnapshot: IBlobManagerLoadInfo,
1176
1225
  private readonly _storage: IDocumentStorageService,
1177
1226
  idCompressor: (IIdCompressor & IIdCompressorCore) | undefined,
1227
+ provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1178
1228
  private readonly requestHandler?: (
1179
1229
  request: IRequest,
1180
1230
  runtime: IContainerRuntime,
@@ -1185,7 +1235,6 @@ export class ContainerRuntime
1185
1235
  // the runtime configuration overrides
1186
1236
  ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
1187
1237
  },
1188
- initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1189
1238
  ) {
1190
1239
  super();
1191
1240
 
@@ -1619,7 +1668,7 @@ export class ContainerRuntime
1619
1668
  this, // IConnectedState
1620
1669
  this.summaryCollection,
1621
1670
  this.logger,
1622
- this.formRequestSummarizerFn(loader),
1671
+ this.formCreateSummarizerFn(loader),
1623
1672
  new Throttler(
1624
1673
  60 * 1000, // 60 sec delay window
1625
1674
  30 * 1000, // 30 sec max delay
@@ -1638,35 +1687,6 @@ export class ContainerRuntime
1638
1687
  }
1639
1688
  }
1640
1689
 
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
1690
  // logging hardware telemetry
1671
1691
  logger.sendTelemetryEvent({
1672
1692
  eventName: "DeviceSpec",
@@ -1706,7 +1726,7 @@ export class ContainerRuntime
1706
1726
  );
1707
1727
  return this._summarizer;
1708
1728
  }
1709
- return initializeEntryPoint?.(this);
1729
+ return provideEntryPoint(this);
1710
1730
  });
1711
1731
  }
1712
1732
 
@@ -1747,14 +1767,14 @@ export class ContainerRuntime
1747
1767
  /**
1748
1768
  * Notifies this object about the request made to the container.
1749
1769
  * @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
1770
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
1751
1771
  */
1752
1772
  public async request(request: IRequest): Promise<IResponse> {
1753
1773
  try {
1754
1774
  const parser = RequestParser.create(request);
1755
1775
  const id = parser.pathParts[0];
1756
1776
 
1757
- if (id === "_summarizer" && parser.pathParts.length === 1) {
1777
+ if (id === summarizerRequestUrl && parser.pathParts.length === 1) {
1758
1778
  if (this._summarizer !== undefined) {
1759
1779
  return {
1760
1780
  status: 200,
@@ -1765,6 +1785,7 @@ export class ContainerRuntime
1765
1785
  return create404Response(request);
1766
1786
  }
1767
1787
  if (this.requestHandler !== undefined) {
1788
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1768
1789
  return this.requestHandler(parser, this);
1769
1790
  }
1770
1791
 
@@ -1784,6 +1805,7 @@ export class ContainerRuntime
1784
1805
  const id = requestParser.pathParts[0];
1785
1806
 
1786
1807
  if (id === "_channels") {
1808
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1787
1809
  return this.resolveHandle(requestParser.createSubRequest(1));
1788
1810
  }
1789
1811
 
@@ -1797,7 +1819,10 @@ export class ContainerRuntime
1797
1819
  }
1798
1820
  : create404Response(request);
1799
1821
  } else if (requestParser.pathParts.length > 0) {
1800
- const dataStore = await this.getDataStoreFromRequest(id, request);
1822
+ // Differentiate between requesting the dataStore directly, or one of its children
1823
+ const requestForChild = !requestParser.isLeaf(1);
1824
+ const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
1825
+
1801
1826
  const subRequest = requestParser.createSubRequest(1);
1802
1827
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
1803
1828
  // unintentionally modifying the url if that changes.
@@ -1805,6 +1830,7 @@ export class ContainerRuntime
1805
1830
  subRequest.url.startsWith("/"),
1806
1831
  0x126 /* "Expected createSubRequest url to include a leading slash" */,
1807
1832
  );
1833
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1808
1834
  return dataStore.request(subRequest);
1809
1835
  }
1810
1836
 
@@ -1817,16 +1843,20 @@ export class ContainerRuntime
1817
1843
  /**
1818
1844
  * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
1819
1845
  */
1820
- public async getEntryPoint?(): Promise<FluidObject | undefined> {
1846
+ public async getEntryPoint(): Promise<FluidObject> {
1821
1847
  return this.entryPoint;
1822
1848
  }
1823
- private readonly entryPoint: LazyPromise<FluidObject | undefined>;
1849
+ private readonly entryPoint: LazyPromise<FluidObject>;
1824
1850
 
1825
1851
  private internalId(maybeAlias: string): string {
1826
1852
  return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
1827
1853
  }
1828
1854
 
1829
- private async getDataStoreFromRequest(id: string, request: IRequest): Promise<IFluidRouter> {
1855
+ private async getDataStoreFromRequest(
1856
+ id: string,
1857
+ request: IRequest,
1858
+ requestForChild: boolean,
1859
+ ): Promise<IFluidDataStoreChannel> {
1830
1860
  const headerData: RuntimeHeaderData = {};
1831
1861
  if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
1832
1862
  headerData.wait = request.headers[RuntimeHeaders.wait];
@@ -1838,6 +1868,11 @@ export class ContainerRuntime
1838
1868
  headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
1839
1869
  }
1840
1870
 
1871
+ // We allow Tombstone requests for sub-DataStore objects
1872
+ if (requestForChild) {
1873
+ headerData.allowTombstone = true;
1874
+ }
1875
+
1841
1876
  await this.dataStores.waitIfPendingAlias(id);
1842
1877
  const internalId = this.internalId(id);
1843
1878
  const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
@@ -2015,28 +2050,28 @@ export class ContainerRuntime
2015
2050
  * Parse an op's type and actual content from given serialized content
2016
2051
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
2017
2052
  */
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 };
2053
+ // TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
2054
+ private parseLocalOpContent(serializedContents?: string): LocalContainerRuntimeMessage {
2055
+ assert(serializedContents !== undefined, 0x6d5 /* content must be defined */);
2056
+ const message: LocalContainerRuntimeMessage = JSON.parse(serializedContents);
2057
+ assert(message.type !== undefined, 0x6d6 /* incorrect op content format */);
2058
+ return message;
2024
2059
  }
2025
2060
 
2026
- private async applyStashedOp(op: string): Promise<unknown> {
2061
+ private async applyStashedOp(serializedOpContent: string): Promise<unknown> {
2027
2062
  // Need to parse from string for back-compat
2028
- const { type, contents, compatDetails } = this.parseOpContent(op);
2029
- switch (type) {
2063
+ const opContents = this.parseLocalOpContent(serializedOpContent);
2064
+ switch (opContents.type) {
2030
2065
  case ContainerMessageType.FluidDataStoreOp:
2031
- return this.dataStores.applyStashedOp(contents as IEnvelope);
2066
+ return this.dataStores.applyStashedOp(opContents.contents);
2032
2067
  case ContainerMessageType.Attach:
2033
- return this.dataStores.applyStashedAttachOp(contents as IAttachMessage);
2068
+ return this.dataStores.applyStashedAttachOp(opContents.contents);
2034
2069
  case ContainerMessageType.IdAllocation:
2035
2070
  assert(
2036
2071
  this.idCompressor !== undefined,
2037
2072
  0x67b /* IdCompressor should be defined if enabled */,
2038
2073
  );
2039
- return this.applyStashedIdAllocationOp(contents as IdCreationRangeWithStashedState);
2074
+ return this.applyStashedIdAllocationOp(opContents.contents);
2040
2075
  case ContainerMessageType.Alias:
2041
2076
  case ContainerMessageType.BlobAttach:
2042
2077
  return;
@@ -2048,15 +2083,15 @@ export class ContainerRuntime
2048
2083
  // This should be extremely rare for stashed ops.
2049
2084
  // It would require a newer runtime stashing ops and then an older one applying them,
2050
2085
  // e.g. if an app rolled back its container version
2051
- const compatBehavior = compatDetails?.behavior;
2052
- if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
2086
+ const compatBehavior = opContents.compatDetails?.behavior;
2087
+ if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
2053
2088
  const error = DataProcessingError.create(
2054
2089
  "Stashed runtime message of unknown type",
2055
2090
  "applyStashedOp",
2056
2091
  undefined /* sequencedMessage */,
2057
2092
  {
2058
2093
  messageDetails: JSON.stringify({
2059
- type,
2094
+ type: opContents.type,
2060
2095
  compatBehavior,
2061
2096
  }),
2062
2097
  },
@@ -2078,6 +2113,30 @@ export class ContainerRuntime
2078
2113
  return;
2079
2114
  }
2080
2115
 
2116
+ // If there are stashed blobs in the pending state, we need to delay
2117
+ // propagation of the "connected" event until we have uploaded them to
2118
+ // ensure we don't submit ops referencing a blob that has not been uploaded
2119
+ const connecting = connected && !this._connected;
2120
+ if (connecting && this.blobManager.hasPendingStashedBlobs()) {
2121
+ assert(
2122
+ !this.delayConnectClientId,
2123
+ 0x791 /* Connect event delay must be canceled before subsequent connect event */,
2124
+ );
2125
+ assert(!!clientId, 0x792 /* Must have clientId when connecting */);
2126
+ this.delayConnectClientId = clientId;
2127
+ this.blobManager.processStashedChanges().then(
2128
+ () => {
2129
+ // make sure we didn't reconnect before the promise resolved
2130
+ if (this.delayConnectClientId === clientId && !this.disposed) {
2131
+ this.delayConnectClientId = undefined;
2132
+ this.setConnectionStateCore(connected, clientId);
2133
+ }
2134
+ },
2135
+ (error) => this.closeFn(error),
2136
+ );
2137
+ return;
2138
+ }
2139
+
2081
2140
  this.setConnectionStateCore(connected, clientId);
2082
2141
  }
2083
2142
 
@@ -2156,9 +2215,25 @@ export class ContainerRuntime
2156
2215
  const modernRuntimeMessage = messageArg.type === MessageType.Operation;
2157
2216
 
2158
2217
  // Do shallow copy of message, as the processing flow will modify it.
2218
+ // There might be multiple container instances receiving the same message.
2219
+ // We do not need to make a deep copy. Each layer will just replace message.contents itself,
2220
+ // but will not modify the contents object (likely it will replace it on the message).
2159
2221
  const messageCopy = { ...messageArg };
2160
2222
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
2161
- this.processCore(message, local, modernRuntimeMessage);
2223
+ if (modernRuntimeMessage) {
2224
+ this.processCore({
2225
+ // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
2226
+ // There is nothing really ensuring that anytime original message.type is Operation that
2227
+ // the result messages will be so. In the end modern bool being true only directs to
2228
+ // throw error if ultimately unrecognized without compat details saying otherwise.
2229
+ message: message as InboundSequencedContainerRuntimeMessage,
2230
+ local,
2231
+ modernRuntimeMessage,
2232
+ });
2233
+ } else {
2234
+ // Unrecognized message will be ignored.
2235
+ this.processCore({ message, local, modernRuntimeMessage });
2236
+ }
2162
2237
  }
2163
2238
  }
2164
2239
 
@@ -2166,15 +2241,9 @@ export class ContainerRuntime
2166
2241
 
2167
2242
  /**
2168
2243
  * 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
- ) {
2244
+ */
2245
+ private processCore(messageWithContext: MessageWithContext) {
2246
+ const { message, local } = messageWithContext;
2178
2247
  // Surround the actual processing of the operation with messages to the schedule manager indicating
2179
2248
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
2180
2249
  // messages once a batch has been fully processed.
@@ -2184,9 +2253,13 @@ export class ContainerRuntime
2184
2253
 
2185
2254
  try {
2186
2255
  let localOpMetadata: unknown;
2187
- if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
2256
+ if (
2257
+ local &&
2258
+ messageWithContext.modernRuntimeMessage &&
2259
+ message.type !== ContainerMessageType.ChunkedOp
2260
+ ) {
2188
2261
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
2189
- message as SequencedContainerRuntimeMessage,
2262
+ messageWithContext.message,
2190
2263
  );
2191
2264
  }
2192
2265
 
@@ -2196,14 +2269,9 @@ export class ContainerRuntime
2196
2269
  this.updateDocumentDirtyState(false);
2197
2270
  }
2198
2271
 
2199
- this.validateAndProcessRuntimeMessage(
2200
- message,
2201
- localOpMetadata,
2202
- local,
2203
- modernRuntimeMessage,
2204
- );
2272
+ this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
2205
2273
 
2206
- this.emit("op", message, modernRuntimeMessage);
2274
+ this.emit("op", message, messageWithContext.modernRuntimeMessage);
2207
2275
 
2208
2276
  this.scheduleManager.afterOpProcessing(undefined, message);
2209
2277
 
@@ -2219,39 +2287,43 @@ export class ContainerRuntime
2219
2287
  }
2220
2288
  }
2221
2289
  /**
2222
- * Assuming the given message is also a ContainerRuntimeMessage,
2290
+ * Assuming the given message is also a TypedContainerRuntimeMessage,
2223
2291
  * 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.
2292
+ * Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
2225
2293
  */
2226
2294
  private validateAndProcessRuntimeMessage(
2227
- message: ISequencedDocumentMessage,
2295
+ messageWithContext: MessageWithContext,
2228
2296
  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) {
2297
+ ): void {
2298
+ // TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
2299
+ const { local } = messageWithContext;
2300
+ switch (messageWithContext.message.type) {
2237
2301
  case ContainerMessageType.Attach:
2238
- this.dataStores.processAttachMessage(message, local);
2302
+ this.dataStores.processAttachMessage(messageWithContext.message, local);
2239
2303
  break;
2240
2304
  case ContainerMessageType.Alias:
2241
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
2305
+ this.dataStores.processAliasMessage(
2306
+ messageWithContext.message,
2307
+ localOpMetadata,
2308
+ local,
2309
+ );
2242
2310
  break;
2243
2311
  case ContainerMessageType.FluidDataStoreOp:
2244
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
2312
+ this.dataStores.processFluidDataStoreOp(
2313
+ messageWithContext.message,
2314
+ local,
2315
+ localOpMetadata,
2316
+ );
2245
2317
  break;
2246
2318
  case ContainerMessageType.BlobAttach:
2247
- this.blobManager.processBlobAttachOp(message, local);
2319
+ this.blobManager.processBlobAttachOp(messageWithContext.message, local);
2248
2320
  break;
2249
2321
  case ContainerMessageType.IdAllocation:
2250
2322
  assert(
2251
2323
  this.idCompressor !== undefined,
2252
2324
  0x67c /* IdCompressor should be defined if enabled */,
2253
2325
  );
2254
- this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
2326
+ this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
2255
2327
  break;
2256
2328
  case ContainerMessageType.ChunkedOp:
2257
2329
  case ContainerMessageType.Rejoin:
@@ -2259,12 +2331,18 @@ export class ContainerRuntime
2259
2331
  default: {
2260
2332
  // If we didn't necessarily expect a runtime message type, then no worries - just return
2261
2333
  // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
2262
- if (!expectRuntimeMessageType) {
2334
+ if (!messageWithContext.modernRuntimeMessage) {
2263
2335
  return;
2264
2336
  }
2265
2337
 
2266
- const compatBehavior = compatDetails?.behavior;
2267
- if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
2338
+ const compatBehavior = messageWithContext.message.compatDetails?.behavior;
2339
+ if (
2340
+ !compatBehaviorAllowsMessageType(
2341
+ messageWithContext.message.type,
2342
+ compatBehavior,
2343
+ )
2344
+ ) {
2345
+ const { message } = messageWithContext;
2268
2346
  const error = DataProcessingError.create(
2269
2347
  // Former assert 0x3ce
2270
2348
  "Runtime message of unknown type",
@@ -2354,8 +2432,9 @@ export class ContainerRuntime
2354
2432
  * Returns the runtime of the data store.
2355
2433
  * @param id - Id supplied during creating the data store.
2356
2434
  * @param wait - True if you want to wait for it.
2357
- * @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
2435
+ * @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
2358
2436
  */
2437
+ // eslint-disable-next-line import/no-deprecated
2359
2438
  public async getRootDataStore(id: string, wait = true): Promise<IFluidRouter> {
2360
2439
  return this.getRootDataStoreChannel(id, wait);
2361
2440
  }
@@ -2535,7 +2614,7 @@ export class ContainerRuntime
2535
2614
  return this.dirtyContainer;
2536
2615
  }
2537
2616
 
2538
- private isContainerMessageDirtyable({ type, contents }: ContainerRuntimeMessage) {
2617
+ private isContainerMessageDirtyable({ type, contents }: OutboundContainerRuntimeMessage) {
2539
2618
  // For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
2540
2619
  // Ultimately we should have no special-cases from the ContainerRuntime's perspective.
2541
2620
  if (type === ContainerMessageType.Attach) {
@@ -2544,7 +2623,7 @@ export class ContainerRuntime
2544
2623
  return false;
2545
2624
  }
2546
2625
  } else if (type === ContainerMessageType.FluidDataStoreOp) {
2547
- const envelope = contents as IEnvelope;
2626
+ const envelope = contents;
2548
2627
  if (envelope.address === agentSchedulerId) {
2549
2628
  return false;
2550
2629
  }
@@ -2788,7 +2867,7 @@ export class ContainerRuntime
2788
2867
  }
2789
2868
 
2790
2869
  /**
2791
- * @deprecated - Replaced by deleteSweepReadyNodes.
2870
+ * @deprecated Replaced by deleteSweepReadyNodes.
2792
2871
  */
2793
2872
  public deleteUnusedNodes(unusedRoutes: string[]): string[] {
2794
2873
  throw new Error("deleteUnusedRoutes should not be called");
@@ -2937,19 +3016,15 @@ export class ContainerRuntime
2937
3016
 
2938
3017
  assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
2939
3018
 
3019
+ // We close the summarizer and download a new snapshot and reload the container
2940
3020
  let latestSnapshotVersionId: string | undefined;
2941
- if (refreshLatestAck) {
2942
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(
3021
+ if (refreshLatestAck === true) {
3022
+ return this.prefetchLatestSummaryThenClose(
2943
3023
  createChildLogger({
2944
3024
  logger: summaryNumberLogger,
2945
3025
  properties: { all: { safeSummary: true } },
2946
3026
  }),
2947
3027
  );
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
3028
  }
2954
3029
 
2955
3030
  // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
@@ -3397,7 +3472,7 @@ export class ContainerRuntime
3397
3472
  }
3398
3473
 
3399
3474
  if (idRange !== undefined) {
3400
- const idAllocationMessage: ContainerRuntimeMessage = {
3475
+ const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
3401
3476
  type: ContainerMessageType.IdAllocation,
3402
3477
  contents: idRange,
3403
3478
  };
@@ -3417,7 +3492,7 @@ export class ContainerRuntime
3417
3492
  }
3418
3493
 
3419
3494
  private submit(
3420
- containerRuntimeMessage: ContainerRuntimeMessage,
3495
+ containerRuntimeMessage: OutboundContainerRuntimeMessage,
3421
3496
  localOpMetadata: unknown = undefined,
3422
3497
  metadata: Record<string, unknown> | undefined = undefined,
3423
3498
  ): void {
@@ -3613,39 +3688,36 @@ export class ContainerRuntime
3613
3688
 
3614
3689
  private reSubmit(message: IPendingBatchMessage) {
3615
3690
  // Need to parse from string for back-compat
3616
- const containerRuntimeMessage = this.parseOpContent(message.content);
3691
+ const containerRuntimeMessage = this.parseLocalOpContent(message.content);
3617
3692
  this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
3618
3693
  }
3619
3694
 
3620
3695
  /**
3621
3696
  * Finds the right store and asks it to resubmit the message. This typically happens when we
3622
3697
  * reconnect and there are pending messages.
3623
- * @param message - The original ContainerRuntimeMessage.
3698
+ * @param message - The original LocalContainerRuntimeMessage.
3624
3699
  * @param localOpMetadata - The local metadata associated with the original message.
3625
3700
  */
3626
3701
  private reSubmitCore(
3627
- message: ContainerRuntimeMessage,
3702
+ message: LocalContainerRuntimeMessage,
3628
3703
  localOpMetadata: unknown,
3629
3704
  opMetadata: Record<string, unknown> | undefined,
3630
3705
  ) {
3631
- const contents = message.contents;
3632
3706
  switch (message.type) {
3633
3707
  case ContainerMessageType.FluidDataStoreOp:
3634
3708
  // For Operations, call resubmitDataStoreOp which will find the right store
3635
3709
  // and trigger resubmission on it.
3636
- this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
3710
+ this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
3637
3711
  break;
3638
3712
  case ContainerMessageType.Attach:
3639
3713
  case ContainerMessageType.Alias:
3640
3714
  this.submit(message, localOpMetadata);
3641
3715
  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
- }
3716
+ case ContainerMessageType.IdAllocation: {
3717
+ prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
3647
3718
  this.submit(message, localOpMetadata);
3648
3719
  break;
3720
+ }
3649
3721
  case ContainerMessageType.ChunkedOp:
3650
3722
  throw new Error(`chunkedOp not expected here`);
3651
3723
  case ContainerMessageType.BlobAttach:
@@ -3684,12 +3756,12 @@ export class ContainerRuntime
3684
3756
 
3685
3757
  private rollback(content: string | undefined, localOpMetadata: unknown) {
3686
3758
  // Need to parse from string for back-compat
3687
- const { type, contents } = this.parseOpContent(content);
3759
+ const { type, contents } = this.parseLocalOpContent(content);
3688
3760
  switch (type) {
3689
3761
  case ContainerMessageType.FluidDataStoreOp:
3690
3762
  // For operations, call rollbackDataStoreOp which will find the right store
3691
3763
  // and trigger rollback on it.
3692
- this.dataStores.rollbackDataStoreOp(contents as IEnvelope, localOpMetadata);
3764
+ this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
3693
3765
  break;
3694
3766
  default:
3695
3767
  // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
@@ -3697,26 +3769,6 @@ export class ContainerRuntime
3697
3769
  }
3698
3770
  }
3699
3771
 
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
3772
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
3721
3773
  public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions) {
3722
3774
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
@@ -3735,7 +3787,7 @@ export class ContainerRuntime
3735
3787
  * and then close as the current main client is likely to be re-elected as the parent summarizer again.
3736
3788
  */
3737
3789
  if (!result.isSummaryTracked && result.isSummaryNewer) {
3738
- const fetchResult = await this.fetchSnapshotFromStorage(
3790
+ const fetchResult = await this.fetchLatestSnapshotFromStorage(
3739
3791
  summaryLogger,
3740
3792
  {
3741
3793
  eventName: "RefreshLatestSummaryAckFetch",
@@ -3743,7 +3795,6 @@ export class ContainerRuntime
3743
3795
  targetSequenceNumber: summaryRefSeq,
3744
3796
  },
3745
3797
  readAndParseBlob,
3746
- null,
3747
3798
  );
3748
3799
 
3749
3800
  /**
@@ -3780,40 +3831,37 @@ export class ContainerRuntime
3780
3831
  }
3781
3832
 
3782
3833
  /**
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.
3834
+ * Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
3835
+ * summarizer to reload from new state.
3785
3836
  * @param summaryLogger - logger to use when fetching snapshot from storage
3786
- * @returns downloaded snapshot's reference sequence number
3837
+ * @returns a generic summarization error
3787
3838
  */
3788
- private async refreshLatestSummaryAckFromServer(
3839
+ private async prefetchLatestSummaryThenClose(
3789
3840
  summaryLogger: ITelemetryLoggerExt,
3790
- ): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
3841
+ ): Promise<IBaseSummarizeResult> {
3791
3842
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3792
- const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(
3843
+
3844
+ // This is a performance optimization as the same parent is likely to be elected again, and would use its
3845
+ // cache to fetch the snapshot instead of the network.
3846
+ await this.fetchLatestSnapshotFromStorage(
3793
3847
  summaryLogger,
3794
3848
  {
3795
3849
  eventName: "RefreshLatestSummaryFromServerFetch",
3796
3850
  },
3797
3851
  readAndParseBlob,
3798
- null,
3799
3852
  );
3800
3853
 
3801
3854
  await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
3802
3855
 
3803
- return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
3856
+ return {
3857
+ stage: "base",
3858
+ error: "summary state stale - Unsupported option 'refreshLatestAck'",
3859
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
3860
+ minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
3861
+ };
3804
3862
  }
3805
3863
 
3806
3864
  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
3865
  // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
3818
3866
  await delay(this.closeSummarizerDelayMs);
3819
3867
  this._summarizer?.stop("latestSummaryStateStale");
@@ -3821,15 +3869,14 @@ export class ContainerRuntime
3821
3869
  }
3822
3870
 
3823
3871
  /**
3824
- * Downloads snapshot from storage with the given versionId or latest if versionId is null.
3872
+ * Downloads the latest snapshot from storage.
3825
3873
  * By default, it also closes the container after downloading the snapshot. However, this may be
3826
3874
  * overridden via options.
3827
3875
  */
3828
- private async fetchSnapshotFromStorage(
3876
+ private async fetchLatestSnapshotFromStorage(
3829
3877
  logger: ITelemetryLoggerExt,
3830
3878
  event: ITelemetryGenericEvent,
3831
3879
  readAndParseBlob: ReadAndParseBlob,
3832
- versionId: string | null,
3833
3880
  ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3834
3881
  return PerformanceEvent.timedExecAsync(
3835
3882
  logger,
@@ -3851,10 +3898,10 @@ export class ContainerRuntime
3851
3898
  const trace = Trace.start();
3852
3899
 
3853
3900
  const versions = await this.storage.getVersions(
3854
- versionId,
3901
+ null,
3855
3902
  1,
3856
- "refreshLatestSummaryAckFromServer",
3857
- versionId === null ? FetchSource.noCache : undefined,
3903
+ "prefetchLatestSummaryBeforeClose",
3904
+ FetchSource.noCache,
3858
3905
  );
3859
3906
  assert(
3860
3907
  !!versions && !!versions[0],
@@ -3896,17 +3943,17 @@ export class ContainerRuntime
3896
3943
  if (this._orderSequentiallyCalls !== 0) {
3897
3944
  throw new UsageError("can't get state during orderSequentially");
3898
3945
  }
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
3946
  // Flush pending batch.
3907
3947
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
3908
3948
  // to close current batch.
3909
3949
  this.flush();
3950
+ const pendingAttachmentBlobs = waitBlobsToAttach
3951
+ ? await this.blobManager.attachAndGetPendingBlobs()
3952
+ : undefined;
3953
+ const pending = this.pendingStateManager.getLocalState();
3954
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
3955
+ return; // no pending state to save
3956
+ }
3910
3957
 
3911
3958
  const pendingState: IPendingRuntimeState = {
3912
3959
  pending,
@@ -3948,35 +3995,11 @@ export class ContainerRuntime
3948
3995
  }
3949
3996
 
3950
3997
  /**
3951
- * * Forms a function that will request a Summarizer.
3952
- * @param loaderRouter - the loader acting as an IFluidRouter
3953
- * */
3954
- private formRequestSummarizerFn(loaderRouter: IFluidRouter) {
3998
+ * Forms a function that will create and retrieve a Summarizer.
3999
+ */
4000
+ private formCreateSummarizerFn(loader: ILoader) {
3955
4001
  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;
4002
+ return createSummarizer(loader, `/${summarizerRequestUrl}`);
3980
4003
  };
3981
4004
  }
3982
4005
 
@@ -4003,30 +4026,3 @@ export class ContainerRuntime
4003
4026
  return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
4004
4027
  }
4005
4028
  }
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
- });