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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/api-extractor.json +1 -1
  3. package/api-report/container-runtime.api.md +864 -0
  4. package/dist/blobManager.d.ts +4 -4
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +55 -71
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/connectionTelemetry.d.ts.map +1 -1
  9. package/dist/connectionTelemetry.js +75 -42
  10. package/dist/connectionTelemetry.js.map +1 -1
  11. package/dist/container-runtime-alpha.d.ts +1742 -0
  12. package/dist/container-runtime-beta.d.ts +1742 -0
  13. package/dist/container-runtime-public.d.ts +1742 -0
  14. package/dist/container-runtime-untrimmed.d.ts +1803 -0
  15. package/dist/containerHandleContext.js +3 -3
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +88 -98
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +466 -453
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.js +11 -11
  22. package/dist/dataStore.js.map +1 -1
  23. package/dist/dataStoreContext.d.ts +2 -4
  24. package/dist/dataStoreContext.d.ts.map +1 -1
  25. package/dist/dataStoreContext.js +60 -59
  26. package/dist/dataStoreContext.js.map +1 -1
  27. package/dist/dataStoreRegistry.d.ts +3 -0
  28. package/dist/dataStoreRegistry.d.ts.map +1 -1
  29. package/dist/dataStoreRegistry.js +6 -3
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.js +1 -1
  32. package/dist/dataStores.js.map +1 -1
  33. package/dist/deltaManagerProxyBase.js +4 -4
  34. package/dist/deltaManagerProxyBase.js.map +1 -1
  35. package/dist/deltaManagerSummarizerProxy.js +6 -6
  36. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  37. package/dist/deltaScheduler.js.map +1 -1
  38. package/dist/error.d.ts.map +1 -1
  39. package/dist/error.js.map +1 -1
  40. package/dist/gc/garbageCollection.d.ts.map +1 -1
  41. package/dist/gc/garbageCollection.js +23 -24
  42. package/dist/gc/garbageCollection.js.map +1 -1
  43. package/dist/gc/gcConfigs.js +1 -1
  44. package/dist/gc/gcConfigs.js.map +1 -1
  45. package/dist/gc/gcDefinitions.d.ts +34 -24
  46. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  47. package/dist/gc/gcDefinitions.js +10 -7
  48. package/dist/gc/gcDefinitions.js.map +1 -1
  49. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  50. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  51. package/dist/gc/gcTelemetry.d.ts +2 -2
  52. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  53. package/dist/gc/gcTelemetry.js +5 -5
  54. package/dist/gc/gcTelemetry.js.map +1 -1
  55. package/dist/gc/gcUnreferencedStateTracker.js +3 -3
  56. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  57. package/dist/gc/index.d.ts +1 -1
  58. package/dist/gc/index.d.ts.map +1 -1
  59. package/dist/gc/index.js +3 -3
  60. package/dist/gc/index.js.map +1 -1
  61. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  62. package/dist/id-compressor/idCompressor.js.map +1 -1
  63. package/dist/id-compressor/identifiers.d.ts +3 -3
  64. package/dist/id-compressor/identifiers.d.ts.map +1 -1
  65. package/dist/id-compressor/utilities.d.ts +3 -0
  66. package/dist/id-compressor/utilities.d.ts.map +1 -1
  67. package/dist/id-compressor/utilities.js +3 -0
  68. package/dist/id-compressor/utilities.js.map +1 -1
  69. package/dist/index.d.ts +5 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +6 -2
  72. package/dist/index.js.map +1 -1
  73. package/dist/messageTypes.d.ts +137 -0
  74. package/dist/messageTypes.d.ts.map +1 -0
  75. package/dist/messageTypes.js +32 -0
  76. package/dist/messageTypes.js.map +1 -0
  77. package/dist/opLifecycle/batchManager.js +6 -6
  78. package/dist/opLifecycle/batchManager.js.map +1 -1
  79. package/dist/opLifecycle/definitions.d.ts +7 -3
  80. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  81. package/dist/opLifecycle/definitions.js.map +1 -1
  82. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  83. package/dist/opLifecycle/opDecompressor.js +0 -4
  84. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  85. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  86. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  87. package/dist/opLifecycle/opSplitter.js +3 -3
  88. package/dist/opLifecycle/opSplitter.js.map +1 -1
  89. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  90. package/dist/opLifecycle/outbox.js +7 -2
  91. package/dist/opLifecycle/outbox.js.map +1 -1
  92. package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  93. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  94. package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
  95. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  96. package/dist/packageVersion.d.ts +1 -1
  97. package/dist/packageVersion.js +1 -1
  98. package/dist/packageVersion.js.map +1 -1
  99. package/dist/pendingStateManager.d.ts +4 -20
  100. package/dist/pendingStateManager.d.ts.map +1 -1
  101. package/dist/pendingStateManager.js +36 -46
  102. package/dist/pendingStateManager.js.map +1 -1
  103. package/dist/scheduleManager.js +6 -2
  104. package/dist/scheduleManager.js.map +1 -1
  105. package/dist/summary/orderedClientElection.d.ts +7 -4
  106. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  107. package/dist/summary/orderedClientElection.js +54 -54
  108. package/dist/summary/orderedClientElection.js.map +1 -1
  109. package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
  110. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  111. package/dist/summary/runWhileConnectedCoordinator.js +7 -6
  112. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  113. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  114. package/dist/summary/runningSummarizer.js +40 -38
  115. package/dist/summary/runningSummarizer.js.map +1 -1
  116. package/dist/summary/summarizer.d.ts +2 -0
  117. package/dist/summary/summarizer.d.ts.map +1 -1
  118. package/dist/summary/summarizer.js +18 -8
  119. package/dist/summary/summarizer.js.map +1 -1
  120. package/dist/summary/summarizerClientElection.js +6 -6
  121. package/dist/summary/summarizerClientElection.js.map +1 -1
  122. package/dist/summary/summarizerHeuristics.js +9 -9
  123. package/dist/summary/summarizerHeuristics.js.map +1 -1
  124. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
  125. package/dist/summary/summarizerNode/summarizerNode.js +8 -8
  126. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  127. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  128. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  129. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  130. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  131. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  132. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  133. package/dist/summary/summarizerTypes.d.ts +107 -22
  134. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  135. package/dist/summary/summarizerTypes.js.map +1 -1
  136. package/dist/summary/summaryCollection.d.ts +18 -2
  137. package/dist/summary/summaryCollection.d.ts.map +1 -1
  138. package/dist/summary/summaryCollection.js +23 -21
  139. package/dist/summary/summaryCollection.js.map +1 -1
  140. package/dist/summary/summaryFormat.d.ts +15 -6
  141. package/dist/summary/summaryFormat.d.ts.map +1 -1
  142. package/dist/summary/summaryFormat.js.map +1 -1
  143. package/dist/summary/summaryGenerator.d.ts +3 -3
  144. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  145. package/dist/summary/summaryGenerator.js.map +1 -1
  146. package/dist/summary/summaryManager.d.ts +2 -2
  147. package/dist/summary/summaryManager.d.ts.map +1 -1
  148. package/dist/summary/summaryManager.js +10 -10
  149. package/dist/summary/summaryManager.js.map +1 -1
  150. package/dist/throttler.js +16 -16
  151. package/dist/throttler.js.map +1 -1
  152. package/dist/tsdoc-metadata.json +1 -1
  153. package/lib/blobManager.d.ts +4 -4
  154. package/lib/blobManager.d.ts.map +1 -1
  155. package/lib/blobManager.js +56 -72
  156. package/lib/blobManager.js.map +1 -1
  157. package/lib/connectionTelemetry.d.ts.map +1 -1
  158. package/lib/connectionTelemetry.js +76 -43
  159. package/lib/connectionTelemetry.js.map +1 -1
  160. package/lib/containerHandleContext.js +3 -3
  161. package/lib/containerHandleContext.js.map +1 -1
  162. package/lib/containerRuntime.d.ts +88 -98
  163. package/lib/containerRuntime.d.ts.map +1 -1
  164. package/lib/containerRuntime.js +424 -416
  165. package/lib/containerRuntime.js.map +1 -1
  166. package/lib/dataStore.js +11 -11
  167. package/lib/dataStore.js.map +1 -1
  168. package/lib/dataStoreContext.d.ts +2 -4
  169. package/lib/dataStoreContext.d.ts.map +1 -1
  170. package/lib/dataStoreContext.js +60 -59
  171. package/lib/dataStoreContext.js.map +1 -1
  172. package/lib/dataStoreRegistry.d.ts +3 -0
  173. package/lib/dataStoreRegistry.d.ts.map +1 -1
  174. package/lib/dataStoreRegistry.js +6 -3
  175. package/lib/dataStoreRegistry.js.map +1 -1
  176. package/lib/dataStores.js +1 -1
  177. package/lib/dataStores.js.map +1 -1
  178. package/lib/deltaManagerProxyBase.js +4 -4
  179. package/lib/deltaManagerProxyBase.js.map +1 -1
  180. package/lib/deltaManagerSummarizerProxy.js +6 -6
  181. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  182. package/lib/deltaScheduler.js.map +1 -1
  183. package/lib/error.d.ts.map +1 -1
  184. package/lib/error.js.map +1 -1
  185. package/lib/gc/garbageCollection.d.ts.map +1 -1
  186. package/lib/gc/garbageCollection.js +23 -24
  187. package/lib/gc/garbageCollection.js.map +1 -1
  188. package/lib/gc/gcConfigs.js +2 -2
  189. package/lib/gc/gcConfigs.js.map +1 -1
  190. package/lib/gc/gcDefinitions.d.ts +34 -24
  191. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  192. package/lib/gc/gcDefinitions.js +9 -6
  193. package/lib/gc/gcDefinitions.js.map +1 -1
  194. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  195. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  196. package/lib/gc/gcTelemetry.d.ts +2 -2
  197. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  198. package/lib/gc/gcTelemetry.js +5 -5
  199. package/lib/gc/gcTelemetry.js.map +1 -1
  200. package/lib/gc/gcUnreferencedStateTracker.js +3 -3
  201. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  202. package/lib/gc/index.d.ts +1 -1
  203. package/lib/gc/index.d.ts.map +1 -1
  204. package/lib/gc/index.js +1 -1
  205. package/lib/gc/index.js.map +1 -1
  206. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  207. package/lib/id-compressor/idCompressor.js.map +1 -1
  208. package/lib/id-compressor/identifiers.d.ts +3 -3
  209. package/lib/id-compressor/identifiers.d.ts.map +1 -1
  210. package/lib/id-compressor/utilities.d.ts +3 -0
  211. package/lib/id-compressor/utilities.d.ts.map +1 -1
  212. package/lib/id-compressor/utilities.js +3 -0
  213. package/lib/id-compressor/utilities.js.map +1 -1
  214. package/lib/index.d.ts +5 -3
  215. package/lib/index.d.ts.map +1 -1
  216. package/lib/index.js +3 -1
  217. package/lib/index.js.map +1 -1
  218. package/lib/messageTypes.d.ts +137 -0
  219. package/lib/messageTypes.d.ts.map +1 -0
  220. package/lib/messageTypes.js +29 -0
  221. package/lib/messageTypes.js.map +1 -0
  222. package/lib/opLifecycle/batchManager.js +6 -6
  223. package/lib/opLifecycle/batchManager.js.map +1 -1
  224. package/lib/opLifecycle/definitions.d.ts +7 -3
  225. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  226. package/lib/opLifecycle/definitions.js.map +1 -1
  227. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  228. package/lib/opLifecycle/opDecompressor.js +0 -4
  229. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  230. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  231. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  232. package/lib/opLifecycle/opSplitter.js +1 -1
  233. package/lib/opLifecycle/opSplitter.js.map +1 -1
  234. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  235. package/lib/opLifecycle/outbox.js +7 -2
  236. package/lib/opLifecycle/outbox.js.map +1 -1
  237. package/lib/opLifecycle/remoteMessageProcessor.d.ts +17 -3
  238. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  239. package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
  240. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  241. package/lib/packageVersion.d.ts +1 -1
  242. package/lib/packageVersion.js +1 -1
  243. package/lib/packageVersion.js.map +1 -1
  244. package/lib/pendingStateManager.d.ts +4 -20
  245. package/lib/pendingStateManager.d.ts.map +1 -1
  246. package/lib/pendingStateManager.js +35 -45
  247. package/lib/pendingStateManager.js.map +1 -1
  248. package/lib/scheduleManager.js +6 -2
  249. package/lib/scheduleManager.js.map +1 -1
  250. package/lib/summary/orderedClientElection.d.ts +7 -4
  251. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  252. package/lib/summary/orderedClientElection.js +54 -54
  253. package/lib/summary/orderedClientElection.js.map +1 -1
  254. package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
  255. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  256. package/lib/summary/runWhileConnectedCoordinator.js +7 -6
  257. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  258. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  259. package/lib/summary/runningSummarizer.js +40 -38
  260. package/lib/summary/runningSummarizer.js.map +1 -1
  261. package/lib/summary/summarizer.d.ts +2 -0
  262. package/lib/summary/summarizer.d.ts.map +1 -1
  263. package/lib/summary/summarizer.js +19 -9
  264. package/lib/summary/summarizer.js.map +1 -1
  265. package/lib/summary/summarizerClientElection.js +6 -6
  266. package/lib/summary/summarizerClientElection.js.map +1 -1
  267. package/lib/summary/summarizerHeuristics.js +9 -9
  268. package/lib/summary/summarizerHeuristics.js.map +1 -1
  269. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
  270. package/lib/summary/summarizerNode/summarizerNode.js +8 -8
  271. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  272. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
  273. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  274. package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  275. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  276. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
  277. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  278. package/lib/summary/summarizerTypes.d.ts +107 -22
  279. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  280. package/lib/summary/summarizerTypes.js.map +1 -1
  281. package/lib/summary/summaryCollection.d.ts +18 -2
  282. package/lib/summary/summaryCollection.d.ts.map +1 -1
  283. package/lib/summary/summaryCollection.js +23 -21
  284. package/lib/summary/summaryCollection.js.map +1 -1
  285. package/lib/summary/summaryFormat.d.ts +15 -6
  286. package/lib/summary/summaryFormat.d.ts.map +1 -1
  287. package/lib/summary/summaryFormat.js.map +1 -1
  288. package/lib/summary/summaryGenerator.d.ts +3 -3
  289. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  290. package/lib/summary/summaryGenerator.js.map +1 -1
  291. package/lib/summary/summaryManager.d.ts +2 -2
  292. package/lib/summary/summaryManager.d.ts.map +1 -1
  293. package/lib/summary/summaryManager.js +9 -9
  294. package/lib/summary/summaryManager.js.map +1 -1
  295. package/lib/throttler.js +16 -16
  296. package/lib/throttler.js.map +1 -1
  297. package/package.json +27 -28
  298. package/src/blobManager.ts +64 -77
  299. package/src/connectionTelemetry.ts +97 -52
  300. package/src/containerRuntime.ts +337 -341
  301. package/src/dataStore.ts +3 -3
  302. package/src/dataStoreContext.ts +7 -7
  303. package/src/dataStoreRegistry.ts +3 -0
  304. package/src/dataStores.ts +1 -1
  305. package/src/error.ts +4 -1
  306. package/src/gc/garbageCollection.ts +12 -11
  307. package/src/gc/gcConfigs.ts +3 -3
  308. package/src/gc/gcDefinitions.ts +35 -25
  309. package/src/gc/gcSummaryDefinitions.ts +1 -1
  310. package/src/gc/gcTelemetry.ts +6 -5
  311. package/src/gc/index.ts +2 -2
  312. package/src/id-compressor/utilities.ts +3 -0
  313. package/src/index.ts +21 -5
  314. package/src/messageTypes.ts +228 -0
  315. package/src/opLifecycle/README.md +93 -68
  316. package/src/opLifecycle/definitions.ts +5 -1
  317. package/src/opLifecycle/opDecompressor.ts +0 -8
  318. package/src/opLifecycle/opGroupingManager.ts +2 -4
  319. package/src/opLifecycle/opSplitter.ts +2 -2
  320. package/src/opLifecycle/outbox.ts +3 -0
  321. package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
  322. package/src/packageVersion.ts +1 -1
  323. package/src/pendingStateManager.ts +31 -52
  324. package/src/scheduleManager.ts +2 -0
  325. package/src/summary/orderedClientElection.ts +4 -1
  326. package/src/summary/runWhileConnectedCoordinator.ts +5 -1
  327. package/src/summary/runningSummarizer.ts +3 -1
  328. package/src/summary/summarizer.ts +21 -7
  329. package/src/summary/summarizerNode/summarizerNode.ts +1 -1
  330. package/src/summary/summarizerTypes.ts +96 -11
  331. package/src/summary/summaryCollection.ts +19 -1
  332. package/src/summary/summaryFormat.ts +11 -1
  333. package/src/summary/summaryGenerator.ts +3 -3
  334. package/src/summary/summaryManager.ts +2 -2
  335. package/src/gc/gcEarlyAdoption.md +0 -145
@@ -8,7 +8,7 @@ import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
8
8
  import { readAndParse } from "@fluidframework/driver-utils";
9
9
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
10
10
  import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
11
- import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
11
+ import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, seqFromTree, calculateStats, TelemetryContext, responseToException, } from "@fluidframework/runtime-utils";
12
12
  import { v4 as uuid } from "uuid";
13
13
  import { ContainerFluidHandleContext } from "./containerHandleContext";
14
14
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
@@ -25,32 +25,12 @@ import { BindBatchTracker } from "./batchTracker";
25
25
  import { ScheduleManager } from "./scheduleManager";
26
26
  import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, OpGroupingManager, getLongStack, } from "./opLifecycle";
27
27
  import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
28
- export var ContainerMessageType;
29
- (function (ContainerMessageType) {
30
- // An op to be delivered to store
31
- ContainerMessageType["FluidDataStoreOp"] = "component";
32
- // Creates a new store
33
- ContainerMessageType["Attach"] = "attach";
34
- // Chunked operation.
35
- ContainerMessageType["ChunkedOp"] = "chunkedOp";
36
- // Signifies that a blob has been attached and should not be garbage collected by storage
37
- ContainerMessageType["BlobAttach"] = "blobAttach";
38
- // Ties our new clientId to our old one on reconnect
39
- ContainerMessageType["Rejoin"] = "rejoin";
40
- // Sets the alias of a root data store
41
- ContainerMessageType["Alias"] = "alias";
42
- /**
43
- * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
44
- * the last allocation op was sent.
45
- * See the [IdCompressor README](./id-compressor/README.md) for more details.
46
- */
47
- ContainerMessageType["IdAllocation"] = "idAllocation";
48
- })(ContainerMessageType || (ContainerMessageType = {}));
28
+ import { ContainerMessageType, } from "./messageTypes";
49
29
  /**
50
30
  * Utility to implement compat behaviors given an unknown message type
51
31
  * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
52
32
  *
53
- * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
33
+ * @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
54
34
  * handled before calling this function (e.g. in a switch statement).
55
35
  * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
56
36
  */
@@ -58,6 +38,15 @@ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, co
58
38
  // undefined defaults to same behavior as "FailToProcess"
59
39
  return compatBehavior === "Ignore";
60
40
  }
41
+ function prepareLocalContainerRuntimeIdAllocationMessageForTransit(message) {
42
+ // Remove the stashedState from the op if it's a stashed op
43
+ if ("stashedState" in message.contents) {
44
+ delete message.contents.stashedState;
45
+ }
46
+ }
47
+ /**
48
+ * @public
49
+ */
61
50
  export const DefaultSummaryConfiguration = {
62
51
  state: "enabled",
63
52
  minIdleTime: 0,
@@ -74,6 +63,7 @@ export const DefaultSummaryConfiguration = {
74
63
  };
75
64
  /**
76
65
  * Accepted header keys for requests coming to the runtime.
66
+ * @public
77
67
  */
78
68
  export var RuntimeHeaders;
79
69
  (function (RuntimeHeaders) {
@@ -82,13 +72,24 @@ export var RuntimeHeaders;
82
72
  /** True if the request is coming from an IFluidHandle. */
83
73
  RuntimeHeaders["viaHandle"] = "viaHandle";
84
74
  })(RuntimeHeaders || (RuntimeHeaders = {}));
85
- /** True if a tombstoned object should be returned without erroring */
75
+ /** True if a tombstoned object should be returned without erroring
76
+ * @public
77
+ */
86
78
  export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
87
- /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
79
+ /**
80
+ * [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
81
+ * @public
82
+ */
88
83
  export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
89
- /** Tombstone error responses will have this header set to true */
84
+ /**
85
+ * Tombstone error responses will have this header set to true
86
+ * @public
87
+ */
90
88
  export const TombstoneResponseHeaderKey = "isTombstoned";
91
- /** Inactive error responses will have this header set to true */
89
+ /**
90
+ * Inactive error responses will have this header set to true
91
+ * @public
92
+ */
92
93
  export const InactiveResponseHeaderKey = "isInactive";
93
94
  /** Default values for Runtime Headers */
94
95
  export const defaultRuntimeHeaderData = {
@@ -98,6 +99,7 @@ export const defaultRuntimeHeaderData = {
98
99
  };
99
100
  /**
100
101
  * Available compression algorithms for op compression.
102
+ * @public
101
103
  */
102
104
  export var CompressionAlgorithms;
103
105
  (function (CompressionAlgorithms) {
@@ -127,7 +129,8 @@ export const defaultPendingOpsRetryDelayMs = 1000;
127
129
  */
128
130
  const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
129
131
  /**
130
- * @deprecated - use ContainerRuntimeMessage instead
132
+ * @deprecated use ContainerRuntimeMessageType instead
133
+ * @public
131
134
  */
132
135
  export var RuntimeMessage;
133
136
  (function (RuntimeMessage) {
@@ -140,7 +143,8 @@ export var RuntimeMessage;
140
143
  RuntimeMessage["Operation"] = "op";
141
144
  })(RuntimeMessage || (RuntimeMessage = {}));
142
145
  /**
143
- * @deprecated - please use version in driver-utils
146
+ * @deprecated please use version in driver-utils
147
+ * @public
144
148
  */
145
149
  export function isRuntimeMessage(message) {
146
150
  return Object.values(RuntimeMessage).includes(message.type);
@@ -149,6 +153,7 @@ export function isRuntimeMessage(message) {
149
153
  * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
150
154
  * special-case for document dirty state. Ultimately we should have no special-cases from the
151
155
  * ContainerRuntime's perspective.
156
+ * @public
152
157
  */
153
158
  export const agentSchedulerId = "_scheduler";
154
159
  // safely check navigator and get the hardware spec value
@@ -178,20 +183,276 @@ export const makeLegacySendBatchFn = (submitFn, deltaManager) => (batch) => {
178
183
  }
179
184
  deltaManager.flush();
180
185
  };
186
+ const summarizerRequestUrl = "_summarizer";
187
+ /**
188
+ * Create and retrieve the summmarizer
189
+ */
190
+ async function createSummarizer(loader, url) {
191
+ const request = {
192
+ headers: {
193
+ [LoaderHeader.cache]: false,
194
+ [LoaderHeader.clientDetails]: {
195
+ capabilities: { interactive: false },
196
+ type: summarizerClientType,
197
+ },
198
+ [DriverHeader.summarizingClient]: true,
199
+ [LoaderHeader.reconnect]: false,
200
+ },
201
+ url,
202
+ };
203
+ const resolvedContainer = await loader.resolve(request);
204
+ let fluidObject;
205
+ // Older containers may not have the "getEntryPoint" API
206
+ // ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
207
+ if (resolvedContainer.getEntryPoint !== undefined) {
208
+ fluidObject = await resolvedContainer.getEntryPoint();
209
+ }
210
+ else {
211
+ const response = await resolvedContainer.request({ url: `/${summarizerRequestUrl}` });
212
+ if (response.status !== 200 || response.mimeType !== "fluid/object") {
213
+ throw responseToException(response, request);
214
+ }
215
+ fluidObject = response.value;
216
+ }
217
+ if (fluidObject?.ISummarizer === undefined) {
218
+ throw new UsageError("Fluid object does not implement ISummarizer");
219
+ }
220
+ return fluidObject.ISummarizer;
221
+ }
222
+ /**
223
+ * This function is not supported publicly and exists for e2e testing
224
+ * @internal
225
+ */
226
+ export async function TEST_requestSummarizer(loader, url) {
227
+ return createSummarizer(loader, url);
228
+ }
181
229
  /**
182
230
  * Represents the runtime of the container. Contains helper functions/state of the container.
183
231
  * It will define the store level mappings.
232
+ * @public
184
233
  */
185
234
  export class ContainerRuntime extends TypedEventEmitter {
235
+ /**
236
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
237
+ */
238
+ get IFluidRouter() {
239
+ return this;
240
+ }
241
+ /**
242
+ * @deprecated use loadRuntime instead.
243
+ * Load the stores from a snapshot and returns the runtime.
244
+ * @param context - Context of the container.
245
+ * @param registryEntries - Mapping to the stores.
246
+ * @param requestHandler - Request handlers for the container runtime
247
+ * @param runtimeOptions - Additional options to be passed to the runtime
248
+ * @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
249
+ * @param containerRuntimeCtor - (optional) Constructor to use to create the ContainerRuntime instance. This
250
+ * allows mixin classes to leverage this method to define their own async initializer.
251
+ */
252
+ static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
253
+ let existingFlag = true;
254
+ if (!existing) {
255
+ existingFlag = false;
256
+ }
257
+ return this.loadRuntime({
258
+ context,
259
+ registryEntries,
260
+ existing: existingFlag,
261
+ runtimeOptions,
262
+ containerScope,
263
+ containerRuntimeCtor,
264
+ requestHandler,
265
+ provideEntryPoint: () => {
266
+ throw new UsageError("ContainerRuntime.load is deprecated and should no longer be used");
267
+ },
268
+ });
269
+ }
270
+ /**
271
+ * Load the stores from a snapshot and returns the runtime.
272
+ * @param params - An object housing the runtime properties:
273
+ * - context - Context of the container.
274
+ * - registryEntries - Mapping from data store types to their corresponding factories.
275
+ * - existing - Pass 'true' if loading from an existing snapshot.
276
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
277
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
278
+ * - runtimeOptions - Additional options to be passed to the runtime
279
+ * - containerScope - runtime services provided with context
280
+ * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
281
+ * This allows mixin classes to leverage this method to define their own async initializer.
282
+ * - provideEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
283
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
284
+ */
285
+ static async loadRuntime(params) {
286
+ const { context, registryEntries, existing, requestHandler, provideEntryPoint, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
287
+ // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
288
+ // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
289
+ const backCompatContext = context;
290
+ const passLogger = backCompatContext.taggedLogger ??
291
+ // eslint-disable-next-line import/no-deprecated
292
+ new TaggedLoggerAdapter(backCompatContext.logger);
293
+ const logger = createChildLogger({
294
+ logger: passLogger,
295
+ properties: {
296
+ all: {
297
+ runtimeVersion: pkgVersion,
298
+ },
299
+ },
300
+ });
301
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
302
+ const registry = new FluidDataStoreRegistry(registryEntries);
303
+ const tryFetchBlob = async (blobName) => {
304
+ const blobId = context.baseSnapshot?.blobs[blobName];
305
+ if (context.baseSnapshot && blobId) {
306
+ // IContainerContext storage api return type still has undefined in 0.39 package version.
307
+ // So once we release 0.40 container-defn package we can remove this check.
308
+ assert(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
309
+ return readAndParse(context.storage, blobId);
310
+ }
311
+ };
312
+ const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
313
+ tryFetchBlob(chunksBlobName),
314
+ tryFetchBlob(metadataBlobName),
315
+ tryFetchBlob(electedSummarizerBlobName),
316
+ tryFetchBlob(aliasBlobName),
317
+ tryFetchBlob(idCompressorBlobName),
318
+ ]);
319
+ // read snapshot blobs needed for BlobManager to load
320
+ const blobManagerSnapshot = await BlobManager.load(context.baseSnapshot?.trees[blobsTreeName], async (id) => {
321
+ // IContainerContext storage api return type still has undefined in 0.39 package version.
322
+ // So once we release 0.40 container-defn package we can remove this check.
323
+ assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
324
+ return readAndParse(context.storage, id);
325
+ });
326
+ // Verify summary runtime sequence number matches protocol sequence number.
327
+ const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
328
+ // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
329
+ if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
330
+ const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
331
+ // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
332
+ if (loadSequenceNumberVerification !== "bypass" &&
333
+ runtimeSequenceNumber !== protocolSequenceNumber) {
334
+ // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
335
+ const error = new DataCorruptionError(
336
+ // pre-0.58 error message: SummaryMetadataMismatch
337
+ "Summary metadata mismatch", { runtimeVersion: pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
338
+ if (loadSequenceNumberVerification === "log") {
339
+ logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
340
+ }
341
+ else {
342
+ context.closeFn(error);
343
+ }
344
+ }
345
+ }
346
+ const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
347
+ let idCompressor;
348
+ if (idCompressorEnabled) {
349
+ const { IdCompressor, createSessionId } = await import("./id-compressor");
350
+ idCompressor =
351
+ serializedIdCompressor !== undefined
352
+ ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
353
+ : IdCompressor.create(logger);
354
+ }
355
+ const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
356
+ summaryOptions,
357
+ gcOptions,
358
+ loadSequenceNumberVerification,
359
+ flushMode,
360
+ compressionOptions,
361
+ maxBatchSizeInBytes,
362
+ chunkSizeInBytes,
363
+ enableRuntimeIdCompressor,
364
+ enableOpReentryCheck,
365
+ enableGroupedBatching,
366
+ }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, provideEntryPoint, requestHandler, undefined);
367
+ // Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
368
+ // or zero. This must be done before Container replays saved ops.
369
+ await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
370
+ // Initialize the base state of the runtime before it's returned.
371
+ await runtime.initializeBaseState();
372
+ return runtime;
373
+ }
374
+ get clientId() {
375
+ return this._getClientId();
376
+ }
377
+ get storage() {
378
+ return this._storage;
379
+ }
380
+ get flushMode() {
381
+ return this._flushMode;
382
+ }
383
+ get scope() {
384
+ return this.containerScope;
385
+ }
386
+ get IFluidDataStoreRegistry() {
387
+ return this.registry;
388
+ }
389
+ get attachState() {
390
+ return this._getAttachState();
391
+ }
392
+ get IFluidHandleContext() {
393
+ return this.handleContext;
394
+ }
395
+ /**
396
+ * Invokes the given callback and expects that no ops are submitted
397
+ * until execution finishes. If an op is submitted, an error will be raised.
398
+ *
399
+ * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
400
+ *
401
+ * @param callback - the callback to be invoked
402
+ */
403
+ ensureNoDataModelChanges(callback) {
404
+ this.ensureNoDataModelChangesCalls++;
405
+ try {
406
+ return callback();
407
+ }
408
+ finally {
409
+ this.ensureNoDataModelChangesCalls--;
410
+ }
411
+ }
412
+ get connected() {
413
+ return this._connected;
414
+ }
415
+ /** clientId of parent (non-summarizing) container that owns summarizer container */
416
+ get summarizerClientId() {
417
+ return this.summarizerClientElection?.electedClientId;
418
+ }
419
+ get disposed() {
420
+ return this._disposed;
421
+ }
422
+ get summarizer() {
423
+ assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
424
+ return this._summarizer;
425
+ }
426
+ isSummariesDisabled() {
427
+ return this.summaryConfiguration.state === "disabled";
428
+ }
429
+ isHeuristicsDisabled() {
430
+ return this.summaryConfiguration.state === "disableHeuristics";
431
+ }
432
+ getMaxOpsSinceLastSummary() {
433
+ return this.summaryConfiguration.state !== "disabled"
434
+ ? this.summaryConfiguration.maxOpsSinceLastSummary
435
+ : 0;
436
+ }
437
+ getInitialSummarizerDelayMs() {
438
+ // back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
439
+ // to ISummaryConfiguration in 0.60.
440
+ if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
441
+ return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
442
+ }
443
+ return this.summaryConfiguration.state !== "disabled"
444
+ ? this.summaryConfiguration.initialSummarizerDelayMs
445
+ : 0;
446
+ }
186
447
  /**
187
448
  * @internal
188
449
  */
189
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration = {
450
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, provideEntryPoint, requestHandler, summaryConfiguration = {
190
451
  // the defaults
191
452
  ...DefaultSummaryConfiguration,
192
453
  // the runtime configuration overrides
193
454
  ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
194
- }, initializeEntryPoint) {
455
+ }) {
195
456
  super();
196
457
  this.registry = registry;
197
458
  this.runtimeOptions = runtimeOptions;
@@ -483,7 +744,7 @@ export class ContainerRuntime extends TypedEventEmitter {
483
744
  this.summaryCollection.on("default", defaultAction);
484
745
  // Create the SummaryManager and mark the initial state
485
746
  this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
486
- this.summaryCollection, this.logger, this.formRequestSummarizerFn(loader), new Throttler(60 * 1000, // 60 sec delay window
747
+ this.summaryCollection, this.logger, this.formCreateSummarizerFn(loader), new Throttler(60 * 1000, // 60 sec delay window
487
748
  30 * 1000, // 30 sec max delay
488
749
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
489
750
  formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
@@ -495,26 +756,6 @@ export class ContainerRuntime extends TypedEventEmitter {
495
756
  this.summaryManager.start();
496
757
  }
497
758
  }
498
- this.deltaManager.on("readonly", (readonly) => {
499
- // we accumulate ops while being in read-only state.
500
- // once user gets write permissions and we have active connection, flush all pending ops.
501
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
502
- assert(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
503
- // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
504
- // when we either never send an op, or attempted to send it but we know for sure it was not
505
- // sequenced by server and will never be sequenced (i.e. was lost)
506
- // For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
507
- // ops that made it from previous connection, before switching clientId and raising "connected" event
508
- // But with read-only permissions, if we transition between read-only and r/w states while on same
509
- // connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
510
- // being in read-only state.
511
- // For that reason, we support getting to read-only state only when disconnected. This ensures that we
512
- // can rely on same safety mechanism and resend ops only when we establish new connection.
513
- // This is applicable for read-only permissions (event is raised before connection is properly registered),
514
- // but it's an extra requirement for Container.forceReadonly() API
515
- assert(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
516
- this.replayPendingStates();
517
- });
518
759
  // logging hardware telemetry
519
760
  logger.sendTelemetryEvent({
520
761
  eventName: "DeviceSpec",
@@ -548,234 +789,9 @@ export class ContainerRuntime extends TypedEventEmitter {
548
789
  assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
549
790
  return this._summarizer;
550
791
  }
551
- return initializeEntryPoint?.(this);
792
+ return provideEntryPoint(this);
552
793
  });
553
794
  }
554
- /**
555
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
556
- */
557
- get IFluidRouter() {
558
- return this;
559
- }
560
- /**
561
- * @deprecated - use loadRuntime instead.
562
- * Load the stores from a snapshot and returns the runtime.
563
- * @param context - Context of the container.
564
- * @param registryEntries - Mapping to the stores.
565
- * @param requestHandler - Request handlers for the container runtime
566
- * @param runtimeOptions - Additional options to be passed to the runtime
567
- * @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
568
- * @param containerRuntimeCtor - (optional) Constructor to use to create the ContainerRuntime instance. This
569
- * allows mixin classes to leverage this method to define their own async initializer.
570
- */
571
- static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
572
- let existingFlag = true;
573
- if (!existing) {
574
- existingFlag = false;
575
- }
576
- return this.loadRuntime({
577
- context,
578
- registryEntries,
579
- existing: existingFlag,
580
- requestHandler,
581
- runtimeOptions,
582
- containerScope,
583
- containerRuntimeCtor,
584
- });
585
- }
586
- /**
587
- * Load the stores from a snapshot and returns the runtime.
588
- * @param params - An object housing the runtime properties:
589
- * - context - Context of the container.
590
- * - registryEntries - Mapping from data store types to their corresponding factories.
591
- * - existing - Pass 'true' if loading from an existing snapshot.
592
- * - requestHandler - (optional) Request handler for the request() method of the container runtime.
593
- * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
594
- * - runtimeOptions - Additional options to be passed to the runtime
595
- * - containerScope - runtime services provided with context
596
- * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
597
- * This allows mixin classes to leverage this method to define their own async initializer.
598
- * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
599
- * This object should provide all the functionality that the Container is expected to provide to the loader layer.
600
- */
601
- static async loadRuntime(params) {
602
- const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
603
- const initializeEntryPoint = params.initializeEntryPoint ??
604
- (async (containerRuntime) => ({
605
- get IFluidRouter() {
606
- return this;
607
- },
608
- async request(req) {
609
- return containerRuntime.request(req);
610
- },
611
- }));
612
- // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
613
- // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
614
- const backCompatContext = context;
615
- const passLogger = backCompatContext.taggedLogger ??
616
- // eslint-disable-next-line import/no-deprecated
617
- new TaggedLoggerAdapter(backCompatContext.logger);
618
- const logger = createChildLogger({
619
- logger: passLogger,
620
- properties: {
621
- all: {
622
- runtimeVersion: pkgVersion,
623
- },
624
- },
625
- });
626
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
627
- const registry = new FluidDataStoreRegistry(registryEntries);
628
- const tryFetchBlob = async (blobName) => {
629
- const blobId = context.baseSnapshot?.blobs[blobName];
630
- if (context.baseSnapshot && blobId) {
631
- // IContainerContext storage api return type still has undefined in 0.39 package version.
632
- // So once we release 0.40 container-defn package we can remove this check.
633
- assert(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
634
- return readAndParse(context.storage, blobId);
635
- }
636
- };
637
- const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
638
- tryFetchBlob(chunksBlobName),
639
- tryFetchBlob(metadataBlobName),
640
- tryFetchBlob(electedSummarizerBlobName),
641
- tryFetchBlob(aliasBlobName),
642
- tryFetchBlob(idCompressorBlobName),
643
- ]);
644
- // read snapshot blobs needed for BlobManager to load
645
- const blobManagerSnapshot = await BlobManager.load(context.baseSnapshot?.trees[blobsTreeName], async (id) => {
646
- // IContainerContext storage api return type still has undefined in 0.39 package version.
647
- // So once we release 0.40 container-defn package we can remove this check.
648
- assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
649
- return readAndParse(context.storage, id);
650
- });
651
- // Verify summary runtime sequence number matches protocol sequence number.
652
- const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
653
- // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
654
- if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
655
- const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
656
- // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
657
- if (loadSequenceNumberVerification !== "bypass" &&
658
- runtimeSequenceNumber !== protocolSequenceNumber) {
659
- // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
660
- const error = new DataCorruptionError(
661
- // pre-0.58 error message: SummaryMetadataMismatch
662
- "Summary metadata mismatch", { runtimeVersion: pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
663
- if (loadSequenceNumberVerification === "log") {
664
- logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
665
- }
666
- else {
667
- context.closeFn(error);
668
- }
669
- }
670
- }
671
- const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
672
- let idCompressor;
673
- if (idCompressorEnabled) {
674
- const { IdCompressor, createSessionId } = await import("./id-compressor");
675
- idCompressor =
676
- serializedIdCompressor !== undefined
677
- ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
678
- : IdCompressor.create(logger);
679
- }
680
- const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
681
- summaryOptions,
682
- gcOptions,
683
- loadSequenceNumberVerification,
684
- flushMode,
685
- compressionOptions,
686
- maxBatchSizeInBytes,
687
- chunkSizeInBytes,
688
- enableRuntimeIdCompressor,
689
- enableOpReentryCheck,
690
- enableGroupedBatching,
691
- }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
692
- initializeEntryPoint);
693
- await runtime.blobManager.processStashedChanges();
694
- // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
695
- // at 1, so we won't see a replayed saved op with a sequence number of 0.
696
- await runtime.pendingStateManager.applyStashedOpsAt(0);
697
- // Initialize the base state of the runtime before it's returned.
698
- await runtime.initializeBaseState();
699
- return runtime;
700
- }
701
- get clientId() {
702
- return this._getClientId();
703
- }
704
- get storage() {
705
- return this._storage;
706
- }
707
- /** @deprecated - The functionality is no longer exposed publicly */
708
- get reSubmitFn() {
709
- return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
710
- // Note: compatDetails is not included in this deprecated API
711
- }
712
- get flushMode() {
713
- return this._flushMode;
714
- }
715
- get scope() {
716
- return this.containerScope;
717
- }
718
- get IFluidDataStoreRegistry() {
719
- return this.registry;
720
- }
721
- get attachState() {
722
- return this._getAttachState();
723
- }
724
- get IFluidHandleContext() {
725
- return this.handleContext;
726
- }
727
- /**
728
- * Invokes the given callback and expects that no ops are submitted
729
- * until execution finishes. If an op is submitted, an error will be raised.
730
- *
731
- * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
732
- *
733
- * @param callback - the callback to be invoked
734
- */
735
- ensureNoDataModelChanges(callback) {
736
- this.ensureNoDataModelChangesCalls++;
737
- try {
738
- return callback();
739
- }
740
- finally {
741
- this.ensureNoDataModelChangesCalls--;
742
- }
743
- }
744
- get connected() {
745
- return this._connected;
746
- }
747
- /** clientId of parent (non-summarizing) container that owns summarizer container */
748
- get summarizerClientId() {
749
- return this.summarizerClientElection?.electedClientId;
750
- }
751
- get disposed() {
752
- return this._disposed;
753
- }
754
- get summarizer() {
755
- assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
756
- return this._summarizer;
757
- }
758
- isSummariesDisabled() {
759
- return this.summaryConfiguration.state === "disabled";
760
- }
761
- isHeuristicsDisabled() {
762
- return this.summaryConfiguration.state === "disableHeuristics";
763
- }
764
- getMaxOpsSinceLastSummary() {
765
- return this.summaryConfiguration.state !== "disabled"
766
- ? this.summaryConfiguration.maxOpsSinceLastSummary
767
- : 0;
768
- }
769
- getInitialSummarizerDelayMs() {
770
- // back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
771
- // to ISummaryConfiguration in 0.60.
772
- if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
773
- return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
774
- }
775
- return this.summaryConfiguration.state !== "disabled"
776
- ? this.summaryConfiguration.initialSummarizerDelayMs
777
- : 0;
778
- }
779
795
  /**
780
796
  * Initializes the state from the base snapshot this container runtime loaded from.
781
797
  */
@@ -806,13 +822,13 @@ export class ContainerRuntime extends TypedEventEmitter {
806
822
  /**
807
823
  * Notifies this object about the request made to the container.
808
824
  * @param request - Request made to the handler.
809
- * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
825
+ * @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
810
826
  */
811
827
  async request(request) {
812
828
  try {
813
829
  const parser = RequestParser.create(request);
814
830
  const id = parser.pathParts[0];
815
- if (id === "_summarizer" && parser.pathParts.length === 1) {
831
+ if (id === summarizerRequestUrl && parser.pathParts.length === 1) {
816
832
  if (this._summarizer !== undefined) {
817
833
  return {
818
834
  status: 200,
@@ -823,6 +839,7 @@ export class ContainerRuntime extends TypedEventEmitter {
823
839
  return create404Response(request);
824
840
  }
825
841
  if (this.requestHandler !== undefined) {
842
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
826
843
  return this.requestHandler(parser, this);
827
844
  }
828
845
  return create404Response(request);
@@ -840,6 +857,7 @@ export class ContainerRuntime extends TypedEventEmitter {
840
857
  const requestParser = RequestParser.create(request);
841
858
  const id = requestParser.pathParts[0];
842
859
  if (id === "_channels") {
860
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
843
861
  return this.resolveHandle(requestParser.createSubRequest(1));
844
862
  }
845
863
  if (id === BlobManager.basePath && requestParser.isLeaf(2)) {
@@ -853,11 +871,14 @@ export class ContainerRuntime extends TypedEventEmitter {
853
871
  : create404Response(request);
854
872
  }
855
873
  else if (requestParser.pathParts.length > 0) {
856
- const dataStore = await this.getDataStoreFromRequest(id, request);
874
+ // Differentiate between requesting the dataStore directly, or one of its children
875
+ const requestForChild = !requestParser.isLeaf(1);
876
+ const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
857
877
  const subRequest = requestParser.createSubRequest(1);
858
878
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
859
879
  // unintentionally modifying the url if that changes.
860
880
  assert(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
881
+ // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
861
882
  return dataStore.request(subRequest);
862
883
  }
863
884
  return create404Response(request);
@@ -875,7 +896,7 @@ export class ContainerRuntime extends TypedEventEmitter {
875
896
  internalId(maybeAlias) {
876
897
  return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
877
898
  }
878
- async getDataStoreFromRequest(id, request) {
899
+ async getDataStoreFromRequest(id, request, requestForChild) {
879
900
  const headerData = {};
880
901
  if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
881
902
  headerData.wait = request.headers[RuntimeHeaders.wait];
@@ -886,6 +907,10 @@ export class ContainerRuntime extends TypedEventEmitter {
886
907
  if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
887
908
  headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
888
909
  }
910
+ // We allow Tombstone requests for sub-DataStore objects
911
+ if (requestForChild) {
912
+ headerData.allowTombstone = true;
913
+ }
889
914
  await this.dataStores.waitIfPendingAlias(id);
890
915
  const internalId = this.internalId(id);
891
916
  const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
@@ -1024,23 +1049,24 @@ export class ContainerRuntime extends TypedEventEmitter {
1024
1049
  * Parse an op's type and actual content from given serialized content
1025
1050
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
1026
1051
  */
1027
- parseOpContent(serializedContent) {
1028
- assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1029
- const { type, contents, compatDetails } = JSON.parse(serializedContent);
1030
- assert(type !== undefined, 0x6d6 /* incorrect op content format */);
1031
- return { type, contents, compatDetails };
1032
- }
1033
- async applyStashedOp(op) {
1052
+ // TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
1053
+ parseLocalOpContent(serializedContents) {
1054
+ assert(serializedContents !== undefined, 0x6d5 /* content must be defined */);
1055
+ const message = JSON.parse(serializedContents);
1056
+ assert(message.type !== undefined, 0x6d6 /* incorrect op content format */);
1057
+ return message;
1058
+ }
1059
+ async applyStashedOp(serializedOpContent) {
1034
1060
  // Need to parse from string for back-compat
1035
- const { type, contents, compatDetails } = this.parseOpContent(op);
1036
- switch (type) {
1061
+ const opContents = this.parseLocalOpContent(serializedOpContent);
1062
+ switch (opContents.type) {
1037
1063
  case ContainerMessageType.FluidDataStoreOp:
1038
- return this.dataStores.applyStashedOp(contents);
1064
+ return this.dataStores.applyStashedOp(opContents.contents);
1039
1065
  case ContainerMessageType.Attach:
1040
- return this.dataStores.applyStashedAttachOp(contents);
1066
+ return this.dataStores.applyStashedAttachOp(opContents.contents);
1041
1067
  case ContainerMessageType.IdAllocation:
1042
1068
  assert(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1043
- return this.applyStashedIdAllocationOp(contents);
1069
+ return this.applyStashedIdAllocationOp(opContents.contents);
1044
1070
  case ContainerMessageType.Alias:
1045
1071
  case ContainerMessageType.BlobAttach:
1046
1072
  return;
@@ -1052,11 +1078,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1052
1078
  // This should be extremely rare for stashed ops.
1053
1079
  // It would require a newer runtime stashing ops and then an older one applying them,
1054
1080
  // e.g. if an app rolled back its container version
1055
- const compatBehavior = compatDetails?.behavior;
1056
- if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
1081
+ const compatBehavior = opContents.compatDetails?.behavior;
1082
+ if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
1057
1083
  const error = DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1058
1084
  messageDetails: JSON.stringify({
1059
- type,
1085
+ type: opContents.type,
1060
1086
  compatBehavior,
1061
1087
  }),
1062
1088
  });
@@ -1075,6 +1101,23 @@ export class ContainerRuntime extends TypedEventEmitter {
1075
1101
  // Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
1076
1102
  return;
1077
1103
  }
1104
+ // If there are stashed blobs in the pending state, we need to delay
1105
+ // propagation of the "connected" event until we have uploaded them to
1106
+ // ensure we don't submit ops referencing a blob that has not been uploaded
1107
+ const connecting = connected && !this._connected;
1108
+ if (connecting && this.blobManager.hasPendingStashedBlobs()) {
1109
+ assert(!this.delayConnectClientId, 0x791 /* Connect event delay must be canceled before subsequent connect event */);
1110
+ assert(!!clientId, 0x792 /* Must have clientId when connecting */);
1111
+ this.delayConnectClientId = clientId;
1112
+ this.blobManager.processStashedChanges().then(() => {
1113
+ // make sure we didn't reconnect before the promise resolved
1114
+ if (this.delayConnectClientId === clientId && !this.disposed) {
1115
+ this.delayConnectClientId = undefined;
1116
+ this.setConnectionStateCore(connected, clientId);
1117
+ }
1118
+ }, (error) => this.closeFn(error));
1119
+ return;
1120
+ }
1078
1121
  this.setConnectionStateCore(connected, clientId);
1079
1122
  }
1080
1123
  setConnectionStateCore(connected, clientId) {
@@ -1127,18 +1170,33 @@ export class ContainerRuntime extends TypedEventEmitter {
1127
1170
  // or something different, like a system message.
1128
1171
  const modernRuntimeMessage = messageArg.type === MessageType.Operation;
1129
1172
  // Do shallow copy of message, as the processing flow will modify it.
1173
+ // There might be multiple container instances receiving the same message.
1174
+ // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1175
+ // but will not modify the contents object (likely it will replace it on the message).
1130
1176
  const messageCopy = { ...messageArg };
1131
1177
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1132
- this.processCore(message, local, modernRuntimeMessage);
1178
+ if (modernRuntimeMessage) {
1179
+ this.processCore({
1180
+ // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1181
+ // There is nothing really ensuring that anytime original message.type is Operation that
1182
+ // the result messages will be so. In the end modern bool being true only directs to
1183
+ // throw error if ultimately unrecognized without compat details saying otherwise.
1184
+ message: message,
1185
+ local,
1186
+ modernRuntimeMessage,
1187
+ });
1188
+ }
1189
+ else {
1190
+ // Unrecognized message will be ignored.
1191
+ this.processCore({ message, local, modernRuntimeMessage });
1192
+ }
1133
1193
  }
1134
1194
  }
1135
1195
  /**
1136
1196
  * Direct the message to the correct subsystem for processing, and implement other side effects
1137
- * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
1138
- * @param local - Did this client send the op?
1139
- * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
1140
1197
  */
1141
- processCore(message, local, modernRuntimeMessage) {
1198
+ processCore(messageWithContext) {
1199
+ const { message, local } = messageWithContext;
1142
1200
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1143
1201
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1144
1202
  // messages once a batch has been fully processed.
@@ -1146,16 +1204,18 @@ export class ContainerRuntime extends TypedEventEmitter {
1146
1204
  this._processedClientSequenceNumber = message.clientSequenceNumber;
1147
1205
  try {
1148
1206
  let localOpMetadata;
1149
- if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1150
- localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
1207
+ if (local &&
1208
+ messageWithContext.modernRuntimeMessage &&
1209
+ message.type !== ContainerMessageType.ChunkedOp) {
1210
+ localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
1151
1211
  }
1152
1212
  // If there are no more pending messages after processing a local message,
1153
1213
  // the document is no longer dirty.
1154
1214
  if (!this.hasPendingMessages()) {
1155
1215
  this.updateDocumentDirtyState(false);
1156
1216
  }
1157
- this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
1158
- this.emit("op", message, modernRuntimeMessage);
1217
+ this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
1218
+ this.emit("op", message, messageWithContext.modernRuntimeMessage);
1159
1219
  this.scheduleManager.afterOpProcessing(undefined, message);
1160
1220
  if (local) {
1161
1221
  // If we have processed a local op, this means that the container is
@@ -1170,29 +1230,29 @@ export class ContainerRuntime extends TypedEventEmitter {
1170
1230
  }
1171
1231
  }
1172
1232
  /**
1173
- * Assuming the given message is also a ContainerRuntimeMessage,
1233
+ * Assuming the given message is also a TypedContainerRuntimeMessage,
1174
1234
  * checks its type and dispatches the message to the appropriate handler in the runtime.
1175
- * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
1235
+ * Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
1176
1236
  */
1177
- validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
1178
- // Optimistically extract ContainerRuntimeMessage-specific props from the message
1179
- const { type: maybeContainerMessageType, compatDetails } = message;
1180
- switch (maybeContainerMessageType) {
1237
+ validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata) {
1238
+ // TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
1239
+ const { local } = messageWithContext;
1240
+ switch (messageWithContext.message.type) {
1181
1241
  case ContainerMessageType.Attach:
1182
- this.dataStores.processAttachMessage(message, local);
1242
+ this.dataStores.processAttachMessage(messageWithContext.message, local);
1183
1243
  break;
1184
1244
  case ContainerMessageType.Alias:
1185
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
1245
+ this.dataStores.processAliasMessage(messageWithContext.message, localOpMetadata, local);
1186
1246
  break;
1187
1247
  case ContainerMessageType.FluidDataStoreOp:
1188
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1248
+ this.dataStores.processFluidDataStoreOp(messageWithContext.message, local, localOpMetadata);
1189
1249
  break;
1190
1250
  case ContainerMessageType.BlobAttach:
1191
- this.blobManager.processBlobAttachOp(message, local);
1251
+ this.blobManager.processBlobAttachOp(messageWithContext.message, local);
1192
1252
  break;
1193
1253
  case ContainerMessageType.IdAllocation:
1194
1254
  assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1195
- this.idCompressor.finalizeCreationRange(message.contents);
1255
+ this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
1196
1256
  break;
1197
1257
  case ContainerMessageType.ChunkedOp:
1198
1258
  case ContainerMessageType.Rejoin:
@@ -1200,11 +1260,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1200
1260
  default: {
1201
1261
  // If we didn't necessarily expect a runtime message type, then no worries - just return
1202
1262
  // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
1203
- if (!expectRuntimeMessageType) {
1263
+ if (!messageWithContext.modernRuntimeMessage) {
1204
1264
  return;
1205
1265
  }
1206
- const compatBehavior = compatDetails?.behavior;
1207
- if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
1266
+ const compatBehavior = messageWithContext.message.compatDetails?.behavior;
1267
+ if (!compatBehaviorAllowsMessageType(messageWithContext.message.type, compatBehavior)) {
1268
+ const { message } = messageWithContext;
1208
1269
  const error = DataProcessingError.create(
1209
1270
  // Former assert 0x3ce
1210
1271
  "Runtime message of unknown type", "OpProcessing", message, {
@@ -1280,8 +1341,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1280
1341
  * Returns the runtime of the data store.
1281
1342
  * @param id - Id supplied during creating the data store.
1282
1343
  * @param wait - True if you want to wait for it.
1283
- * @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
1344
+ * @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
1284
1345
  */
1346
+ // eslint-disable-next-line import/no-deprecated
1285
1347
  async getRootDataStore(id, wait = true) {
1286
1348
  return this.getRootDataStoreChannel(id, wait);
1287
1349
  }
@@ -1578,7 +1640,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1578
1640
  this.dataStores.updateUnusedRoutes(dataStoreRoutes);
1579
1641
  }
1580
1642
  /**
1581
- * @deprecated - Replaced by deleteSweepReadyNodes.
1643
+ * @deprecated Replaced by deleteSweepReadyNodes.
1582
1644
  */
1583
1645
  deleteUnusedNodes(unusedRoutes) {
1584
1646
  throw new Error("deleteUnusedRoutes should not be called");
@@ -1700,16 +1762,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1700
1762
  },
1701
1763
  });
1702
1764
  assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1765
+ // We close the summarizer and download a new snapshot and reload the container
1703
1766
  let latestSnapshotVersionId;
1704
- if (refreshLatestAck) {
1705
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(createChildLogger({
1767
+ if (refreshLatestAck === true) {
1768
+ return this.prefetchLatestSummaryThenClose(createChildLogger({
1706
1769
  logger: summaryNumberLogger,
1707
1770
  properties: { all: { safeSummary: true } },
1708
1771
  }));
1709
- const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1710
- latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1711
- // We might need to catch up to the latest summary's reference sequence number before pausing.
1712
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1713
1772
  }
1714
1773
  // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
1715
1774
  // incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
@@ -2233,34 +2292,31 @@ export class ContainerRuntime extends TypedEventEmitter {
2233
2292
  }
2234
2293
  reSubmit(message) {
2235
2294
  // Need to parse from string for back-compat
2236
- const containerRuntimeMessage = this.parseOpContent(message.content);
2295
+ const containerRuntimeMessage = this.parseLocalOpContent(message.content);
2237
2296
  this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
2238
2297
  }
2239
2298
  /**
2240
2299
  * Finds the right store and asks it to resubmit the message. This typically happens when we
2241
2300
  * reconnect and there are pending messages.
2242
- * @param message - The original ContainerRuntimeMessage.
2301
+ * @param message - The original LocalContainerRuntimeMessage.
2243
2302
  * @param localOpMetadata - The local metadata associated with the original message.
2244
2303
  */
2245
2304
  reSubmitCore(message, localOpMetadata, opMetadata) {
2246
- const contents = message.contents;
2247
2305
  switch (message.type) {
2248
2306
  case ContainerMessageType.FluidDataStoreOp:
2249
2307
  // For Operations, call resubmitDataStoreOp which will find the right store
2250
2308
  // and trigger resubmission on it.
2251
- this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
2309
+ this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
2252
2310
  break;
2253
2311
  case ContainerMessageType.Attach:
2254
2312
  case ContainerMessageType.Alias:
2255
2313
  this.submit(message, localOpMetadata);
2256
2314
  break;
2257
- case ContainerMessageType.IdAllocation:
2258
- // Remove the stashedState from the op if it's a stashed op
2259
- if (contents.stashedState !== undefined) {
2260
- delete contents.stashedState;
2261
- }
2315
+ case ContainerMessageType.IdAllocation: {
2316
+ prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
2262
2317
  this.submit(message, localOpMetadata);
2263
2318
  break;
2319
+ }
2264
2320
  case ContainerMessageType.ChunkedOp:
2265
2321
  throw new Error(`chunkedOp not expected here`);
2266
2322
  case ContainerMessageType.BlobAttach:
@@ -2294,7 +2350,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2294
2350
  }
2295
2351
  rollback(content, localOpMetadata) {
2296
2352
  // Need to parse from string for back-compat
2297
- const { type, contents } = this.parseOpContent(content);
2353
+ const { type, contents } = this.parseLocalOpContent(content);
2298
2354
  switch (type) {
2299
2355
  case ContainerMessageType.FluidDataStoreOp:
2300
2356
  // For operations, call rollbackDataStoreOp which will find the right store
@@ -2306,17 +2362,6 @@ export class ContainerRuntime extends TypedEventEmitter {
2306
2362
  throw new Error(`Can't rollback ${type}`);
2307
2363
  }
2308
2364
  }
2309
- async waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger) {
2310
- if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
2311
- // We need to catch up to the latest summary's reference sequence number before proceeding.
2312
- await PerformanceEvent.timedExecAsync(summaryLogger, {
2313
- eventName: "WaitingForSeq",
2314
- lastSequenceNumber: this.deltaManager.lastSequenceNumber,
2315
- targetSequenceNumber: latestSnapshotRefSeq,
2316
- lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
2317
- }, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
2318
- }
2319
- }
2320
2365
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2321
2366
  async refreshLatestSummaryAck(options) {
2322
2367
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
@@ -2331,11 +2376,11 @@ export class ContainerRuntime extends TypedEventEmitter {
2331
2376
  * and then close as the current main client is likely to be re-elected as the parent summarizer again.
2332
2377
  */
2333
2378
  if (!result.isSummaryTracked && result.isSummaryNewer) {
2334
- const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2379
+ const fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2335
2380
  eventName: "RefreshLatestSummaryAckFetch",
2336
2381
  ackHandle,
2337
2382
  targetSequenceNumber: summaryRefSeq,
2338
- }, readAndParseBlob, null);
2383
+ }, readAndParseBlob);
2339
2384
  /**
2340
2385
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
2341
2386
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -2362,41 +2407,42 @@ export class ContainerRuntime extends TypedEventEmitter {
2362
2407
  await this.garbageCollector.refreshLatestSummary(result);
2363
2408
  }
2364
2409
  /**
2365
- * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
2366
- * internal state as it should be considered the latest summary ack.
2410
+ * Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
2411
+ * summarizer to reload from new state.
2367
2412
  * @param summaryLogger - logger to use when fetching snapshot from storage
2368
- * @returns downloaded snapshot's reference sequence number
2413
+ * @returns a generic summarization error
2369
2414
  */
2370
- async refreshLatestSummaryAckFromServer(summaryLogger) {
2415
+ async prefetchLatestSummaryThenClose(summaryLogger) {
2371
2416
  const readAndParseBlob = async (id) => readAndParse(this.storage, id);
2372
- const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
2417
+ // This is a performance optimization as the same parent is likely to be elected again, and would use its
2418
+ // cache to fetch the snapshot instead of the network.
2419
+ await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2373
2420
  eventName: "RefreshLatestSummaryFromServerFetch",
2374
- }, readAndParseBlob, null);
2421
+ }, readAndParseBlob);
2375
2422
  await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
2376
- return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2423
+ return {
2424
+ stage: "base",
2425
+ error: "summary state stale - Unsupported option 'refreshLatestAck'",
2426
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2427
+ minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
2428
+ };
2377
2429
  }
2378
2430
  async closeStaleSummarizer(codePath) {
2379
- this.mc.logger.sendTelemetryEvent({
2380
- eventName: "ClosingSummarizerOnSummaryStale",
2381
- codePath,
2382
- message: "Stopping fetch from storage",
2383
- closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2384
- }, new GenericError("Restarting summarizer instead of refreshing"));
2385
2431
  // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2386
2432
  await delay(this.closeSummarizerDelayMs);
2387
2433
  this._summarizer?.stop("latestSummaryStateStale");
2388
2434
  this.disposeFn();
2389
2435
  }
2390
2436
  /**
2391
- * Downloads snapshot from storage with the given versionId or latest if versionId is null.
2437
+ * Downloads the latest snapshot from storage.
2392
2438
  * By default, it also closes the container after downloading the snapshot. However, this may be
2393
2439
  * overridden via options.
2394
2440
  */
2395
- async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
2441
+ async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2396
2442
  return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2397
2443
  const stats = {};
2398
2444
  const trace = Trace.start();
2399
- const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
2445
+ const versions = await this.storage.getVersions(null, 1, "prefetchLatestSummaryBeforeClose", FetchSource.noCache);
2400
2446
  assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2401
2447
  stats.getVersionDuration = trace.trace().duration;
2402
2448
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
@@ -2424,15 +2470,17 @@ export class ContainerRuntime extends TypedEventEmitter {
2424
2470
  if (this._orderSequentiallyCalls !== 0) {
2425
2471
  throw new UsageError("can't get state during orderSequentially");
2426
2472
  }
2427
- const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2428
- const pending = this.pendingStateManager.getLocalState();
2429
- if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2430
- return; // no pending state to save
2431
- }
2432
2473
  // Flush pending batch.
2433
2474
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2434
2475
  // to close current batch.
2435
2476
  this.flush();
2477
+ const pendingAttachmentBlobs = waitBlobsToAttach
2478
+ ? await this.blobManager.attachAndGetPendingBlobs()
2479
+ : undefined;
2480
+ const pending = this.pendingStateManager.getLocalState();
2481
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2482
+ return; // no pending state to save
2483
+ }
2436
2484
  const pendingState = {
2437
2485
  pending,
2438
2486
  pendingAttachmentBlobs,
@@ -2473,29 +2521,11 @@ export class ContainerRuntime extends TypedEventEmitter {
2473
2521
  }
2474
2522
  }
2475
2523
  /**
2476
- * * Forms a function that will request a Summarizer.
2477
- * @param loaderRouter - the loader acting as an IFluidRouter
2478
- * */
2479
- formRequestSummarizerFn(loaderRouter) {
2524
+ * Forms a function that will create and retrieve a Summarizer.
2525
+ */
2526
+ formCreateSummarizerFn(loader) {
2480
2527
  return async () => {
2481
- const request = {
2482
- headers: {
2483
- [LoaderHeader.cache]: false,
2484
- [LoaderHeader.clientDetails]: {
2485
- capabilities: { interactive: false },
2486
- type: summarizerClientType,
2487
- },
2488
- [DriverHeader.summarizingClient]: true,
2489
- [LoaderHeader.reconnect]: false,
2490
- },
2491
- url: "/_summarizer",
2492
- };
2493
- const fluidObject = await requestFluidObject(loaderRouter, request);
2494
- const summarizer = fluidObject.ISummarizer;
2495
- if (!summarizer) {
2496
- throw new UsageError("Fluid object does not implement ISummarizer");
2497
- }
2498
- return summarizer;
2528
+ return createSummarizer(loader, `/${summarizerRequestUrl}`);
2499
2529
  };
2500
2530
  }
2501
2531
  validateSummaryHeuristicConfiguration(configuration) {
@@ -2514,26 +2544,4 @@ export class ContainerRuntime extends TypedEventEmitter {
2514
2544
  return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
2515
2545
  }
2516
2546
  }
2517
- /**
2518
- * Wait for a specific sequence number. Promise should resolve when we reach that number,
2519
- * or reject if closed.
2520
- */
2521
- const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
2522
- // TODO: remove cast to any when actual event is determined
2523
- deltaManager.on("closed", reject);
2524
- deltaManager.on("disposed", reject);
2525
- // If we already reached target sequence number, simply resolve the promise.
2526
- if (deltaManager.lastSequenceNumber >= targetSeq) {
2527
- resolve();
2528
- }
2529
- else {
2530
- const handleOp = (message) => {
2531
- if (message.sequenceNumber >= targetSeq) {
2532
- resolve();
2533
- deltaManager.off("op", handleOp);
2534
- }
2535
- };
2536
- deltaManager.on("op", handleOp);
2537
- }
2538
- });
2539
2547
  //# sourceMappingURL=containerRuntime.js.map