@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
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -19,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
19
23
  return result;
20
24
  };
21
25
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
26
+ exports.ContainerRuntime = exports.TEST_requestSummarizer = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = void 0;
23
27
  const container_definitions_1 = require("@fluidframework/container-definitions");
24
28
  const core_utils_1 = require("@fluidframework/core-utils");
25
29
  const client_utils_1 = require("@fluid-internal/client-utils");
@@ -45,32 +49,12 @@ const batchTracker_1 = require("./batchTracker");
45
49
  const scheduleManager_1 = require("./scheduleManager");
46
50
  const opLifecycle_1 = require("./opLifecycle");
47
51
  const deltaManagerSummarizerProxy_1 = require("./deltaManagerSummarizerProxy");
48
- var ContainerMessageType;
49
- (function (ContainerMessageType) {
50
- // An op to be delivered to store
51
- ContainerMessageType["FluidDataStoreOp"] = "component";
52
- // Creates a new store
53
- ContainerMessageType["Attach"] = "attach";
54
- // Chunked operation.
55
- ContainerMessageType["ChunkedOp"] = "chunkedOp";
56
- // Signifies that a blob has been attached and should not be garbage collected by storage
57
- ContainerMessageType["BlobAttach"] = "blobAttach";
58
- // Ties our new clientId to our old one on reconnect
59
- ContainerMessageType["Rejoin"] = "rejoin";
60
- // Sets the alias of a root data store
61
- ContainerMessageType["Alias"] = "alias";
62
- /**
63
- * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
64
- * the last allocation op was sent.
65
- * See the [IdCompressor README](./id-compressor/README.md) for more details.
66
- */
67
- ContainerMessageType["IdAllocation"] = "idAllocation";
68
- })(ContainerMessageType = exports.ContainerMessageType || (exports.ContainerMessageType = {}));
52
+ const messageTypes_1 = require("./messageTypes");
69
53
  /**
70
54
  * Utility to implement compat behaviors given an unknown message type
71
55
  * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
72
56
  *
73
- * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
57
+ * @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
74
58
  * handled before calling this function (e.g. in a switch statement).
75
59
  * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
76
60
  */
@@ -78,6 +62,15 @@ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, co
78
62
  // undefined defaults to same behavior as "FailToProcess"
79
63
  return compatBehavior === "Ignore";
80
64
  }
65
+ function prepareLocalContainerRuntimeIdAllocationMessageForTransit(message) {
66
+ // Remove the stashedState from the op if it's a stashed op
67
+ if ("stashedState" in message.contents) {
68
+ delete message.contents.stashedState;
69
+ }
70
+ }
71
+ /**
72
+ * @public
73
+ */
81
74
  exports.DefaultSummaryConfiguration = {
82
75
  state: "enabled",
83
76
  minIdleTime: 0,
@@ -94,6 +87,7 @@ exports.DefaultSummaryConfiguration = {
94
87
  };
95
88
  /**
96
89
  * Accepted header keys for requests coming to the runtime.
90
+ * @public
97
91
  */
98
92
  var RuntimeHeaders;
99
93
  (function (RuntimeHeaders) {
@@ -101,14 +95,25 @@ var RuntimeHeaders;
101
95
  RuntimeHeaders["wait"] = "wait";
102
96
  /** True if the request is coming from an IFluidHandle. */
103
97
  RuntimeHeaders["viaHandle"] = "viaHandle";
104
- })(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
105
- /** True if a tombstoned object should be returned without erroring */
98
+ })(RuntimeHeaders || (exports.RuntimeHeaders = RuntimeHeaders = {}));
99
+ /** True if a tombstoned object should be returned without erroring
100
+ * @public
101
+ */
106
102
  exports.AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
107
- /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
103
+ /**
104
+ * [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
105
+ * @public
106
+ */
108
107
  exports.AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
109
- /** Tombstone error responses will have this header set to true */
108
+ /**
109
+ * Tombstone error responses will have this header set to true
110
+ * @public
111
+ */
110
112
  exports.TombstoneResponseHeaderKey = "isTombstoned";
111
- /** Inactive error responses will have this header set to true */
113
+ /**
114
+ * Inactive error responses will have this header set to true
115
+ * @public
116
+ */
112
117
  exports.InactiveResponseHeaderKey = "isInactive";
113
118
  /** Default values for Runtime Headers */
114
119
  exports.defaultRuntimeHeaderData = {
@@ -118,11 +123,12 @@ exports.defaultRuntimeHeaderData = {
118
123
  };
119
124
  /**
120
125
  * Available compression algorithms for op compression.
126
+ * @public
121
127
  */
122
128
  var CompressionAlgorithms;
123
129
  (function (CompressionAlgorithms) {
124
130
  CompressionAlgorithms["lz4"] = "lz4";
125
- })(CompressionAlgorithms = exports.CompressionAlgorithms || (exports.CompressionAlgorithms = {}));
131
+ })(CompressionAlgorithms || (exports.CompressionAlgorithms = CompressionAlgorithms = {}));
126
132
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
127
133
  const defaultFlushMode = runtime_definitions_1.FlushMode.TurnBased;
128
134
  // The actual limit is 1Mb (socket.io and Kafka limits)
@@ -147,7 +153,8 @@ exports.defaultPendingOpsRetryDelayMs = 1000;
147
153
  */
148
154
  const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
149
155
  /**
150
- * @deprecated - use ContainerRuntimeMessage instead
156
+ * @deprecated use ContainerRuntimeMessageType instead
157
+ * @public
151
158
  */
152
159
  var RuntimeMessage;
153
160
  (function (RuntimeMessage) {
@@ -158,9 +165,10 @@ var RuntimeMessage;
158
165
  RuntimeMessage["Rejoin"] = "rejoin";
159
166
  RuntimeMessage["Alias"] = "alias";
160
167
  RuntimeMessage["Operation"] = "op";
161
- })(RuntimeMessage = exports.RuntimeMessage || (exports.RuntimeMessage = {}));
168
+ })(RuntimeMessage || (exports.RuntimeMessage = RuntimeMessage = {}));
162
169
  /**
163
- * @deprecated - please use version in driver-utils
170
+ * @deprecated please use version in driver-utils
171
+ * @public
164
172
  */
165
173
  function isRuntimeMessage(message) {
166
174
  return Object.values(RuntimeMessage).includes(message.type);
@@ -170,6 +178,7 @@ exports.isRuntimeMessage = isRuntimeMessage;
170
178
  * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
171
179
  * special-case for document dirty state. Ultimately we should have no special-cases from the
172
180
  * ContainerRuntime's perspective.
181
+ * @public
173
182
  */
174
183
  exports.agentSchedulerId = "_scheduler";
175
184
  // safely check navigator and get the hardware spec value
@@ -201,20 +210,277 @@ const makeLegacySendBatchFn = (submitFn, deltaManager) => (batch) => {
201
210
  deltaManager.flush();
202
211
  };
203
212
  exports.makeLegacySendBatchFn = makeLegacySendBatchFn;
213
+ const summarizerRequestUrl = "_summarizer";
214
+ /**
215
+ * Create and retrieve the summmarizer
216
+ */
217
+ async function createSummarizer(loader, url) {
218
+ const request = {
219
+ headers: {
220
+ [container_definitions_1.LoaderHeader.cache]: false,
221
+ [container_definitions_1.LoaderHeader.clientDetails]: {
222
+ capabilities: { interactive: false },
223
+ type: summary_1.summarizerClientType,
224
+ },
225
+ [driver_definitions_1.DriverHeader.summarizingClient]: true,
226
+ [container_definitions_1.LoaderHeader.reconnect]: false,
227
+ },
228
+ url,
229
+ };
230
+ const resolvedContainer = await loader.resolve(request);
231
+ let fluidObject;
232
+ // Older containers may not have the "getEntryPoint" API
233
+ // ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
234
+ if (resolvedContainer.getEntryPoint !== undefined) {
235
+ fluidObject = await resolvedContainer.getEntryPoint();
236
+ }
237
+ else {
238
+ const response = await resolvedContainer.request({ url: `/${summarizerRequestUrl}` });
239
+ if (response.status !== 200 || response.mimeType !== "fluid/object") {
240
+ throw (0, runtime_utils_1.responseToException)(response, request);
241
+ }
242
+ fluidObject = response.value;
243
+ }
244
+ if (fluidObject?.ISummarizer === undefined) {
245
+ throw new telemetry_utils_1.UsageError("Fluid object does not implement ISummarizer");
246
+ }
247
+ return fluidObject.ISummarizer;
248
+ }
249
+ /**
250
+ * This function is not supported publicly and exists for e2e testing
251
+ * @internal
252
+ */
253
+ async function TEST_requestSummarizer(loader, url) {
254
+ return createSummarizer(loader, url);
255
+ }
256
+ exports.TEST_requestSummarizer = TEST_requestSummarizer;
204
257
  /**
205
258
  * Represents the runtime of the container. Contains helper functions/state of the container.
206
259
  * It will define the store level mappings.
260
+ * @public
207
261
  */
208
262
  class ContainerRuntime extends client_utils_1.TypedEventEmitter {
263
+ /**
264
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
265
+ */
266
+ get IFluidRouter() {
267
+ return this;
268
+ }
269
+ /**
270
+ * @deprecated use loadRuntime instead.
271
+ * Load the stores from a snapshot and returns the runtime.
272
+ * @param context - Context of the container.
273
+ * @param registryEntries - Mapping to the stores.
274
+ * @param requestHandler - Request handlers for the container runtime
275
+ * @param runtimeOptions - Additional options to be passed to the runtime
276
+ * @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
277
+ * @param containerRuntimeCtor - (optional) Constructor to use to create the ContainerRuntime instance. This
278
+ * allows mixin classes to leverage this method to define their own async initializer.
279
+ */
280
+ static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
281
+ let existingFlag = true;
282
+ if (!existing) {
283
+ existingFlag = false;
284
+ }
285
+ return this.loadRuntime({
286
+ context,
287
+ registryEntries,
288
+ existing: existingFlag,
289
+ runtimeOptions,
290
+ containerScope,
291
+ containerRuntimeCtor,
292
+ requestHandler,
293
+ provideEntryPoint: () => {
294
+ throw new telemetry_utils_1.UsageError("ContainerRuntime.load is deprecated and should no longer be used");
295
+ },
296
+ });
297
+ }
298
+ /**
299
+ * Load the stores from a snapshot and returns the runtime.
300
+ * @param params - An object housing the runtime properties:
301
+ * - context - Context of the container.
302
+ * - registryEntries - Mapping from data store types to their corresponding factories.
303
+ * - existing - Pass 'true' if loading from an existing snapshot.
304
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
305
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
306
+ * - runtimeOptions - Additional options to be passed to the runtime
307
+ * - containerScope - runtime services provided with context
308
+ * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
309
+ * This allows mixin classes to leverage this method to define their own async initializer.
310
+ * - provideEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
311
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
312
+ */
313
+ static async loadRuntime(params) {
314
+ const { context, registryEntries, existing, requestHandler, provideEntryPoint, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
315
+ // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
316
+ // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
317
+ const backCompatContext = context;
318
+ const passLogger = backCompatContext.taggedLogger ??
319
+ // eslint-disable-next-line import/no-deprecated
320
+ new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
321
+ const logger = (0, telemetry_utils_1.createChildLogger)({
322
+ logger: passLogger,
323
+ properties: {
324
+ all: {
325
+ runtimeVersion: packageVersion_1.pkgVersion,
326
+ },
327
+ },
328
+ });
329
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
330
+ const registry = new dataStoreRegistry_1.FluidDataStoreRegistry(registryEntries);
331
+ const tryFetchBlob = async (blobName) => {
332
+ const blobId = context.baseSnapshot?.blobs[blobName];
333
+ if (context.baseSnapshot && blobId) {
334
+ // IContainerContext storage api return type still has undefined in 0.39 package version.
335
+ // So once we release 0.40 container-defn package we can remove this check.
336
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
337
+ return (0, driver_utils_1.readAndParse)(context.storage, blobId);
338
+ }
339
+ };
340
+ const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
341
+ tryFetchBlob(summary_1.chunksBlobName),
342
+ tryFetchBlob(summary_1.metadataBlobName),
343
+ tryFetchBlob(summary_1.electedSummarizerBlobName),
344
+ tryFetchBlob(summary_1.aliasBlobName),
345
+ tryFetchBlob(summary_1.idCompressorBlobName),
346
+ ]);
347
+ // read snapshot blobs needed for BlobManager to load
348
+ const blobManagerSnapshot = await blobManager_1.BlobManager.load(context.baseSnapshot?.trees[summary_1.blobsTreeName], async (id) => {
349
+ // IContainerContext storage api return type still has undefined in 0.39 package version.
350
+ // So once we release 0.40 container-defn package we can remove this check.
351
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
352
+ return (0, driver_utils_1.readAndParse)(context.storage, id);
353
+ });
354
+ // Verify summary runtime sequence number matches protocol sequence number.
355
+ const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
356
+ // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
357
+ if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
358
+ const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
359
+ // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
360
+ if (loadSequenceNumberVerification !== "bypass" &&
361
+ runtimeSequenceNumber !== protocolSequenceNumber) {
362
+ // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
363
+ const error = new telemetry_utils_1.DataCorruptionError(
364
+ // pre-0.58 error message: SummaryMetadataMismatch
365
+ "Summary metadata mismatch", { runtimeVersion: packageVersion_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
366
+ if (loadSequenceNumberVerification === "log") {
367
+ logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
368
+ }
369
+ else {
370
+ context.closeFn(error);
371
+ }
372
+ }
373
+ }
374
+ const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
375
+ let idCompressor;
376
+ if (idCompressorEnabled) {
377
+ const { IdCompressor, createSessionId } = await Promise.resolve().then(() => __importStar(require("./id-compressor")));
378
+ idCompressor =
379
+ serializedIdCompressor !== undefined
380
+ ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
381
+ : IdCompressor.create(logger);
382
+ }
383
+ const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
384
+ summaryOptions,
385
+ gcOptions,
386
+ loadSequenceNumberVerification,
387
+ flushMode,
388
+ compressionOptions,
389
+ maxBatchSizeInBytes,
390
+ chunkSizeInBytes,
391
+ enableRuntimeIdCompressor,
392
+ enableOpReentryCheck,
393
+ enableGroupedBatching,
394
+ }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, provideEntryPoint, requestHandler, undefined);
395
+ // Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
396
+ // or zero. This must be done before Container replays saved ops.
397
+ await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
398
+ // Initialize the base state of the runtime before it's returned.
399
+ await runtime.initializeBaseState();
400
+ return runtime;
401
+ }
402
+ get clientId() {
403
+ return this._getClientId();
404
+ }
405
+ get storage() {
406
+ return this._storage;
407
+ }
408
+ get flushMode() {
409
+ return this._flushMode;
410
+ }
411
+ get scope() {
412
+ return this.containerScope;
413
+ }
414
+ get IFluidDataStoreRegistry() {
415
+ return this.registry;
416
+ }
417
+ get attachState() {
418
+ return this._getAttachState();
419
+ }
420
+ get IFluidHandleContext() {
421
+ return this.handleContext;
422
+ }
423
+ /**
424
+ * Invokes the given callback and expects that no ops are submitted
425
+ * until execution finishes. If an op is submitted, an error will be raised.
426
+ *
427
+ * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
428
+ *
429
+ * @param callback - the callback to be invoked
430
+ */
431
+ ensureNoDataModelChanges(callback) {
432
+ this.ensureNoDataModelChangesCalls++;
433
+ try {
434
+ return callback();
435
+ }
436
+ finally {
437
+ this.ensureNoDataModelChangesCalls--;
438
+ }
439
+ }
440
+ get connected() {
441
+ return this._connected;
442
+ }
443
+ /** clientId of parent (non-summarizing) container that owns summarizer container */
444
+ get summarizerClientId() {
445
+ return this.summarizerClientElection?.electedClientId;
446
+ }
447
+ get disposed() {
448
+ return this._disposed;
449
+ }
450
+ get summarizer() {
451
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
452
+ return this._summarizer;
453
+ }
454
+ isSummariesDisabled() {
455
+ return this.summaryConfiguration.state === "disabled";
456
+ }
457
+ isHeuristicsDisabled() {
458
+ return this.summaryConfiguration.state === "disableHeuristics";
459
+ }
460
+ getMaxOpsSinceLastSummary() {
461
+ return this.summaryConfiguration.state !== "disabled"
462
+ ? this.summaryConfiguration.maxOpsSinceLastSummary
463
+ : 0;
464
+ }
465
+ getInitialSummarizerDelayMs() {
466
+ // back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
467
+ // to ISummaryConfiguration in 0.60.
468
+ if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
469
+ return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
470
+ }
471
+ return this.summaryConfiguration.state !== "disabled"
472
+ ? this.summaryConfiguration.initialSummarizerDelayMs
473
+ : 0;
474
+ }
209
475
  /**
210
476
  * @internal
211
477
  */
212
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration = {
478
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, provideEntryPoint, requestHandler, summaryConfiguration = {
213
479
  // the defaults
214
480
  ...exports.DefaultSummaryConfiguration,
215
481
  // the runtime configuration overrides
216
482
  ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
217
- }, initializeEntryPoint) {
483
+ }) {
218
484
  super();
219
485
  this.registry = registry;
220
486
  this.runtimeOptions = runtimeOptions;
@@ -401,10 +667,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
401
667
  if (baseSnapshot) {
402
668
  this.summarizerNode.updateBaseSummaryState(baseSnapshot);
403
669
  }
404
- this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata), this, (attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
670
+ this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata), this, (attachMsg) => this.submit({ type: messageTypes_1.ContainerMessageType.Attach, contents: attachMsg }), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
405
671
  this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
406
672
  if (!this.disposed) {
407
- this.submit({ type: ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
673
+ this.submit({ type: messageTypes_1.ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
408
674
  localId,
409
675
  blobId,
410
676
  });
@@ -506,7 +772,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
506
772
  this.summaryCollection.on("default", defaultAction);
507
773
  // Create the SummaryManager and mark the initial state
508
774
  this.summaryManager = new summary_1.SummaryManager(this.summarizerClientElection, this, // IConnectedState
509
- this.summaryCollection, this.logger, this.formRequestSummarizerFn(loader), new throttler_1.Throttler(60 * 1000, // 60 sec delay window
775
+ this.summaryCollection, this.logger, this.formCreateSummarizerFn(loader), new throttler_1.Throttler(60 * 1000, // 60 sec delay window
510
776
  30 * 1000, // 30 sec max delay
511
777
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
512
778
  (0, throttler_1.formExponentialFn)({ coefficient: 20, initialDelay: 0 })), {
@@ -518,26 +784,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
518
784
  this.summaryManager.start();
519
785
  }
520
786
  }
521
- this.deltaManager.on("readonly", (readonly) => {
522
- // we accumulate ops while being in read-only state.
523
- // once user gets write permissions and we have active connection, flush all pending ops.
524
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
525
- (0, core_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
526
- // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
527
- // when we either never send an op, or attempted to send it but we know for sure it was not
528
- // sequenced by server and will never be sequenced (i.e. was lost)
529
- // For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
530
- // ops that made it from previous connection, before switching clientId and raising "connected" event
531
- // But with read-only permissions, if we transition between read-only and r/w states while on same
532
- // connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
533
- // being in read-only state.
534
- // For that reason, we support getting to read-only state only when disconnected. This ensures that we
535
- // can rely on same safety mechanism and resend ops only when we establish new connection.
536
- // This is applicable for read-only permissions (event is raised before connection is properly registered),
537
- // but it's an extra requirement for Container.forceReadonly() API
538
- (0, core_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
539
- this.replayPendingStates();
540
- });
541
787
  // logging hardware telemetry
542
788
  logger.sendTelemetryEvent({
543
789
  eventName: "DeviceSpec",
@@ -571,233 +817,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
571
817
  (0, core_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
572
818
  return this._summarizer;
573
819
  }
574
- return initializeEntryPoint?.(this);
575
- });
576
- }
577
- /**
578
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
579
- */
580
- get IFluidRouter() {
581
- return this;
582
- }
583
- /**
584
- * @deprecated - use loadRuntime instead.
585
- * Load the stores from a snapshot and returns the runtime.
586
- * @param context - Context of the container.
587
- * @param registryEntries - Mapping to the stores.
588
- * @param requestHandler - Request handlers for the container runtime
589
- * @param runtimeOptions - Additional options to be passed to the runtime
590
- * @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
591
- * @param containerRuntimeCtor - (optional) Constructor to use to create the ContainerRuntime instance. This
592
- * allows mixin classes to leverage this method to define their own async initializer.
593
- */
594
- static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
595
- let existingFlag = true;
596
- if (!existing) {
597
- existingFlag = false;
598
- }
599
- return this.loadRuntime({
600
- context,
601
- registryEntries,
602
- existing: existingFlag,
603
- requestHandler,
604
- runtimeOptions,
605
- containerScope,
606
- containerRuntimeCtor,
607
- });
608
- }
609
- /**
610
- * Load the stores from a snapshot and returns the runtime.
611
- * @param params - An object housing the runtime properties:
612
- * - context - Context of the container.
613
- * - registryEntries - Mapping from data store types to their corresponding factories.
614
- * - existing - Pass 'true' if loading from an existing snapshot.
615
- * - requestHandler - (optional) Request handler for the request() method of the container runtime.
616
- * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
617
- * - runtimeOptions - Additional options to be passed to the runtime
618
- * - containerScope - runtime services provided with context
619
- * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
620
- * This allows mixin classes to leverage this method to define their own async initializer.
621
- * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
622
- * This object should provide all the functionality that the Container is expected to provide to the loader layer.
623
- */
624
- static async loadRuntime(params) {
625
- const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
626
- const initializeEntryPoint = params.initializeEntryPoint ??
627
- (async (containerRuntime) => ({
628
- get IFluidRouter() {
629
- return this;
630
- },
631
- async request(req) {
632
- return containerRuntime.request(req);
633
- },
634
- }));
635
- // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
636
- // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
637
- const backCompatContext = context;
638
- const passLogger = backCompatContext.taggedLogger ??
639
- // eslint-disable-next-line import/no-deprecated
640
- new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
641
- const logger = (0, telemetry_utils_1.createChildLogger)({
642
- logger: passLogger,
643
- properties: {
644
- all: {
645
- runtimeVersion: packageVersion_1.pkgVersion,
646
- },
647
- },
648
- });
649
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
650
- const registry = new dataStoreRegistry_1.FluidDataStoreRegistry(registryEntries);
651
- const tryFetchBlob = async (blobName) => {
652
- const blobId = context.baseSnapshot?.blobs[blobName];
653
- if (context.baseSnapshot && blobId) {
654
- // IContainerContext storage api return type still has undefined in 0.39 package version.
655
- // So once we release 0.40 container-defn package we can remove this check.
656
- (0, core_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
657
- return (0, driver_utils_1.readAndParse)(context.storage, blobId);
658
- }
659
- };
660
- const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
661
- tryFetchBlob(summary_1.chunksBlobName),
662
- tryFetchBlob(summary_1.metadataBlobName),
663
- tryFetchBlob(summary_1.electedSummarizerBlobName),
664
- tryFetchBlob(summary_1.aliasBlobName),
665
- tryFetchBlob(summary_1.idCompressorBlobName),
666
- ]);
667
- // read snapshot blobs needed for BlobManager to load
668
- const blobManagerSnapshot = await blobManager_1.BlobManager.load(context.baseSnapshot?.trees[summary_1.blobsTreeName], async (id) => {
669
- // IContainerContext storage api return type still has undefined in 0.39 package version.
670
- // So once we release 0.40 container-defn package we can remove this check.
671
- (0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
672
- return (0, driver_utils_1.readAndParse)(context.storage, id);
820
+ return provideEntryPoint(this);
673
821
  });
674
- // Verify summary runtime sequence number matches protocol sequence number.
675
- const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
676
- // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
677
- if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
678
- const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
679
- // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
680
- if (loadSequenceNumberVerification !== "bypass" &&
681
- runtimeSequenceNumber !== protocolSequenceNumber) {
682
- // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
683
- const error = new telemetry_utils_1.DataCorruptionError(
684
- // pre-0.58 error message: SummaryMetadataMismatch
685
- "Summary metadata mismatch", { runtimeVersion: packageVersion_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
686
- if (loadSequenceNumberVerification === "log") {
687
- logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
688
- }
689
- else {
690
- context.closeFn(error);
691
- }
692
- }
693
- }
694
- const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
695
- let idCompressor;
696
- if (idCompressorEnabled) {
697
- const { IdCompressor, createSessionId } = await Promise.resolve().then(() => __importStar(require("./id-compressor")));
698
- idCompressor =
699
- serializedIdCompressor !== undefined
700
- ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
701
- : IdCompressor.create(logger);
702
- }
703
- const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
704
- summaryOptions,
705
- gcOptions,
706
- loadSequenceNumberVerification,
707
- flushMode,
708
- compressionOptions,
709
- maxBatchSizeInBytes,
710
- chunkSizeInBytes,
711
- enableRuntimeIdCompressor,
712
- enableOpReentryCheck,
713
- enableGroupedBatching,
714
- }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
715
- initializeEntryPoint);
716
- await runtime.blobManager.processStashedChanges();
717
- // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
718
- // at 1, so we won't see a replayed saved op with a sequence number of 0.
719
- await runtime.pendingStateManager.applyStashedOpsAt(0);
720
- // Initialize the base state of the runtime before it's returned.
721
- await runtime.initializeBaseState();
722
- return runtime;
723
- }
724
- get clientId() {
725
- return this._getClientId();
726
- }
727
- get storage() {
728
- return this._storage;
729
- }
730
- /** @deprecated - The functionality is no longer exposed publicly */
731
- get reSubmitFn() {
732
- return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
733
- // Note: compatDetails is not included in this deprecated API
734
- }
735
- get flushMode() {
736
- return this._flushMode;
737
- }
738
- get scope() {
739
- return this.containerScope;
740
- }
741
- get IFluidDataStoreRegistry() {
742
- return this.registry;
743
- }
744
- get attachState() {
745
- return this._getAttachState();
746
- }
747
- get IFluidHandleContext() {
748
- return this.handleContext;
749
- }
750
- /**
751
- * Invokes the given callback and expects that no ops are submitted
752
- * until execution finishes. If an op is submitted, an error will be raised.
753
- *
754
- * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
755
- *
756
- * @param callback - the callback to be invoked
757
- */
758
- ensureNoDataModelChanges(callback) {
759
- this.ensureNoDataModelChangesCalls++;
760
- try {
761
- return callback();
762
- }
763
- finally {
764
- this.ensureNoDataModelChangesCalls--;
765
- }
766
- }
767
- get connected() {
768
- return this._connected;
769
- }
770
- /** clientId of parent (non-summarizing) container that owns summarizer container */
771
- get summarizerClientId() {
772
- return this.summarizerClientElection?.electedClientId;
773
- }
774
- get disposed() {
775
- return this._disposed;
776
- }
777
- get summarizer() {
778
- (0, core_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
779
- return this._summarizer;
780
- }
781
- isSummariesDisabled() {
782
- return this.summaryConfiguration.state === "disabled";
783
- }
784
- isHeuristicsDisabled() {
785
- return this.summaryConfiguration.state === "disableHeuristics";
786
- }
787
- getMaxOpsSinceLastSummary() {
788
- return this.summaryConfiguration.state !== "disabled"
789
- ? this.summaryConfiguration.maxOpsSinceLastSummary
790
- : 0;
791
- }
792
- getInitialSummarizerDelayMs() {
793
- // back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
794
- // to ISummaryConfiguration in 0.60.
795
- if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
796
- return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
797
- }
798
- return this.summaryConfiguration.state !== "disabled"
799
- ? this.summaryConfiguration.initialSummarizerDelayMs
800
- : 0;
801
822
  }
802
823
  /**
803
824
  * Initializes the state from the base snapshot this container runtime loaded from.
@@ -829,13 +850,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
829
850
  /**
830
851
  * Notifies this object about the request made to the container.
831
852
  * @param request - Request made to the handler.
832
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
853
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
833
854
  */
834
855
  async request(request) {
835
856
  try {
836
857
  const parser = runtime_utils_1.RequestParser.create(request);
837
858
  const id = parser.pathParts[0];
838
- if (id === "_summarizer" && parser.pathParts.length === 1) {
859
+ if (id === summarizerRequestUrl && parser.pathParts.length === 1) {
839
860
  if (this._summarizer !== undefined) {
840
861
  return {
841
862
  status: 200,
@@ -846,6 +867,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
846
867
  return (0, runtime_utils_1.create404Response)(request);
847
868
  }
848
869
  if (this.requestHandler !== undefined) {
870
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
849
871
  return this.requestHandler(parser, this);
850
872
  }
851
873
  return (0, runtime_utils_1.create404Response)(request);
@@ -863,6 +885,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
863
885
  const requestParser = runtime_utils_1.RequestParser.create(request);
864
886
  const id = requestParser.pathParts[0];
865
887
  if (id === "_channels") {
888
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
866
889
  return this.resolveHandle(requestParser.createSubRequest(1));
867
890
  }
868
891
  if (id === blobManager_1.BlobManager.basePath && requestParser.isLeaf(2)) {
@@ -876,11 +899,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
876
899
  : (0, runtime_utils_1.create404Response)(request);
877
900
  }
878
901
  else if (requestParser.pathParts.length > 0) {
879
- const dataStore = await this.getDataStoreFromRequest(id, request);
902
+ // Differentiate between requesting the dataStore directly, or one of its children
903
+ const requestForChild = !requestParser.isLeaf(1);
904
+ const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
880
905
  const subRequest = requestParser.createSubRequest(1);
881
906
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
882
907
  // unintentionally modifying the url if that changes.
883
908
  (0, core_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
909
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
884
910
  return dataStore.request(subRequest);
885
911
  }
886
912
  return (0, runtime_utils_1.create404Response)(request);
@@ -898,7 +924,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
898
924
  internalId(maybeAlias) {
899
925
  return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
900
926
  }
901
- async getDataStoreFromRequest(id, request) {
927
+ async getDataStoreFromRequest(id, request, requestForChild) {
902
928
  const headerData = {};
903
929
  if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
904
930
  headerData.wait = request.headers[RuntimeHeaders.wait];
@@ -909,6 +935,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
909
935
  if (typeof request.headers?.[exports.AllowTombstoneRequestHeaderKey] === "boolean") {
910
936
  headerData.allowTombstone = request.headers[exports.AllowTombstoneRequestHeaderKey];
911
937
  }
938
+ // We allow Tombstone requests for sub-DataStore objects
939
+ if (requestForChild) {
940
+ headerData.allowTombstone = true;
941
+ }
912
942
  await this.dataStores.waitIfPendingAlias(id);
913
943
  const internalId = this.internalId(id);
914
944
  const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
@@ -999,7 +1029,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
999
1029
  // in their own batches before the originating batch is sent.
1000
1030
  // Therefore, receiving them while attempting to send the originating batch
1001
1031
  // does not mean that the container is making any progress.
1002
- if (message?.type !== ContainerMessageType.ChunkedOp) {
1032
+ if (message?.type !== messageTypes_1.ContainerMessageType.ChunkedOp) {
1003
1033
  this.consecutiveReconnects = 0;
1004
1034
  }
1005
1035
  }
@@ -1047,39 +1077,40 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1047
1077
  * Parse an op's type and actual content from given serialized content
1048
1078
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
1049
1079
  */
1050
- parseOpContent(serializedContent) {
1051
- (0, core_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1052
- const { type, contents, compatDetails } = JSON.parse(serializedContent);
1053
- (0, core_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
1054
- return { type, contents, compatDetails };
1055
- }
1056
- async applyStashedOp(op) {
1080
+ // TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
1081
+ parseLocalOpContent(serializedContents) {
1082
+ (0, core_utils_1.assert)(serializedContents !== undefined, 0x6d5 /* content must be defined */);
1083
+ const message = JSON.parse(serializedContents);
1084
+ (0, core_utils_1.assert)(message.type !== undefined, 0x6d6 /* incorrect op content format */);
1085
+ return message;
1086
+ }
1087
+ async applyStashedOp(serializedOpContent) {
1057
1088
  // Need to parse from string for back-compat
1058
- const { type, contents, compatDetails } = this.parseOpContent(op);
1059
- switch (type) {
1060
- case ContainerMessageType.FluidDataStoreOp:
1061
- return this.dataStores.applyStashedOp(contents);
1062
- case ContainerMessageType.Attach:
1063
- return this.dataStores.applyStashedAttachOp(contents);
1064
- case ContainerMessageType.IdAllocation:
1089
+ const opContents = this.parseLocalOpContent(serializedOpContent);
1090
+ switch (opContents.type) {
1091
+ case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
1092
+ return this.dataStores.applyStashedOp(opContents.contents);
1093
+ case messageTypes_1.ContainerMessageType.Attach:
1094
+ return this.dataStores.applyStashedAttachOp(opContents.contents);
1095
+ case messageTypes_1.ContainerMessageType.IdAllocation:
1065
1096
  (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1066
- return this.applyStashedIdAllocationOp(contents);
1067
- case ContainerMessageType.Alias:
1068
- case ContainerMessageType.BlobAttach:
1097
+ return this.applyStashedIdAllocationOp(opContents.contents);
1098
+ case messageTypes_1.ContainerMessageType.Alias:
1099
+ case messageTypes_1.ContainerMessageType.BlobAttach:
1069
1100
  return;
1070
- case ContainerMessageType.ChunkedOp:
1101
+ case messageTypes_1.ContainerMessageType.ChunkedOp:
1071
1102
  throw new Error("chunkedOp not expected here");
1072
- case ContainerMessageType.Rejoin:
1103
+ case messageTypes_1.ContainerMessageType.Rejoin:
1073
1104
  throw new Error("rejoin not expected here");
1074
1105
  default: {
1075
1106
  // This should be extremely rare for stashed ops.
1076
1107
  // It would require a newer runtime stashing ops and then an older one applying them,
1077
1108
  // e.g. if an app rolled back its container version
1078
- const compatBehavior = compatDetails?.behavior;
1079
- if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
1109
+ const compatBehavior = opContents.compatDetails?.behavior;
1110
+ if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
1080
1111
  const error = telemetry_utils_1.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1081
1112
  messageDetails: JSON.stringify({
1082
- type,
1113
+ type: opContents.type,
1083
1114
  compatBehavior,
1084
1115
  }),
1085
1116
  });
@@ -1098,6 +1129,23 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1098
1129
  // Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
1099
1130
  return;
1100
1131
  }
1132
+ // If there are stashed blobs in the pending state, we need to delay
1133
+ // propagation of the "connected" event until we have uploaded them to
1134
+ // ensure we don't submit ops referencing a blob that has not been uploaded
1135
+ const connecting = connected && !this._connected;
1136
+ if (connecting && this.blobManager.hasPendingStashedBlobs()) {
1137
+ (0, core_utils_1.assert)(!this.delayConnectClientId, 0x791 /* Connect event delay must be canceled before subsequent connect event */);
1138
+ (0, core_utils_1.assert)(!!clientId, 0x792 /* Must have clientId when connecting */);
1139
+ this.delayConnectClientId = clientId;
1140
+ this.blobManager.processStashedChanges().then(() => {
1141
+ // make sure we didn't reconnect before the promise resolved
1142
+ if (this.delayConnectClientId === clientId && !this.disposed) {
1143
+ this.delayConnectClientId = undefined;
1144
+ this.setConnectionStateCore(connected, clientId);
1145
+ }
1146
+ }, (error) => this.closeFn(error));
1147
+ return;
1148
+ }
1101
1149
  this.setConnectionStateCore(connected, clientId);
1102
1150
  }
1103
1151
  setConnectionStateCore(connected, clientId) {
@@ -1150,18 +1198,33 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1150
1198
  // or something different, like a system message.
1151
1199
  const modernRuntimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
1152
1200
  // Do shallow copy of message, as the processing flow will modify it.
1201
+ // There might be multiple container instances receiving the same message.
1202
+ // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1203
+ // but will not modify the contents object (likely it will replace it on the message).
1153
1204
  const messageCopy = { ...messageArg };
1154
1205
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1155
- this.processCore(message, local, modernRuntimeMessage);
1206
+ if (modernRuntimeMessage) {
1207
+ this.processCore({
1208
+ // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1209
+ // There is nothing really ensuring that anytime original message.type is Operation that
1210
+ // the result messages will be so. In the end modern bool being true only directs to
1211
+ // throw error if ultimately unrecognized without compat details saying otherwise.
1212
+ message: message,
1213
+ local,
1214
+ modernRuntimeMessage,
1215
+ });
1216
+ }
1217
+ else {
1218
+ // Unrecognized message will be ignored.
1219
+ this.processCore({ message, local, modernRuntimeMessage });
1220
+ }
1156
1221
  }
1157
1222
  }
1158
1223
  /**
1159
1224
  * Direct the message to the correct subsystem for processing, and implement other side effects
1160
- * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
1161
- * @param local - Did this client send the op?
1162
- * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
1163
1225
  */
1164
- processCore(message, local, modernRuntimeMessage) {
1226
+ processCore(messageWithContext) {
1227
+ const { message, local } = messageWithContext;
1165
1228
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1166
1229
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1167
1230
  // messages once a batch has been fully processed.
@@ -1169,16 +1232,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1169
1232
  this._processedClientSequenceNumber = message.clientSequenceNumber;
1170
1233
  try {
1171
1234
  let localOpMetadata;
1172
- if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1173
- localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
1235
+ if (local &&
1236
+ messageWithContext.modernRuntimeMessage &&
1237
+ message.type !== messageTypes_1.ContainerMessageType.ChunkedOp) {
1238
+ localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
1174
1239
  }
1175
1240
  // If there are no more pending messages after processing a local message,
1176
1241
  // the document is no longer dirty.
1177
1242
  if (!this.hasPendingMessages()) {
1178
1243
  this.updateDocumentDirtyState(false);
1179
1244
  }
1180
- this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
1181
- this.emit("op", message, modernRuntimeMessage);
1245
+ this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
1246
+ this.emit("op", message, messageWithContext.modernRuntimeMessage);
1182
1247
  this.scheduleManager.afterOpProcessing(undefined, message);
1183
1248
  if (local) {
1184
1249
  // If we have processed a local op, this means that the container is
@@ -1193,41 +1258,42 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1193
1258
  }
1194
1259
  }
1195
1260
  /**
1196
- * Assuming the given message is also a ContainerRuntimeMessage,
1261
+ * Assuming the given message is also a TypedContainerRuntimeMessage,
1197
1262
  * checks its type and dispatches the message to the appropriate handler in the runtime.
1198
- * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
1263
+ * Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
1199
1264
  */
1200
- validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
1201
- // Optimistically extract ContainerRuntimeMessage-specific props from the message
1202
- const { type: maybeContainerMessageType, compatDetails } = message;
1203
- switch (maybeContainerMessageType) {
1204
- case ContainerMessageType.Attach:
1205
- this.dataStores.processAttachMessage(message, local);
1265
+ validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata) {
1266
+ // TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
1267
+ const { local } = messageWithContext;
1268
+ switch (messageWithContext.message.type) {
1269
+ case messageTypes_1.ContainerMessageType.Attach:
1270
+ this.dataStores.processAttachMessage(messageWithContext.message, local);
1206
1271
  break;
1207
- case ContainerMessageType.Alias:
1208
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
1272
+ case messageTypes_1.ContainerMessageType.Alias:
1273
+ this.dataStores.processAliasMessage(messageWithContext.message, localOpMetadata, local);
1209
1274
  break;
1210
- case ContainerMessageType.FluidDataStoreOp:
1211
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1275
+ case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
1276
+ this.dataStores.processFluidDataStoreOp(messageWithContext.message, local, localOpMetadata);
1212
1277
  break;
1213
- case ContainerMessageType.BlobAttach:
1214
- this.blobManager.processBlobAttachOp(message, local);
1278
+ case messageTypes_1.ContainerMessageType.BlobAttach:
1279
+ this.blobManager.processBlobAttachOp(messageWithContext.message, local);
1215
1280
  break;
1216
- case ContainerMessageType.IdAllocation:
1281
+ case messageTypes_1.ContainerMessageType.IdAllocation:
1217
1282
  (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1218
- this.idCompressor.finalizeCreationRange(message.contents);
1283
+ this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
1219
1284
  break;
1220
- case ContainerMessageType.ChunkedOp:
1221
- case ContainerMessageType.Rejoin:
1285
+ case messageTypes_1.ContainerMessageType.ChunkedOp:
1286
+ case messageTypes_1.ContainerMessageType.Rejoin:
1222
1287
  break;
1223
1288
  default: {
1224
1289
  // If we didn't necessarily expect a runtime message type, then no worries - just return
1225
1290
  // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
1226
- if (!expectRuntimeMessageType) {
1291
+ if (!messageWithContext.modernRuntimeMessage) {
1227
1292
  return;
1228
1293
  }
1229
- const compatBehavior = compatDetails?.behavior;
1230
- if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
1294
+ const compatBehavior = messageWithContext.message.compatDetails?.behavior;
1295
+ if (!compatBehaviorAllowsMessageType(messageWithContext.message.type, compatBehavior)) {
1296
+ const { message } = messageWithContext;
1231
1297
  const error = telemetry_utils_1.DataProcessingError.create(
1232
1298
  // Former assert 0x3ce
1233
1299
  "Runtime message of unknown type", "OpProcessing", message, {
@@ -1303,8 +1369,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1303
1369
  * Returns the runtime of the data store.
1304
1370
  * @param id - Id supplied during creating the data store.
1305
1371
  * @param wait - True if you want to wait for it.
1306
- * @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
1372
+ * @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
1307
1373
  */
1374
+ // eslint-disable-next-line import/no-deprecated
1308
1375
  async getRootDataStore(id, wait = true) {
1309
1376
  return this.getRootDataStoreChannel(id, wait);
1310
1377
  }
@@ -1437,13 +1504,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1437
1504
  isContainerMessageDirtyable({ type, contents }) {
1438
1505
  // For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
1439
1506
  // Ultimately we should have no special-cases from the ContainerRuntime's perspective.
1440
- if (type === ContainerMessageType.Attach) {
1507
+ if (type === messageTypes_1.ContainerMessageType.Attach) {
1441
1508
  const attachMessage = contents;
1442
1509
  if (attachMessage.id === exports.agentSchedulerId) {
1443
1510
  return false;
1444
1511
  }
1445
1512
  }
1446
- else if (type === ContainerMessageType.FluidDataStoreOp) {
1513
+ else if (type === messageTypes_1.ContainerMessageType.FluidDataStoreOp) {
1447
1514
  const envelope = contents;
1448
1515
  if (envelope.address === exports.agentSchedulerId) {
1449
1516
  return false;
@@ -1601,7 +1668,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1601
1668
  this.dataStores.updateUnusedRoutes(dataStoreRoutes);
1602
1669
  }
1603
1670
  /**
1604
- * @deprecated - Replaced by deleteSweepReadyNodes.
1671
+ * @deprecated Replaced by deleteSweepReadyNodes.
1605
1672
  */
1606
1673
  deleteUnusedNodes(unusedRoutes) {
1607
1674
  throw new Error("deleteUnusedRoutes should not be called");
@@ -1723,16 +1790,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1723
1790
  },
1724
1791
  });
1725
1792
  (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1793
+ // We close the summarizer and download a new snapshot and reload the container
1726
1794
  let latestSnapshotVersionId;
1727
- if (refreshLatestAck) {
1728
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer((0, telemetry_utils_1.createChildLogger)({
1795
+ if (refreshLatestAck === true) {
1796
+ return this.prefetchLatestSummaryThenClose((0, telemetry_utils_1.createChildLogger)({
1729
1797
  logger: summaryNumberLogger,
1730
1798
  properties: { all: { safeSummary: true } },
1731
1799
  }));
1732
- const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1733
- latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1734
- // We might need to catch up to the latest summary's reference sequence number before pausing.
1735
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1736
1800
  }
1737
1801
  // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
1738
1802
  // incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
@@ -2052,21 +2116,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2052
2116
  address: id,
2053
2117
  contents,
2054
2118
  };
2055
- this.submit({ type: ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
2119
+ this.submit({ type: messageTypes_1.ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
2056
2120
  }
2057
2121
  submitDataStoreAliasOp(contents, localOpMetadata) {
2058
2122
  const aliasMessage = contents;
2059
2123
  if (!(0, dataStore_1.isDataStoreAliasMessage)(aliasMessage)) {
2060
2124
  throw new telemetry_utils_1.UsageError("malformedDataStoreAliasMessage");
2061
2125
  }
2062
- this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
2126
+ this.submit({ type: messageTypes_1.ContainerMessageType.Alias, contents }, localOpMetadata);
2063
2127
  }
2064
2128
  async uploadBlob(blob, signal) {
2065
2129
  this.verifyNotClosed();
2066
2130
  return this.blobManager.createBlob(blob, signal);
2067
2131
  }
2068
2132
  maybeSubmitIdAllocationOp(type) {
2069
- if (type !== ContainerMessageType.IdAllocation) {
2133
+ if (type !== messageTypes_1.ContainerMessageType.IdAllocation) {
2070
2134
  let idAllocationBatchMessage;
2071
2135
  let idRange;
2072
2136
  if (this.idCompressorEnabled) {
@@ -2077,7 +2141,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2077
2141
  }
2078
2142
  if (idRange !== undefined) {
2079
2143
  const idAllocationMessage = {
2080
- type: ContainerMessageType.IdAllocation,
2144
+ type: messageTypes_1.ContainerMessageType.IdAllocation,
2081
2145
  contents: idRange,
2082
2146
  };
2083
2147
  idAllocationBatchMessage = {
@@ -2085,7 +2149,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2085
2149
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2086
2150
  metadata: undefined,
2087
2151
  localOpMetadata: this.idCompressor?.serialize(true),
2088
- type: ContainerMessageType.IdAllocation,
2152
+ type: messageTypes_1.ContainerMessageType.IdAllocation,
2089
2153
  };
2090
2154
  }
2091
2155
  if (idAllocationBatchMessage !== undefined) {
@@ -2142,11 +2206,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2142
2206
  // Please note that this does not change file format, so it can be disabled in the future if this
2143
2207
  // optimization no longer makes sense (for example, batch compression may make it less appealing).
2144
2208
  if (this.currentlyBatching() &&
2145
- type === ContainerMessageType.Attach &&
2209
+ type === messageTypes_1.ContainerMessageType.Attach &&
2146
2210
  this.disableAttachReorder !== true) {
2147
2211
  this.outbox.submitAttach(message);
2148
2212
  }
2149
- else if (type === ContainerMessageType.BlobAttach) {
2213
+ else if (type === messageTypes_1.ContainerMessageType.BlobAttach) {
2150
2214
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2151
2215
  this.outbox.submitBlobAttach(message);
2152
2216
  }
@@ -2256,40 +2320,37 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2256
2320
  }
2257
2321
  reSubmit(message) {
2258
2322
  // Need to parse from string for back-compat
2259
- const containerRuntimeMessage = this.parseOpContent(message.content);
2323
+ const containerRuntimeMessage = this.parseLocalOpContent(message.content);
2260
2324
  this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
2261
2325
  }
2262
2326
  /**
2263
2327
  * Finds the right store and asks it to resubmit the message. This typically happens when we
2264
2328
  * reconnect and there are pending messages.
2265
- * @param message - The original ContainerRuntimeMessage.
2329
+ * @param message - The original LocalContainerRuntimeMessage.
2266
2330
  * @param localOpMetadata - The local metadata associated with the original message.
2267
2331
  */
2268
2332
  reSubmitCore(message, localOpMetadata, opMetadata) {
2269
- const contents = message.contents;
2270
2333
  switch (message.type) {
2271
- case ContainerMessageType.FluidDataStoreOp:
2334
+ case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
2272
2335
  // For Operations, call resubmitDataStoreOp which will find the right store
2273
2336
  // and trigger resubmission on it.
2274
- this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
2337
+ this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
2275
2338
  break;
2276
- case ContainerMessageType.Attach:
2277
- case ContainerMessageType.Alias:
2339
+ case messageTypes_1.ContainerMessageType.Attach:
2340
+ case messageTypes_1.ContainerMessageType.Alias:
2278
2341
  this.submit(message, localOpMetadata);
2279
2342
  break;
2280
- case ContainerMessageType.IdAllocation:
2281
- // Remove the stashedState from the op if it's a stashed op
2282
- if (contents.stashedState !== undefined) {
2283
- delete contents.stashedState;
2284
- }
2343
+ case messageTypes_1.ContainerMessageType.IdAllocation: {
2344
+ prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
2285
2345
  this.submit(message, localOpMetadata);
2286
2346
  break;
2287
- case ContainerMessageType.ChunkedOp:
2347
+ }
2348
+ case messageTypes_1.ContainerMessageType.ChunkedOp:
2288
2349
  throw new Error(`chunkedOp not expected here`);
2289
- case ContainerMessageType.BlobAttach:
2350
+ case messageTypes_1.ContainerMessageType.BlobAttach:
2290
2351
  this.blobManager.reSubmit(opMetadata);
2291
2352
  break;
2292
- case ContainerMessageType.Rejoin:
2353
+ case messageTypes_1.ContainerMessageType.Rejoin:
2293
2354
  this.submit(message);
2294
2355
  break;
2295
2356
  default: {
@@ -2317,9 +2378,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2317
2378
  }
2318
2379
  rollback(content, localOpMetadata) {
2319
2380
  // Need to parse from string for back-compat
2320
- const { type, contents } = this.parseOpContent(content);
2381
+ const { type, contents } = this.parseLocalOpContent(content);
2321
2382
  switch (type) {
2322
- case ContainerMessageType.FluidDataStoreOp:
2383
+ case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
2323
2384
  // For operations, call rollbackDataStoreOp which will find the right store
2324
2385
  // and trigger rollback on it.
2325
2386
  this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
@@ -2329,17 +2390,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2329
2390
  throw new Error(`Can't rollback ${type}`);
2330
2391
  }
2331
2392
  }
2332
- async waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger) {
2333
- if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
2334
- // We need to catch up to the latest summary's reference sequence number before proceeding.
2335
- await telemetry_utils_1.PerformanceEvent.timedExecAsync(summaryLogger, {
2336
- eventName: "WaitingForSeq",
2337
- lastSequenceNumber: this.deltaManager.lastSequenceNumber,
2338
- targetSequenceNumber: latestSnapshotRefSeq,
2339
- lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
2340
- }, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
2341
- }
2342
- }
2343
2393
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2344
2394
  async refreshLatestSummaryAck(options) {
2345
2395
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
@@ -2354,11 +2404,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2354
2404
  * and then close as the current main client is likely to be re-elected as the parent summarizer again.
2355
2405
  */
2356
2406
  if (!result.isSummaryTracked && result.isSummaryNewer) {
2357
- const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2407
+ const fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2358
2408
  eventName: "RefreshLatestSummaryAckFetch",
2359
2409
  ackHandle,
2360
2410
  targetSequenceNumber: summaryRefSeq,
2361
- }, readAndParseBlob, null);
2411
+ }, readAndParseBlob);
2362
2412
  /**
2363
2413
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
2364
2414
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -2385,41 +2435,42 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2385
2435
  await this.garbageCollector.refreshLatestSummary(result);
2386
2436
  }
2387
2437
  /**
2388
- * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
2389
- * internal state as it should be considered the latest summary ack.
2438
+ * Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
2439
+ * summarizer to reload from new state.
2390
2440
  * @param summaryLogger - logger to use when fetching snapshot from storage
2391
- * @returns downloaded snapshot's reference sequence number
2441
+ * @returns a generic summarization error
2392
2442
  */
2393
- async refreshLatestSummaryAckFromServer(summaryLogger) {
2443
+ async prefetchLatestSummaryThenClose(summaryLogger) {
2394
2444
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2395
- const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
2445
+ // This is a performance optimization as the same parent is likely to be elected again, and would use its
2446
+ // cache to fetch the snapshot instead of the network.
2447
+ await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2396
2448
  eventName: "RefreshLatestSummaryFromServerFetch",
2397
- }, readAndParseBlob, null);
2449
+ }, readAndParseBlob);
2398
2450
  await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
2399
- return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2451
+ return {
2452
+ stage: "base",
2453
+ error: "summary state stale - Unsupported option 'refreshLatestAck'",
2454
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2455
+ minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
2456
+ };
2400
2457
  }
2401
2458
  async closeStaleSummarizer(codePath) {
2402
- this.mc.logger.sendTelemetryEvent({
2403
- eventName: "ClosingSummarizerOnSummaryStale",
2404
- codePath,
2405
- message: "Stopping fetch from storage",
2406
- closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2407
- }, new telemetry_utils_1.GenericError("Restarting summarizer instead of refreshing"));
2408
2459
  // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2409
2460
  await (0, core_utils_1.delay)(this.closeSummarizerDelayMs);
2410
2461
  this._summarizer?.stop("latestSummaryStateStale");
2411
2462
  this.disposeFn();
2412
2463
  }
2413
2464
  /**
2414
- * Downloads snapshot from storage with the given versionId or latest if versionId is null.
2465
+ * Downloads the latest snapshot from storage.
2415
2466
  * By default, it also closes the container after downloading the snapshot. However, this may be
2416
2467
  * overridden via options.
2417
2468
  */
2418
- async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
2469
+ async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2419
2470
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2420
2471
  const stats = {};
2421
2472
  const trace = client_utils_1.Trace.start();
2422
- const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
2473
+ const versions = await this.storage.getVersions(null, 1, "prefetchLatestSummaryBeforeClose", driver_definitions_1.FetchSource.noCache);
2423
2474
  (0, core_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2424
2475
  stats.getVersionDuration = trace.trace().duration;
2425
2476
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
@@ -2447,15 +2498,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2447
2498
  if (this._orderSequentiallyCalls !== 0) {
2448
2499
  throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
2449
2500
  }
2450
- const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2451
- const pending = this.pendingStateManager.getLocalState();
2452
- if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2453
- return; // no pending state to save
2454
- }
2455
2501
  // Flush pending batch.
2456
2502
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2457
2503
  // to close current batch.
2458
2504
  this.flush();
2505
+ const pendingAttachmentBlobs = waitBlobsToAttach
2506
+ ? await this.blobManager.attachAndGetPendingBlobs()
2507
+ : undefined;
2508
+ const pending = this.pendingStateManager.getLocalState();
2509
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2510
+ return; // no pending state to save
2511
+ }
2459
2512
  const pendingState = {
2460
2513
  pending,
2461
2514
  pendingAttachmentBlobs,
@@ -2496,29 +2549,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2496
2549
  }
2497
2550
  }
2498
2551
  /**
2499
- * * Forms a function that will request a Summarizer.
2500
- * @param loaderRouter - the loader acting as an IFluidRouter
2501
- * */
2502
- formRequestSummarizerFn(loaderRouter) {
2552
+ * Forms a function that will create and retrieve a Summarizer.
2553
+ */
2554
+ formCreateSummarizerFn(loader) {
2503
2555
  return async () => {
2504
- const request = {
2505
- headers: {
2506
- [container_definitions_1.LoaderHeader.cache]: false,
2507
- [container_definitions_1.LoaderHeader.clientDetails]: {
2508
- capabilities: { interactive: false },
2509
- type: summary_1.summarizerClientType,
2510
- },
2511
- [driver_definitions_1.DriverHeader.summarizingClient]: true,
2512
- [container_definitions_1.LoaderHeader.reconnect]: false,
2513
- },
2514
- url: "/_summarizer",
2515
- };
2516
- const fluidObject = await (0, runtime_utils_1.requestFluidObject)(loaderRouter, request);
2517
- const summarizer = fluidObject.ISummarizer;
2518
- if (!summarizer) {
2519
- throw new telemetry_utils_1.UsageError("Fluid object does not implement ISummarizer");
2520
- }
2521
- return summarizer;
2556
+ return createSummarizer(loader, `/${summarizerRequestUrl}`);
2522
2557
  };
2523
2558
  }
2524
2559
  validateSummaryHeuristicConfiguration(configuration) {
@@ -2538,26 +2573,4 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2538
2573
  }
2539
2574
  }
2540
2575
  exports.ContainerRuntime = ContainerRuntime;
2541
- /**
2542
- * Wait for a specific sequence number. Promise should resolve when we reach that number,
2543
- * or reject if closed.
2544
- */
2545
- const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
2546
- // TODO: remove cast to any when actual event is determined
2547
- deltaManager.on("closed", reject);
2548
- deltaManager.on("disposed", reject);
2549
- // If we already reached target sequence number, simply resolve the promise.
2550
- if (deltaManager.lastSequenceNumber >= targetSeq) {
2551
- resolve();
2552
- }
2553
- else {
2554
- const handleOp = (message) => {
2555
- if (message.sequenceNumber >= targetSeq) {
2556
- resolve();
2557
- deltaManager.off("op", handleOp);
2558
- }
2559
- };
2560
- deltaManager.on("op", handleOp);
2561
- }
2562
- });
2563
2576
  //# sourceMappingURL=containerRuntime.js.map