@fluidframework/container-runtime 2.0.0-internal.5.3.2 → 2.0.0-internal.6.0.0

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 (290) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/batchTracker.d.ts +2 -1
  3. package/dist/batchTracker.d.ts.map +1 -1
  4. package/dist/batchTracker.js +1 -1
  5. package/dist/batchTracker.js.map +1 -1
  6. package/dist/blobManager.d.ts +13 -2
  7. package/dist/blobManager.d.ts.map +1 -1
  8. package/dist/blobManager.js +103 -25
  9. package/dist/blobManager.js.map +1 -1
  10. package/dist/connectionTelemetry.d.ts.map +1 -1
  11. package/dist/connectionTelemetry.js +12 -4
  12. package/dist/connectionTelemetry.js.map +1 -1
  13. package/dist/containerRuntime.d.ts +69 -22
  14. package/dist/containerRuntime.d.ts.map +1 -1
  15. package/dist/containerRuntime.js +344 -238
  16. package/dist/containerRuntime.js.map +1 -1
  17. package/dist/dataStore.js +11 -2
  18. package/dist/dataStore.js.map +1 -1
  19. package/dist/dataStoreContext.d.ts +1 -1
  20. package/dist/dataStoreContext.d.ts.map +1 -1
  21. package/dist/dataStoreContext.js +40 -44
  22. package/dist/dataStoreContext.js.map +1 -1
  23. package/dist/dataStoreContexts.js +1 -1
  24. package/dist/dataStoreContexts.js.map +1 -1
  25. package/dist/dataStores.d.ts +21 -5
  26. package/dist/dataStores.d.ts.map +1 -1
  27. package/dist/dataStores.js +102 -58
  28. package/dist/dataStores.js.map +1 -1
  29. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  30. package/dist/deltaManagerSummarizerProxy.js +2 -0
  31. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  32. package/dist/deltaScheduler.d.ts.map +1 -1
  33. package/dist/deltaScheduler.js +5 -5
  34. package/dist/deltaScheduler.js.map +1 -1
  35. package/dist/gc/garbageCollection.d.ts.map +1 -1
  36. package/dist/gc/garbageCollection.js +29 -25
  37. package/dist/gc/garbageCollection.js.map +1 -1
  38. package/dist/gc/gcConfigs.js +13 -11
  39. package/dist/gc/gcConfigs.js.map +1 -1
  40. package/dist/gc/gcHelpers.d.ts +1 -0
  41. package/dist/gc/gcHelpers.d.ts.map +1 -1
  42. package/dist/gc/gcHelpers.js +5 -6
  43. package/dist/gc/gcHelpers.js.map +1 -1
  44. package/dist/gc/gcSummaryStateTracker.js +4 -6
  45. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  46. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  47. package/dist/gc/gcTelemetry.js +44 -33
  48. package/dist/gc/gcTelemetry.js.map +1 -1
  49. package/dist/id-compressor/idCompressor.d.ts +3 -3
  50. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  51. package/dist/id-compressor/idCompressor.js +52 -52
  52. package/dist/id-compressor/idCompressor.js.map +1 -1
  53. package/dist/id-compressor/idRange.js +2 -2
  54. package/dist/id-compressor/idRange.js.map +1 -1
  55. package/dist/id-compressor/sessionIdNormalizer.js +11 -16
  56. package/dist/id-compressor/sessionIdNormalizer.js.map +1 -1
  57. package/dist/index.d.ts +1 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/opLifecycle/batchManager.js +10 -6
  61. package/dist/opLifecycle/batchManager.js.map +1 -1
  62. package/dist/opLifecycle/opCompressor.d.ts +2 -2
  63. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  64. package/dist/opLifecycle/opCompressor.js +7 -2
  65. package/dist/opLifecycle/opCompressor.js.map +1 -1
  66. package/dist/opLifecycle/opDecompressor.d.ts +2 -2
  67. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  68. package/dist/opLifecycle/opDecompressor.js +12 -10
  69. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  70. package/dist/opLifecycle/opGroupingManager.js +13 -5
  71. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  72. package/dist/opLifecycle/opSplitter.d.ts +2 -2
  73. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  74. package/dist/opLifecycle/opSplitter.js +11 -7
  75. package/dist/opLifecycle/opSplitter.js.map +1 -1
  76. package/dist/opLifecycle/outbox.d.ts +6 -5
  77. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  78. package/dist/opLifecycle/outbox.js +6 -14
  79. package/dist/opLifecycle/outbox.js.map +1 -1
  80. package/dist/opLifecycle/remoteMessageProcessor.d.ts +6 -1
  81. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  82. package/dist/opLifecycle/remoteMessageProcessor.js +8 -2
  83. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  84. package/dist/opProperties.js +1 -2
  85. package/dist/opProperties.js.map +1 -1
  86. package/dist/packageVersion.d.ts +1 -1
  87. package/dist/packageVersion.js +1 -1
  88. package/dist/packageVersion.js.map +1 -1
  89. package/dist/pendingStateManager.d.ts +6 -3
  90. package/dist/pendingStateManager.d.ts.map +1 -1
  91. package/dist/pendingStateManager.js +41 -32
  92. package/dist/pendingStateManager.js.map +1 -1
  93. package/dist/scheduleManager.d.ts.map +1 -1
  94. package/dist/scheduleManager.js +15 -11
  95. package/dist/scheduleManager.js.map +1 -1
  96. package/dist/summary/orderedClientElection.d.ts +2 -1
  97. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  98. package/dist/summary/orderedClientElection.js +18 -19
  99. package/dist/summary/orderedClientElection.js.map +1 -1
  100. package/dist/summary/runningSummarizer.d.ts +3 -5
  101. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  102. package/dist/summary/runningSummarizer.js +42 -66
  103. package/dist/summary/runningSummarizer.js.map +1 -1
  104. package/dist/summary/summarizer.js +5 -8
  105. package/dist/summary/summarizer.js.map +1 -1
  106. package/dist/summary/summarizerClientElection.js +5 -9
  107. package/dist/summary/summarizerClientElection.js.map +1 -1
  108. package/dist/summary/summarizerHeuristics.js +8 -12
  109. package/dist/summary/summarizerHeuristics.js.map +1 -1
  110. package/dist/summary/summarizerNode/summarizerNode.d.ts +5 -5
  111. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  112. package/dist/summary/summarizerNode/summarizerNode.js +26 -22
  113. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  114. package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  115. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  116. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -3
  117. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  118. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +13 -16
  119. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  120. package/dist/summary/summaryCollection.js +3 -5
  121. package/dist/summary/summaryCollection.js.map +1 -1
  122. package/dist/summary/summaryFormat.js +1 -2
  123. package/dist/summary/summaryFormat.js.map +1 -1
  124. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  125. package/dist/summary/summaryGenerator.js +67 -21
  126. package/dist/summary/summaryGenerator.js.map +1 -1
  127. package/dist/summary/summaryManager.d.ts +2 -3
  128. package/dist/summary/summaryManager.d.ts.map +1 -1
  129. package/dist/summary/summaryManager.js +9 -7
  130. package/dist/summary/summaryManager.js.map +1 -1
  131. package/lib/batchTracker.d.ts +2 -1
  132. package/lib/batchTracker.d.ts.map +1 -1
  133. package/lib/batchTracker.js +2 -2
  134. package/lib/batchTracker.js.map +1 -1
  135. package/lib/blobManager.d.ts +13 -2
  136. package/lib/blobManager.d.ts.map +1 -1
  137. package/lib/blobManager.js +103 -25
  138. package/lib/blobManager.js.map +1 -1
  139. package/lib/connectionTelemetry.d.ts.map +1 -1
  140. package/lib/connectionTelemetry.js +13 -5
  141. package/lib/connectionTelemetry.js.map +1 -1
  142. package/lib/containerRuntime.d.ts +69 -22
  143. package/lib/containerRuntime.d.ts.map +1 -1
  144. package/lib/containerRuntime.js +343 -238
  145. package/lib/containerRuntime.js.map +1 -1
  146. package/lib/dataStore.js +11 -2
  147. package/lib/dataStore.js.map +1 -1
  148. package/lib/dataStoreContext.d.ts +1 -1
  149. package/lib/dataStoreContext.d.ts.map +1 -1
  150. package/lib/dataStoreContext.js +42 -46
  151. package/lib/dataStoreContext.js.map +1 -1
  152. package/lib/dataStoreContexts.js +2 -2
  153. package/lib/dataStoreContexts.js.map +1 -1
  154. package/lib/dataStores.d.ts +21 -5
  155. package/lib/dataStores.d.ts.map +1 -1
  156. package/lib/dataStores.js +103 -59
  157. package/lib/dataStores.js.map +1 -1
  158. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
  159. package/lib/deltaManagerSummarizerProxy.js +2 -0
  160. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  161. package/lib/deltaScheduler.d.ts.map +1 -1
  162. package/lib/deltaScheduler.js +6 -6
  163. package/lib/deltaScheduler.js.map +1 -1
  164. package/lib/gc/garbageCollection.d.ts.map +1 -1
  165. package/lib/gc/garbageCollection.js +30 -26
  166. package/lib/gc/garbageCollection.js.map +1 -1
  167. package/lib/gc/gcConfigs.js +13 -11
  168. package/lib/gc/gcConfigs.js.map +1 -1
  169. package/lib/gc/gcHelpers.d.ts +1 -0
  170. package/lib/gc/gcHelpers.d.ts.map +1 -1
  171. package/lib/gc/gcHelpers.js +5 -6
  172. package/lib/gc/gcHelpers.js.map +1 -1
  173. package/lib/gc/gcSummaryStateTracker.js +4 -6
  174. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  175. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  176. package/lib/gc/gcTelemetry.js +45 -34
  177. package/lib/gc/gcTelemetry.js.map +1 -1
  178. package/lib/id-compressor/idCompressor.d.ts +3 -3
  179. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  180. package/lib/id-compressor/idCompressor.js +52 -52
  181. package/lib/id-compressor/idCompressor.js.map +1 -1
  182. package/lib/id-compressor/idRange.js +2 -2
  183. package/lib/id-compressor/idRange.js.map +1 -1
  184. package/lib/id-compressor/sessionIdNormalizer.js +11 -16
  185. package/lib/id-compressor/sessionIdNormalizer.js.map +1 -1
  186. package/lib/index.d.ts +1 -1
  187. package/lib/index.d.ts.map +1 -1
  188. package/lib/index.js.map +1 -1
  189. package/lib/opLifecycle/batchManager.js +10 -6
  190. package/lib/opLifecycle/batchManager.js.map +1 -1
  191. package/lib/opLifecycle/opCompressor.d.ts +2 -2
  192. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  193. package/lib/opLifecycle/opCompressor.js +8 -3
  194. package/lib/opLifecycle/opCompressor.js.map +1 -1
  195. package/lib/opLifecycle/opDecompressor.d.ts +2 -2
  196. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  197. package/lib/opLifecycle/opDecompressor.js +13 -11
  198. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  199. package/lib/opLifecycle/opGroupingManager.js +13 -5
  200. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  201. package/lib/opLifecycle/opSplitter.d.ts +2 -2
  202. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  203. package/lib/opLifecycle/opSplitter.js +12 -8
  204. package/lib/opLifecycle/opSplitter.js.map +1 -1
  205. package/lib/opLifecycle/outbox.d.ts +6 -5
  206. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  207. package/lib/opLifecycle/outbox.js +7 -15
  208. package/lib/opLifecycle/outbox.js.map +1 -1
  209. package/lib/opLifecycle/remoteMessageProcessor.d.ts +6 -1
  210. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  211. package/lib/opLifecycle/remoteMessageProcessor.js +8 -2
  212. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  213. package/lib/opProperties.js +1 -2
  214. package/lib/opProperties.js.map +1 -1
  215. package/lib/packageVersion.d.ts +1 -1
  216. package/lib/packageVersion.js +1 -1
  217. package/lib/packageVersion.js.map +1 -1
  218. package/lib/pendingStateManager.d.ts +6 -3
  219. package/lib/pendingStateManager.d.ts.map +1 -1
  220. package/lib/pendingStateManager.js +41 -32
  221. package/lib/pendingStateManager.js.map +1 -1
  222. package/lib/scheduleManager.d.ts.map +1 -1
  223. package/lib/scheduleManager.js +16 -12
  224. package/lib/scheduleManager.js.map +1 -1
  225. package/lib/summary/orderedClientElection.d.ts +2 -1
  226. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  227. package/lib/summary/orderedClientElection.js +19 -20
  228. package/lib/summary/orderedClientElection.js.map +1 -1
  229. package/lib/summary/runningSummarizer.d.ts +3 -5
  230. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  231. package/lib/summary/runningSummarizer.js +43 -67
  232. package/lib/summary/runningSummarizer.js.map +1 -1
  233. package/lib/summary/summarizer.js +6 -9
  234. package/lib/summary/summarizer.js.map +1 -1
  235. package/lib/summary/summarizerClientElection.js +5 -9
  236. package/lib/summary/summarizerClientElection.js.map +1 -1
  237. package/lib/summary/summarizerHeuristics.js +8 -12
  238. package/lib/summary/summarizerHeuristics.js.map +1 -1
  239. package/lib/summary/summarizerNode/summarizerNode.d.ts +5 -5
  240. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  241. package/lib/summary/summarizerNode/summarizerNode.js +27 -23
  242. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  243. package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  244. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  245. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -3
  246. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  247. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +14 -17
  248. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  249. package/lib/summary/summaryCollection.js +3 -5
  250. package/lib/summary/summaryCollection.js.map +1 -1
  251. package/lib/summary/summaryFormat.js +1 -2
  252. package/lib/summary/summaryFormat.js.map +1 -1
  253. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  254. package/lib/summary/summaryGenerator.js +68 -22
  255. package/lib/summary/summaryGenerator.js.map +1 -1
  256. package/lib/summary/summaryManager.d.ts +2 -3
  257. package/lib/summary/summaryManager.d.ts.map +1 -1
  258. package/lib/summary/summaryManager.js +10 -8
  259. package/lib/summary/summaryManager.js.map +1 -1
  260. package/package.json +30 -18
  261. package/src/batchTracker.ts +4 -3
  262. package/src/blobManager.ts +113 -15
  263. package/src/connectionTelemetry.ts +7 -3
  264. package/src/containerRuntime.ts +354 -194
  265. package/src/dataStore.ts +10 -1
  266. package/src/dataStoreContext.ts +31 -33
  267. package/src/dataStoreContexts.ts +2 -2
  268. package/src/dataStores.ts +108 -71
  269. package/src/deltaManagerSummarizerProxy.ts +2 -0
  270. package/src/deltaScheduler.ts +6 -10
  271. package/src/gc/garbageCollection.ts +13 -8
  272. package/src/gc/gcHelpers.ts +1 -0
  273. package/src/gc/gcTelemetry.ts +13 -10
  274. package/src/id-compressor/idCompressor.ts +6 -5
  275. package/src/index.ts +0 -1
  276. package/src/opLifecycle/opCompressor.ts +4 -3
  277. package/src/opLifecycle/opDecompressor.ts +4 -3
  278. package/src/opLifecycle/opSplitter.ts +4 -3
  279. package/src/opLifecycle/outbox.ts +13 -25
  280. package/src/opLifecycle/remoteMessageProcessor.ts +8 -2
  281. package/src/packageVersion.ts +1 -1
  282. package/src/pendingStateManager.ts +34 -25
  283. package/src/scheduleManager.ts +2 -2
  284. package/src/summary/orderedClientElection.ts +4 -3
  285. package/src/summary/runningSummarizer.ts +18 -44
  286. package/src/summary/summarizer.ts +2 -2
  287. package/src/summary/summarizerNode/summarizerNode.ts +13 -15
  288. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +8 -7
  289. package/src/summary/summaryGenerator.ts +6 -2
  290. package/src/summary/summaryManager.ts +9 -5
@@ -1,18 +1,7 @@
1
- var __rest = (this && this.__rest) || function (s, e) {
2
- var t = {};
3
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
- t[p] = s[p];
5
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
- t[p[i]] = s[p[i]];
9
- }
10
- return t;
11
- };
12
1
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
13
2
  import { assert, delay, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
14
3
  import { LazyPromise } from "@fluidframework/core-utils";
15
- import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
4
+ import { createChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, wrapError, createChildMonitoringContext, } from "@fluidframework/telemetry-utils";
16
5
  import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
17
6
  import { readAndParse } from "@fluidframework/driver-utils";
18
7
  import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
@@ -115,7 +104,7 @@ const defaultChunkSizeInBytes = 204800;
115
104
  * of the current system, we should close the summarizer and let it recover.
116
105
  * This delay's goal is to prevent tight restart loops
117
106
  */
118
- const defaultCloseSummarizerDelayMs = 10000; // 10 seconds
107
+ const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
119
108
  /**
120
109
  * @deprecated - use ContainerRuntimeMessage instead
121
110
  */
@@ -151,9 +140,23 @@ export function getDeviceSpec() {
151
140
  };
152
141
  }
153
142
  }
154
- catch (_a) { }
143
+ catch { }
155
144
  return {};
156
145
  }
146
+ /**
147
+ * Older loader doesn't have a submitBatchFn member, this is the older way of submitting a batch.
148
+ * Rather than exposing the submitFn (now deprecated) and IDeltaManager (dangerous to hand out) to the Outbox,
149
+ * we can provide a partially-applied function to keep those items private to the ContainerRuntime.
150
+ */
151
+ export const makeLegacySendBatchFn = (submitFn, deltaManager) => (batch) => {
152
+ for (const message of batch.content) {
153
+ submitFn(MessageType.Operation,
154
+ // For back-compat (submitFn only works on deserialized content)
155
+ message.contents === undefined ? undefined : JSON.parse(message.contents), true, // batch
156
+ message.metadata);
157
+ }
158
+ deltaManager.flush();
159
+ };
157
160
  /**
158
161
  * Represents the runtime of the container. Contains helper functions/state of the container.
159
162
  * It will define the store level mappings.
@@ -162,11 +165,13 @@ export class ContainerRuntime extends TypedEventEmitter {
162
165
  /**
163
166
  * @internal
164
167
  */
165
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration, initializeEntryPoint) {
166
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
167
- if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
168
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, idCompressor, requestHandler, summaryConfiguration = {
169
+ // the defaults
170
+ ...DefaultSummaryConfiguration,
171
+ // the runtime configuration overrides
172
+ ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
173
+ }, initializeEntryPoint) {
168
174
  super();
169
- this.context = context;
170
175
  this.registry = registry;
171
176
  this.runtimeOptions = runtimeOptions;
172
177
  this.containerScope = containerScope;
@@ -196,7 +201,7 @@ export class ContainerRuntime extends TypedEventEmitter {
196
201
  trackingSignalSequenceNumber: undefined,
197
202
  };
198
203
  this.summarizeOnDemand = (...args) => {
199
- if (this.clientDetails.type === summarizerClientType) {
204
+ if (this.isSummarizerClient) {
200
205
  return this.summarizer.summarizeOnDemand(...args);
201
206
  }
202
207
  else if (this.summaryManager !== undefined) {
@@ -210,7 +215,7 @@ export class ContainerRuntime extends TypedEventEmitter {
210
215
  }
211
216
  };
212
217
  this.enqueueSummarize = (...args) => {
213
- if (this.clientDetails.type === summarizerClientType) {
218
+ if (this.isSummarizerClient) {
214
219
  return this.summarizer.enqueueSummarize(...args);
215
220
  }
216
221
  else if (this.summaryManager !== undefined) {
@@ -223,23 +228,56 @@ export class ContainerRuntime extends TypedEventEmitter {
223
228
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
224
229
  }
225
230
  };
226
- this.innerDeltaManager = context.deltaManager;
227
- this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
228
- this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
231
+ const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
232
+ this.innerDeltaManager = deltaManager;
233
+ this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
234
+ // Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
235
+ // This makes ContainerRuntime the final gatekeeper for outgoing messages.
236
+ this.submitFn = submitFn;
237
+ this.submitBatchFn = submitBatchFn;
238
+ this.submitSummaryFn = submitSummaryFn;
239
+ this.submitSignalFn = submitSignalFn;
240
+ this.options = options;
241
+ this.clientDetails = clientDetails;
242
+ this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
243
+ this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
244
+ this._getClientId = () => context.clientId;
245
+ this._getAttachState = () => context.attachState;
246
+ this.getAbsoluteUrl = async (relativeUrl) => {
247
+ if (context.getAbsoluteUrl === undefined) {
248
+ throw new Error("Driver does not implement getAbsoluteUrl");
249
+ }
250
+ if (this.attachState !== AttachState.Attached) {
251
+ return undefined;
252
+ }
253
+ return context.getAbsoluteUrl(relativeUrl);
254
+ };
255
+ // TODO: Consider that the Container could just listen to these events itself, or even more appropriately maybe the
256
+ // customer should observe dirty state on the runtime (the owner of dirty state) directly, rather than on the IContainer.
257
+ this.on("dirty", () => context.updateDirtyContainerState(true));
258
+ this.on("saved", () => context.updateDirtyContainerState(false));
259
+ // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
260
+ this.disposeFn = disposeFn ?? closeFn;
261
+ // In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
262
+ this.closeFn = this.isSummarizerClient ? this.disposeFn : closeFn;
263
+ this.mc = createChildMonitoringContext({
264
+ logger: this.logger,
265
+ namespace: "ContainerRuntime",
266
+ });
229
267
  let loadSummaryNumber;
230
268
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
231
269
  // get the values from the metadata blob.
232
270
  if (existing) {
233
271
  this.createContainerMetadata = {
234
- createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
235
- createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
272
+ createContainerRuntimeVersion: metadata?.createContainerRuntimeVersion,
273
+ createContainerTimestamp: metadata?.createContainerTimestamp,
236
274
  };
237
275
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
238
276
  // the count is reset to 0.
239
- loadSummaryNumber = (_b = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _b !== void 0 ? _b : 0;
277
+ loadSummaryNumber = metadata?.summaryNumber ?? 0;
240
278
  // Enabling the IdCompressor is a one-way operation and we only want to
241
279
  // allow new containers to turn it on
242
- this.idCompressorEnabled = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.idCompressorEnabled) !== null && _c !== void 0 ? _c : false;
280
+ this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
243
281
  }
244
282
  else {
245
283
  this.createContainerMetadata = {
@@ -248,24 +286,27 @@ export class ContainerRuntime extends TypedEventEmitter {
248
286
  };
249
287
  loadSummaryNumber = 0;
250
288
  this.idCompressorEnabled =
251
- (_d = this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) !== null && _d !== void 0 ? _d : idCompressor !== undefined;
289
+ this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
290
+ idCompressor !== undefined;
252
291
  }
253
292
  this.nextSummaryNumber = loadSummaryNumber + 1;
254
- this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
255
- this._connected = this.context.connected;
256
- this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_e = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _e === void 0 ? void 0 : _e.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
293
+ this.messageAtLastSummary = metadata?.message;
294
+ // Note that we only need to pull the *initial* connected state from the context.
295
+ // Later updates come through calls to setConnectionState.
296
+ this._connected = connected;
297
+ this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
257
298
  this.mc.logger.sendTelemetryEvent({
258
299
  eventName: "GCFeatureMatrix",
259
- metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
300
+ metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
260
301
  inputs: JSON.stringify({
261
302
  gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
262
303
  }),
263
304
  });
264
- this.telemetryDocumentId = (_f = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _f !== void 0 ? _f : uuid();
305
+ this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
265
306
  this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
266
307
  const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
267
308
  const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
268
- const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
309
+ const opSplitter = new OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
269
310
  this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger), opGroupingManager);
270
311
  this.handleContext = new ContainerFluidHandleContext("", this);
271
312
  if (this.summaryConfiguration.state === "enabled") {
@@ -284,9 +325,10 @@ export class ContainerRuntime extends TypedEventEmitter {
284
325
  this.idCompressor = idCompressor;
285
326
  }
286
327
  this.maxConsecutiveReconnects =
287
- (_g = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _g !== void 0 ? _g : this.defaultMaxConsecutiveReconnects;
328
+ this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
329
+ this.defaultMaxConsecutiveReconnects;
288
330
  if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
289
- ((_h = context.supportedFeatures) === null || _h === void 0 ? void 0 : _h.get("referenceSequenceNumbers")) !== true) {
331
+ supportedFeatures?.get("referenceSequenceNumbers") !== true) {
290
332
  // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
291
333
  this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
292
334
  this._flushMode = FlushMode.TurnBased;
@@ -294,8 +336,8 @@ export class ContainerRuntime extends TypedEventEmitter {
294
336
  else {
295
337
  this._flushMode = runtimeOptions.flushMode;
296
338
  }
297
- const pendingRuntimeState = context.pendingLocalState;
298
- const maxSnapshotCacheDurationMs = (_k = (_j = this._storage) === null || _j === void 0 ? void 0 : _j.policies) === null || _k === void 0 ? void 0 : _k.maximumCacheDurationMs;
339
+ const pendingRuntimeState = pendingLocalState;
340
+ const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
299
341
  if (maxSnapshotCacheDurationMs !== undefined &&
300
342
  maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
301
343
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
@@ -306,27 +348,27 @@ export class ContainerRuntime extends TypedEventEmitter {
306
348
  this.garbageCollector = GarbageCollector.create({
307
349
  runtime: this,
308
350
  gcOptions: this.runtimeOptions.gcOptions,
309
- baseSnapshot: context.baseSnapshot,
351
+ baseSnapshot,
310
352
  baseLogger: this.mc.logger,
311
353
  existing,
312
354
  metadata,
313
355
  createContainerMetadata: this.createContainerMetadata,
314
- isSummarizerClient: this.context.clientDetails.type === summarizerClientType,
356
+ isSummarizerClient: this.isSummarizerClient,
315
357
  getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
316
- getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
358
+ getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
317
359
  readAndParseBlob: async (id) => readAndParse(this.storage, id),
318
360
  // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
319
361
  // delta manager would always return false for summarizer client.
320
362
  activeConnection: () => this.innerDeltaManager.active,
321
363
  });
322
364
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
323
- this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
365
+ this.summarizerNode = createRootSummarizerNodeWithGC(createChildLogger({ logger: this.logger, namespace: "SummarizerNode" }),
324
366
  // Summarize function to call when summarize is called. Summarizer node always tracks summary state.
325
367
  async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
326
368
  // Latest change sequence number, no changes since summary applied yet
327
369
  loadedFromSequenceNumber,
328
370
  // Summary reference sequence number, undefined if no summary yet
329
- context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
371
+ baseSnapshot !== undefined ? loadedFromSequenceNumber : undefined, {
330
372
  // Must set to false to prevent sending summary handle which would be pointing to
331
373
  // a summary with an older protocol state.
332
374
  canReuseHandle: false,
@@ -340,19 +382,19 @@ export class ContainerRuntime extends TypedEventEmitter {
340
382
  async (fullGC) => this.getGCDataInternal(fullGC),
341
383
  // Function to get the GC details from the base snapshot we loaded from.
342
384
  async () => this.garbageCollector.getBaseGCDetails());
343
- if (context.baseSnapshot) {
344
- this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
385
+ if (baseSnapshot) {
386
+ this.summarizerNode.updateBaseSummaryState(baseSnapshot);
345
387
  }
346
- this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
388
+ this.dataStores = new DataStores(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));
347
389
  this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
348
390
  if (!this.disposed) {
349
- this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
391
+ this.submit({ type: ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
350
392
  localId,
351
393
  blobId,
352
394
  });
353
395
  }
354
- }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, (error) => this.closeFn(error));
355
- this.scheduleManager = new ScheduleManager(context.deltaManager, this, () => this.clientId, ChildLogger.create(this.logger, "ScheduleManager"));
396
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState?.pendingAttachmentBlobs, (error) => this.closeFn(error));
397
+ this.scheduleManager = new ScheduleManager(this.innerDeltaManager, this, () => this.clientId, createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }));
356
398
  this.pendingStateManager = new PendingStateManager({
357
399
  applyStashedOp: this.applyStashedOp.bind(this),
358
400
  clientId: () => this.clientId,
@@ -360,7 +402,8 @@ export class ContainerRuntime extends TypedEventEmitter {
360
402
  connected: () => this.connected,
361
403
  reSubmit: this.reSubmit.bind(this),
362
404
  reSubmitBatch: this.reSubmitBatch.bind(this),
363
- }, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
405
+ isActiveConnection: () => this.innerDeltaManager.active,
406
+ }, pendingRuntimeState?.pending, this.logger);
364
407
  const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
365
408
  const compressionOptions = disableCompression === true
366
409
  ? {
@@ -369,10 +412,12 @@ export class ContainerRuntime extends TypedEventEmitter {
369
412
  }
370
413
  : runtimeOptions.compressionOptions;
371
414
  const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
415
+ const legacySendBatchFn = makeLegacySendBatchFn(this.submitFn, this.innerDeltaManager);
372
416
  this.outbox = new Outbox({
373
417
  shouldSend: () => this.canSendOps(),
374
418
  pendingStateManager: this.pendingStateManager,
375
- containerContext: this.context,
419
+ submitBatchFn: this.submitBatchFn,
420
+ legacySendBatchFn,
376
421
  compressor: new OpCompressor(this.mc.logger),
377
422
  splitter: opSplitter,
378
423
  config: {
@@ -391,44 +436,53 @@ export class ContainerRuntime extends TypedEventEmitter {
391
436
  opReentrancy: () => this.ensureNoDataModelChangesCalls > 0,
392
437
  closeContainer: this.closeFn,
393
438
  });
394
- this.context.quorum.on("removeMember", (clientId) => {
439
+ this._quorum = quorum;
440
+ this._quorum.on("removeMember", (clientId) => {
395
441
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
396
442
  });
443
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
444
+ this._audience = audience;
397
445
  this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
398
446
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
399
- this.closeSummarizerDelayMs = closeSummarizerDelayOverride !== null && closeSummarizerDelayOverride !== void 0 ? closeSummarizerDelayOverride : defaultCloseSummarizerDelayMs;
447
+ this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
400
448
  this.validateSummaryBeforeUpload =
401
- (_l = this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload")) !== null && _l !== void 0 ? _l : false;
449
+ this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload") ??
450
+ false;
402
451
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
403
452
  this.dirtyContainer =
404
- this.context.attachState !== AttachState.Attached ||
453
+ this.attachState !== AttachState.Attached ||
405
454
  this.pendingStateManager.hasPendingMessages();
406
- this.context.updateDirtyContainerState(this.dirtyContainer);
455
+ context.updateDirtyContainerState(this.dirtyContainer);
407
456
  if (this.summariesDisabled) {
408
457
  this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
409
458
  }
410
459
  else {
411
- const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
412
- const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
413
- const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
460
+ const orderedClientLogger = createChildLogger({
461
+ logger: this.logger,
462
+ namespace: "OrderedClientElection",
463
+ });
464
+ const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
465
+ const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
414
466
  this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
415
- if (this.context.clientDetails.type === summarizerClientType) {
467
+ if (this.isSummarizerClient) {
416
468
  this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
417
469
  // Summarization runs in summarizer client and needs access to the real (non-proxy) active
418
470
  // information. The proxy delta manager would always return false for summarizer client.
419
471
  () => this.innerDeltaManager.active));
420
472
  }
421
- else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
473
+ else if (SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
422
474
  // Only create a SummaryManager and SummarizerClientElection
423
475
  // if summaries are enabled and we are not the summarizer client.
424
476
  const defaultAction = () => {
425
477
  if (this.summaryCollection.opsSinceLastAck > this.maxOpsSinceLastSummary) {
426
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
478
+ this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
427
479
  // unregister default to no log on every op after falling behind
428
480
  // and register summary ack handler to re-register this handler
429
481
  // after successful summary
430
482
  this.summaryCollection.once(MessageType.SummaryAck, () => {
431
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
483
+ this.mc.logger.sendTelemetryEvent({
484
+ eventName: "SummaryStatus:CaughtUp",
485
+ });
432
486
  // we've caught up, so re-register the default action to monitor for
433
487
  // falling behind, and unregister ourself
434
488
  this.summaryCollection.on("default", defaultAction);
@@ -439,7 +493,7 @@ export class ContainerRuntime extends TypedEventEmitter {
439
493
  this.summaryCollection.on("default", defaultAction);
440
494
  // Create the SummaryManager and mark the initial state
441
495
  this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
442
- this.summaryCollection, this.logger, this.formRequestSummarizerFn(this.context.loader), new Throttler(60 * 1000, // 60 sec delay window
496
+ this.summaryCollection, this.logger, this.formRequestSummarizerFn(loader), new Throttler(60 * 1000, // 60 sec delay window
443
497
  30 * 1000, // 30 sec max delay
444
498
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
445
499
  formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
@@ -469,8 +523,20 @@ export class ContainerRuntime extends TypedEventEmitter {
469
523
  this.replayPendingStates();
470
524
  });
471
525
  // logging hardware telemetry
472
- logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
473
- this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature, options: JSON.stringify(runtimeOptions), featureGates: JSON.stringify({
526
+ logger.sendTelemetryEvent({
527
+ eventName: "DeviceSpec",
528
+ ...getDeviceSpec(),
529
+ });
530
+ this.mc.logger.sendTelemetryEvent({
531
+ eventName: "ContainerLoadStats",
532
+ ...this.createContainerMetadata,
533
+ ...this.dataStores.containerLoadStats,
534
+ summaryNumber: loadSummaryNumber,
535
+ summaryFormatVersion: metadata?.summaryFormatVersion,
536
+ disableIsolatedChannels: metadata?.disableIsolatedChannels,
537
+ gcVersion: metadata?.gcFeature,
538
+ options: JSON.stringify(runtimeOptions),
539
+ featureGates: JSON.stringify({
474
540
  disableCompression,
475
541
  disableOpReentryCheck,
476
542
  disableChunking,
@@ -479,17 +545,23 @@ export class ContainerRuntime extends TypedEventEmitter {
479
545
  idCompressorEnabled: this.idCompressorEnabled,
480
546
  summaryStateUpdateMethod: this.summaryStateUpdateMethod,
481
547
  closeSummarizerDelayOverride,
482
- }), telemetryDocumentId: this.telemetryDocumentId, groupedBatchingEnabled: this.groupedBatchingEnabled }));
483
- ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
548
+ }),
549
+ telemetryDocumentId: this.telemetryDocumentId,
550
+ groupedBatchingEnabled: this.groupedBatchingEnabled,
551
+ });
552
+ ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
484
553
  BindBatchTracker(this, this.logger);
485
554
  this.entryPoint = new LazyPromise(async () => {
486
- if (this.context.clientDetails.type === summarizerClientType) {
555
+ if (this.isSummarizerClient) {
487
556
  assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
488
557
  return this._summarizer;
489
558
  }
490
- return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
559
+ return initializeEntryPoint?.(this);
491
560
  });
492
561
  }
562
+ /**
563
+ * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
564
+ */
493
565
  get IFluidRouter() {
494
566
  return this;
495
567
  }
@@ -535,22 +607,24 @@ export class ContainerRuntime extends TypedEventEmitter {
535
607
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
536
608
  */
537
609
  static async loadRuntime(params) {
538
- var _a, _b, _c, _d, _e, _f;
539
610
  const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
540
611
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
541
612
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
542
613
  const backCompatContext = context;
543
- const passLogger = (_a = backCompatContext.taggedLogger) !== null && _a !== void 0 ? _a : new TaggedLoggerAdapter(backCompatContext.logger);
544
- const logger = ChildLogger.create(passLogger, undefined, {
545
- all: {
546
- runtimeVersion: pkgVersion,
614
+ const passLogger = backCompatContext.taggedLogger ??
615
+ new TaggedLoggerAdapter(backCompatContext.logger);
616
+ const logger = createChildLogger({
617
+ logger: passLogger,
618
+ properties: {
619
+ all: {
620
+ runtimeVersion: pkgVersion,
621
+ },
547
622
  },
548
623
  });
549
624
  const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor = false, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
550
625
  const registry = new FluidDataStoreRegistry(registryEntries);
551
626
  const tryFetchBlob = async (blobName) => {
552
- var _a;
553
- const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
627
+ const blobId = context.baseSnapshot?.blobs[blobName];
554
628
  if (context.baseSnapshot && blobId) {
555
629
  // IContainerContext storage api return type still has undefined in 0.39 package version.
556
630
  // So once we release 0.40 container-defn package we can remove this check.
@@ -565,16 +639,15 @@ export class ContainerRuntime extends TypedEventEmitter {
565
639
  tryFetchBlob(aliasBlobName),
566
640
  tryFetchBlob(idCompressorBlobName),
567
641
  ]);
568
- const loadExisting = existing === true || context.existing === true;
569
642
  // read snapshot blobs needed for BlobManager to load
570
- const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
643
+ const blobManagerSnapshot = await BlobManager.load(context.baseSnapshot?.trees[blobsTreeName], async (id) => {
571
644
  // IContainerContext storage api return type still has undefined in 0.39 package version.
572
645
  // So once we release 0.40 container-defn package we can remove this check.
573
646
  assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
574
647
  return readAndParse(context.storage, id);
575
648
  });
576
649
  // Verify summary runtime sequence number matches protocol sequence number.
577
- const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
650
+ const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
578
651
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
579
652
  if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
580
653
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
@@ -589,13 +662,11 @@ export class ContainerRuntime extends TypedEventEmitter {
589
662
  logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
590
663
  }
591
664
  else {
592
- // Call both close and dispose as closeFn implementation will no longer dispose runtime in future
593
665
  context.closeFn(error);
594
- (_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
595
666
  }
596
667
  }
597
668
  }
598
- const idCompressorEnabled = (_f = (_e = metadata === null || metadata === void 0 ? void 0 : metadata.idCompressorEnabled) !== null && _e !== void 0 ? _e : runtimeOptions.enableRuntimeIdCompressor) !== null && _f !== void 0 ? _f : false;
669
+ const idCompressorEnabled = metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
599
670
  let idCompressor;
600
671
  if (idCompressorEnabled) {
601
672
  const { IdCompressor, createSessionId } = await import("./id-compressor");
@@ -604,7 +675,7 @@ export class ContainerRuntime extends TypedEventEmitter {
604
675
  ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
605
676
  : new IdCompressor(createSessionId(), logger);
606
677
  }
607
- const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks !== null && chunks !== void 0 ? chunks : [], aliases !== null && aliases !== void 0 ? aliases : [], {
678
+ const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
608
679
  summaryOptions,
609
680
  gcOptions,
610
681
  loadSequenceNumberVerification,
@@ -615,7 +686,7 @@ export class ContainerRuntime extends TypedEventEmitter {
615
686
  enableRuntimeIdCompressor,
616
687
  enableOpReentryCheck,
617
688
  enableGroupedBatching,
618
- }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
689
+ }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
619
690
  initializeEntryPoint);
620
691
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
621
692
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
@@ -624,38 +695,15 @@ export class ContainerRuntime extends TypedEventEmitter {
624
695
  await runtime.initializeBaseState();
625
696
  return runtime;
626
697
  }
627
- get options() {
628
- return this.context.options;
629
- }
630
698
  get clientId() {
631
- return this.context.clientId;
632
- }
633
- get clientDetails() {
634
- return this.context.clientDetails;
699
+ return this._getClientId();
635
700
  }
636
701
  get storage() {
637
702
  return this._storage;
638
703
  }
704
+ /** @deprecated - The functionality is no longer exposed publicly */
639
705
  get reSubmitFn() {
640
- // eslint-disable-next-line @typescript-eslint/unbound-method
641
- return this.reSubmitCore;
642
- }
643
- get disposeFn() {
644
- var _a;
645
- // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
646
- return (_a = this.context.disposeFn) !== null && _a !== void 0 ? _a : this.context.closeFn;
647
- }
648
- get closeFn() {
649
- if (this._summarizer !== undefined) {
650
- // In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
651
- return this.disposeFn;
652
- }
653
- // Also call disposeFn to retain functionality of runtime being disposed on close
654
- return (error) => {
655
- var _a, _b;
656
- this.context.closeFn(error);
657
- (_b = (_a = this.context).disposeFn) === null || _b === void 0 ? void 0 : _b.call(_a, error);
658
- };
706
+ return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
659
707
  }
660
708
  get flushMode() {
661
709
  return this._flushMode;
@@ -667,7 +715,7 @@ export class ContainerRuntime extends TypedEventEmitter {
667
715
  return this.registry;
668
716
  }
669
717
  get attachState() {
670
- return this.context.attachState;
718
+ return this._getAttachState();
671
719
  }
672
720
  get IFluidHandleContext() {
673
721
  return this.handleContext;
@@ -694,8 +742,7 @@ export class ContainerRuntime extends TypedEventEmitter {
694
742
  }
695
743
  /** clientId of parent (non-summarizing) container that owns summarizer container */
696
744
  get summarizerClientId() {
697
- var _a;
698
- return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
745
+ return this.summarizerClientElection?.electedClientId;
699
746
  }
700
747
  get disposed() {
701
748
  return this._disposed;
@@ -732,12 +779,11 @@ export class ContainerRuntime extends TypedEventEmitter {
732
779
  await this.garbageCollector.initializeBaseState();
733
780
  }
734
781
  dispose(error) {
735
- var _a;
736
782
  if (this._disposed) {
737
783
  return;
738
784
  }
739
785
  this._disposed = true;
740
- this.logger.sendTelemetryEvent({
786
+ this.mc.logger.sendTelemetryEvent({
741
787
  eventName: "ContainerRuntimeDisposed",
742
788
  isDirty: this.isDirty,
743
789
  lastSequenceNumber: this.deltaManager.lastSequenceNumber,
@@ -747,7 +793,7 @@ export class ContainerRuntime extends TypedEventEmitter {
747
793
  this.summaryManager.dispose();
748
794
  }
749
795
  this.garbageCollector.dispose();
750
- (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.dispose();
796
+ this._summarizer?.dispose();
751
797
  this.dataStores.dispose();
752
798
  this.pendingStateManager.dispose();
753
799
  this.emit("dispose");
@@ -756,6 +802,7 @@ export class ContainerRuntime extends TypedEventEmitter {
756
802
  /**
757
803
  * Notifies this object about the request made to the container.
758
804
  * @param request - Request made to the handler.
805
+ * @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
759
806
  */
760
807
  async request(request) {
761
808
  try {
@@ -822,19 +869,17 @@ export class ContainerRuntime extends TypedEventEmitter {
822
869
  return this.entryPoint;
823
870
  }
824
871
  internalId(maybeAlias) {
825
- var _a;
826
- return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
872
+ return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
827
873
  }
828
874
  async getDataStoreFromRequest(id, request) {
829
- var _a, _b, _c;
830
875
  const headerData = {};
831
- if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
876
+ if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
832
877
  headerData.wait = request.headers[RuntimeHeaders.wait];
833
878
  }
834
- if (typeof ((_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.viaHandle]) === "boolean") {
879
+ if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
835
880
  headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
836
881
  }
837
- if (typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[AllowTombstoneRequestHeaderKey]) === "boolean") {
882
+ if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
838
883
  headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
839
884
  }
840
885
  await this.dataStores.waitIfPendingAlias(id);
@@ -844,22 +889,27 @@ export class ContainerRuntime extends TypedEventEmitter {
844
889
  // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
845
890
  // the same as GC nodes id.
846
891
  const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
847
- this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request === null || request === void 0 ? void 0 : request.headers);
892
+ this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request?.headers);
848
893
  return dataStoreChannel;
849
894
  }
850
895
  /** Adds the container's metadata to the given summary tree. */
851
896
  addMetadataToSummary(summaryTree) {
852
- var _a;
853
- const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
897
+ const metadata = {
898
+ ...this.createContainerMetadata,
854
899
  // Increment the summary number for the next summary that will be generated.
855
- summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
900
+ summaryNumber: this.nextSummaryNumber++,
901
+ summaryFormatVersion: 1,
902
+ ...this.garbageCollector.getMetadata(),
856
903
  // The last message processed at the time of summary. If there are no new messages, use the message from the
857
904
  // last summary.
858
- message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId, idCompressorEnabled: this.idCompressorEnabled ? true : undefined });
905
+ message: extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
906
+ this.messageAtLastSummary,
907
+ telemetryDocumentId: this.telemetryDocumentId,
908
+ idCompressorEnabled: this.idCompressorEnabled ? true : undefined,
909
+ };
859
910
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
860
911
  }
861
912
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
862
- var _a;
863
913
  this.addMetadataToSummary(summaryTree);
864
914
  if (this.idCompressorEnabled) {
865
915
  assert(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
@@ -875,7 +925,7 @@ export class ContainerRuntime extends TypedEventEmitter {
875
925
  addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
876
926
  }
877
927
  if (this.summarizerClientElection) {
878
- const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
928
+ const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
879
929
  addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
880
930
  }
881
931
  const blobManagerSummary = this.blobManager.summarize();
@@ -922,7 +972,7 @@ export class ContainerRuntime extends TypedEventEmitter {
922
972
  // in their own batches before the originating batch is sent.
923
973
  // Therefore, receiving them while attempting to send the originating batch
924
974
  // does not mean that the container is making any progress.
925
- if ((message === null || message === void 0 ? void 0 : message.type) !== ContainerMessageType.ChunkedOp) {
975
+ if (message?.type !== ContainerMessageType.ChunkedOp) {
926
976
  this.consecutiveReconnects = 0;
927
977
  }
928
978
  }
@@ -972,9 +1022,9 @@ export class ContainerRuntime extends TypedEventEmitter {
972
1022
  */
973
1023
  parseOpContent(serializedContent) {
974
1024
  assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
975
- const parsed = JSON.parse(serializedContent);
976
- assert(parsed.type !== undefined, 0x6d6 /* incorrect op content format */);
977
- return { type: parsed.type, contents: parsed.contents };
1025
+ const { type, contents } = JSON.parse(serializedContent);
1026
+ assert(type !== undefined, 0x6d6 /* incorrect op content format */);
1027
+ return { type, contents };
978
1028
  }
979
1029
  async applyStashedOp(op) {
980
1030
  // Need to parse from string for back-compat
@@ -1033,6 +1083,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1033
1083
  // There might be no change of state due to Container calling this API after loading runtime.
1034
1084
  const changeOfState = this._connected !== connected;
1035
1085
  const reconnection = changeOfState && !connected;
1086
+ // We need to flush the ops currently collected by Outbox to preserve original order.
1087
+ // This flush NEEDS to happen before we set the ContainerRuntime to "connected".
1088
+ // We want these ops to get to the PendingStateManager without sending to service and have them return to the Outbox upon calling "replayPendingStates".
1089
+ if (changeOfState && connected) {
1090
+ this.flush();
1091
+ }
1036
1092
  this._connected = connected;
1037
1093
  if (!connected) {
1038
1094
  this._perfSignalData.signalsLost = 0;
@@ -1071,13 +1127,18 @@ export class ContainerRuntime extends TypedEventEmitter {
1071
1127
  // or something different, like a system message.
1072
1128
  const runtimeMessage = messageArg.type === MessageType.Operation;
1073
1129
  // Do shallow copy of message, as the processing flow will modify it.
1074
- const messageCopy = Object.assign({}, messageArg);
1130
+ const messageCopy = { ...messageArg };
1075
1131
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1076
1132
  this.processCore(message, local, runtimeMessage);
1077
1133
  }
1078
1134
  }
1135
+ /**
1136
+ * 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 runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
1140
+ */
1079
1141
  processCore(message, local, runtimeMessage) {
1080
- var _a;
1081
1142
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1082
1143
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1083
1144
  // messages once a batch has been fully processed.
@@ -1122,16 +1183,14 @@ export class ContainerRuntime extends TypedEventEmitter {
1122
1183
  local,
1123
1184
  type: message.type,
1124
1185
  contentType: typeof message.contents,
1125
- batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
1186
+ batch: message.metadata?.batch,
1126
1187
  compression: message.compression,
1127
1188
  });
1128
1189
  this.closeFn(error);
1129
1190
  throw error;
1130
1191
  }
1131
1192
  }
1132
- if (runtimeMessage || this.groupedBatchingEnabled) {
1133
- this.emit("op", message, runtimeMessage);
1134
- }
1193
+ this.emit("op", message, runtimeMessage);
1135
1194
  this.scheduleManager.afterOpProcessing(undefined, message);
1136
1195
  if (local) {
1137
1196
  // If we have processed a local op, this means that the container is
@@ -1154,7 +1213,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1154
1213
  */
1155
1214
  sendSignalTelemetryEvent(clientSignalSequenceNumber) {
1156
1215
  const duration = Date.now() - this._perfSignalData.signalTimestamp;
1157
- this.logger.sendPerformanceEvent({
1216
+ this.mc.logger.sendPerformanceEvent({
1158
1217
  eventName: "SignalLatency",
1159
1218
  duration,
1160
1219
  signalsLost: this._perfSignalData.signalsLost,
@@ -1177,7 +1236,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1177
1236
  this._perfSignalData.trackingSignalSequenceNumber) {
1178
1237
  this._perfSignalData.signalsLost++;
1179
1238
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1180
- this.logger.sendErrorEvent({
1239
+ this.mc.logger.sendErrorEvent({
1181
1240
  eventName: "SignalLost",
1182
1241
  type: envelope.contents.type,
1183
1242
  signalsLost: this._perfSignalData.signalsLost,
@@ -1201,6 +1260,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1201
1260
  }
1202
1261
  this.dataStores.processSignal(envelope.address, transformed, local);
1203
1262
  }
1263
+ /**
1264
+ * Returns the runtime of the data store.
1265
+ * @param id - Id supplied during creating the data store.
1266
+ * @param wait - True if you want to wait for it.
1267
+ * @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
1268
+ */
1204
1269
  async getRootDataStore(id, wait = true) {
1205
1270
  return this.getRootDataStoreChannel(id, wait);
1206
1271
  }
@@ -1262,9 +1327,25 @@ export class ContainerRuntime extends TypedEventEmitter {
1262
1327
  }
1263
1328
  return result;
1264
1329
  }
1265
- async createDataStore(pkg) {
1266
- const internalId = uuid();
1267
- return channelToDataStore(await this._createDataStore(pkg, internalId), internalId, this, this.dataStores, this.mc.logger);
1330
+ /**
1331
+ * Returns the aliased data store's entryPoint, given the alias.
1332
+ * @param alias - The alias for the data store.
1333
+ * @returns - The data store's entry point (IFluidHandle) if it exists and is aliased. Returns undefined if no
1334
+ * data store has been assigned the given alias.
1335
+ */
1336
+ async getAliasedDataStoreEntryPoint(alias) {
1337
+ await this.dataStores.waitIfPendingAlias(alias);
1338
+ const internalId = this.internalId(alias);
1339
+ const context = await this.dataStores.getDataStoreIfAvailable(internalId, { wait: false });
1340
+ // If the data store is not available or not an alias, return undefined.
1341
+ if (context === undefined || !(await context.isRoot())) {
1342
+ return undefined;
1343
+ }
1344
+ const channel = await context.realize();
1345
+ if (channel.entryPoint === undefined) {
1346
+ throw new UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1347
+ }
1348
+ return channel.entryPoint;
1268
1349
  }
1269
1350
  createDetachedRootDataStore(pkg, rootDataStoreId) {
1270
1351
  if (rootDataStoreId.includes("/")) {
@@ -1275,16 +1356,20 @@ export class ContainerRuntime extends TypedEventEmitter {
1275
1356
  createDetachedDataStore(pkg) {
1276
1357
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1277
1358
  }
1278
- async _createDataStoreWithProps(pkg, props, id = uuid()) {
1279
- const fluidDataStore = await this.dataStores
1280
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1281
- .realize();
1282
- return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1359
+ async createDataStore(pkg) {
1360
+ const id = uuid();
1361
+ return channelToDataStore(await this.dataStores
1362
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
1363
+ .realize(), id, this, this.dataStores, this.mc.logger);
1283
1364
  }
1284
- async _createDataStore(pkg, id = uuid(), props) {
1285
- return this.dataStores
1365
+ /**
1366
+ * @deprecated 0.16 Issue #1537, #3631
1367
+ * @internal
1368
+ */
1369
+ async _createDataStoreWithProps(pkg, props, id = uuid()) {
1370
+ return channelToDataStore(await this.dataStores
1286
1371
  ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1287
- .realize();
1372
+ .realize(), id, this, this.dataStores, this.mc.logger);
1288
1373
  }
1289
1374
  canSendOps() {
1290
1375
  // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
@@ -1298,11 +1383,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1298
1383
  return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
1299
1384
  }
1300
1385
  getQuorum() {
1301
- return this.context.quorum;
1386
+ return this._quorum;
1302
1387
  }
1303
1388
  getAudience() {
1304
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1305
- return this.context.audience;
1389
+ return this._audience;
1306
1390
  }
1307
1391
  /**
1308
1392
  * Returns true of container is dirty, i.e. there are some pending local changes that
@@ -1311,7 +1395,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1311
1395
  get isDirty() {
1312
1396
  return this.dirtyContainer;
1313
1397
  }
1314
- isContainerMessageDirtyable(type, contents) {
1398
+ isContainerMessageDirtyable({ type, contents }) {
1315
1399
  // For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
1316
1400
  // Ultimately we should have no special-cases from the ContainerRuntime's perspective.
1317
1401
  if (type === ContainerMessageType.Attach) {
@@ -1351,11 +1435,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1351
1435
  submitSignal(type, content) {
1352
1436
  this.verifyNotClosed();
1353
1437
  const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
1354
- return this.context.submitSignalFn(envelope);
1438
+ return this.submitSignalFn(envelope);
1355
1439
  }
1356
1440
  submitDataStoreSignal(address, type, content) {
1357
1441
  const envelope = this.createNewSignalEnvelope(address, type, content);
1358
- return this.context.submitSignalFn(envelope);
1442
+ return this.submitSignalFn(envelope);
1359
1443
  }
1360
1444
  setAttachState(attachState) {
1361
1445
  if (attachState === AttachState.Attaching) {
@@ -1388,22 +1472,17 @@ export class ContainerRuntime extends TypedEventEmitter {
1388
1472
  this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
1389
1473
  return summarizeResult.summary;
1390
1474
  }
1391
- async getAbsoluteUrl(relativeUrl) {
1392
- if (this.context.getAbsoluteUrl === undefined) {
1393
- throw new Error("Driver does not implement getAbsoluteUrl");
1394
- }
1395
- if (this.attachState !== AttachState.Attached) {
1396
- return undefined;
1397
- }
1398
- return this.context.getAbsoluteUrl(relativeUrl);
1399
- }
1400
1475
  async summarizeInternal(fullTree, trackState, telemetryContext) {
1401
1476
  const summarizeResult = await this.dataStores.summarize(fullTree, trackState, telemetryContext);
1402
1477
  // Wrap data store summaries in .channels subtree.
1403
1478
  wrapSummaryInChannelsTree(summarizeResult);
1404
1479
  const pathPartsForChildren = [channelsTreeName];
1405
1480
  this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
1406
- return Object.assign(Object.assign({}, summarizeResult), { id: "", pathPartsForChildren });
1481
+ return {
1482
+ ...summarizeResult,
1483
+ id: "",
1484
+ pathPartsForChildren,
1485
+ };
1407
1486
  }
1408
1487
  /**
1409
1488
  * Returns a summary of the runtime at the current sequence number.
@@ -1421,16 +1500,15 @@ export class ContainerRuntime extends TypedEventEmitter {
1421
1500
  runSweep,
1422
1501
  });
1423
1502
  try {
1424
- let gcStats;
1425
1503
  if (runGC) {
1426
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1504
+ await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1427
1505
  }
1428
1506
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1429
1507
  assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1430
- return { stats, summary, gcStats };
1508
+ return { stats, summary };
1431
1509
  }
1432
1510
  finally {
1433
- this.logger.sendTelemetryEvent({
1511
+ this.mc.logger.sendTelemetryEvent({
1434
1512
  eventName: "SummarizeTelemetry",
1435
1513
  details: telemetryContext.serialize(),
1436
1514
  });
@@ -1512,21 +1590,19 @@ export class ContainerRuntime extends TypedEventEmitter {
1512
1590
  * Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
1513
1591
  */
1514
1592
  getCurrentReferenceTimestampMs() {
1515
- var _a, _b, _c;
1516
1593
  // Use the timestamp of the last message seen by this client as that is server generated. If no messages have
1517
1594
  // been processed, use the timestamp of the message from the last summary.
1518
- return (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : (_c = this.messageAtLastSummary) === null || _c === void 0 ? void 0 : _c.timestamp;
1595
+ return this.deltaManager.lastMessage?.timestamp ?? this.messageAtLastSummary?.timestamp;
1519
1596
  }
1520
1597
  /**
1521
1598
  * Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
1522
1599
  * blob manager.
1523
1600
  */
1524
1601
  getNodeType(nodePath) {
1525
- var _a;
1526
1602
  if (this.isBlobPath(nodePath)) {
1527
1603
  return GCNodeType.Blob;
1528
1604
  }
1529
- return (_a = this.dataStores.getGCNodeType(nodePath)) !== null && _a !== void 0 ? _a : GCNodeType.Other;
1605
+ return this.dataStores.getGCNodeType(nodePath) ?? GCNodeType.Other;
1530
1606
  }
1531
1607
  /**
1532
1608
  * Called by GC to retrieve the package path of the node with the given path. The node should belong to a
@@ -1597,18 +1673,24 @@ export class ContainerRuntime extends TypedEventEmitter {
1597
1673
  * @param options - options controlling how the summary is generated or submitted
1598
1674
  */
1599
1675
  async submitSummary(options) {
1600
- var _a, _b, _c;
1601
1676
  const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1602
1677
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1603
1678
  // use it for all events logged during this summary.
1604
1679
  const summaryNumber = this.nextSummaryNumber;
1605
- const summaryNumberLogger = ChildLogger.create(summaryLogger, undefined, {
1606
- all: { summaryNumber },
1680
+ const summaryNumberLogger = createChildLogger({
1681
+ logger: summaryLogger,
1682
+ properties: {
1683
+ all: { summaryNumber },
1684
+ },
1607
1685
  });
1608
1686
  assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1609
1687
  let latestSnapshotVersionId;
1610
1688
  if (refreshLatestAck) {
1611
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1689
+ const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(createChildLogger({
1690
+ logger: summaryNumberLogger,
1691
+ namespace: undefined,
1692
+ properties: { all: { safeSummary: true } },
1693
+ }));
1612
1694
  const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1613
1695
  latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1614
1696
  // We might need to catch up to the latest summary's reference sequence number before pausing.
@@ -1628,7 +1710,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1628
1710
  this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
1629
1711
  // Helper function to check whether we should still continue between each async step.
1630
1712
  const checkContinue = () => {
1631
- var _a;
1632
1713
  // Do not check for loss of connectivity directly! Instead leave it up to
1633
1714
  // RunWhileConnectedCoordinator to control policy in a single place.
1634
1715
  // This will allow easier change of design if we chose to. For example, we may chose to allow
@@ -1651,7 +1732,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1651
1732
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1652
1733
  };
1653
1734
  }
1654
- assert(summaryRefSeqNum === ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber), 0x395 /* it's one and the same thing */);
1735
+ assert(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
1655
1736
  if (lastAck !== this.summaryCollection.latestAck) {
1656
1737
  return {
1657
1738
  continue: false,
@@ -1702,7 +1783,15 @@ export class ContainerRuntime extends TypedEventEmitter {
1702
1783
  const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
1703
1784
  ? calculateStats(summaryTree.tree[gcTreeKey])
1704
1785
  : undefined;
1705
- const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, summaryNumber }, partialStats);
1786
+ const summaryStats = {
1787
+ dataStoreCount: this.dataStores.size,
1788
+ summarizedDataStoreCount: this.dataStores.size - handleCount,
1789
+ gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
1790
+ gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
1791
+ gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
1792
+ summaryNumber,
1793
+ ...partialStats,
1794
+ };
1706
1795
  const generateSummaryData = {
1707
1796
  referenceSequenceNumber: summaryRefSeqNum,
1708
1797
  minimumSequenceNumber,
@@ -1716,14 +1805,14 @@ export class ContainerRuntime extends TypedEventEmitter {
1716
1805
  if (this.validateSummaryBeforeUpload) {
1717
1806
  const validateResult = this.summarizerNode.validateSummary();
1718
1807
  if (!validateResult.success) {
1719
- const { success } = validateResult, loggingProps = __rest(validateResult, ["success"]);
1720
- const error = new RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, Object.assign({}, loggingProps));
1721
- return Object.assign(Object.assign({ stage: "base" }, generateSummaryData), { error });
1808
+ const { success, ...loggingProps } = validateResult;
1809
+ const error = new RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
1810
+ return { stage: "base", ...generateSummaryData, error };
1722
1811
  }
1723
1812
  }
1724
1813
  continueResult = checkContinue();
1725
1814
  if (!continueResult.continue) {
1726
- return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
1815
+ return { stage: "generate", ...generateSummaryData, error: continueResult.error };
1727
1816
  }
1728
1817
  // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
1729
1818
  // summary. So if the previous summarizer closes just after submitting the summary and before
@@ -1731,7 +1820,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1731
1820
  // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1732
1821
  // the one fetched from storage as parent as that is the latest.
1733
1822
  let summaryContext;
1734
- if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId &&
1823
+ if (lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId &&
1735
1824
  latestSnapshotVersionId !== undefined) {
1736
1825
  summaryContext = {
1737
1826
  proposalHandle: undefined,
@@ -1742,7 +1831,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1742
1831
  else if (lastAck === undefined) {
1743
1832
  summaryContext = {
1744
1833
  proposalHandle: undefined,
1745
- ackHandle: (_a = this.context.getLoadedFromVersion()) === null || _a === void 0 ? void 0 : _a.id,
1834
+ ackHandle: this.loadedFromVersionId,
1746
1835
  referenceSequenceNumber: summaryRefSeqNum,
1747
1836
  };
1748
1837
  }
@@ -1758,7 +1847,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1758
1847
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
1759
1848
  }
1760
1849
  catch (error) {
1761
- return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error });
1850
+ return { stage: "generate", ...generateSummaryData, error };
1762
1851
  }
1763
1852
  const parent = summaryContext.ackHandle;
1764
1853
  const summaryMessage = {
@@ -1768,25 +1857,34 @@ export class ContainerRuntime extends TypedEventEmitter {
1768
1857
  message,
1769
1858
  parents: parent ? [parent] : [],
1770
1859
  };
1771
- const uploadData = Object.assign(Object.assign({}, generateSummaryData), { handle, uploadDuration: trace.trace().duration });
1860
+ const uploadData = {
1861
+ ...generateSummaryData,
1862
+ handle,
1863
+ uploadDuration: trace.trace().duration,
1864
+ };
1772
1865
  continueResult = checkContinue();
1773
1866
  if (!continueResult.continue) {
1774
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error: continueResult.error });
1867
+ return { stage: "upload", ...uploadData, error: continueResult.error };
1775
1868
  }
1776
1869
  let clientSequenceNumber;
1777
1870
  try {
1778
1871
  clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
1779
1872
  }
1780
1873
  catch (error) {
1781
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
1874
+ return { stage: "upload", ...uploadData, error };
1782
1875
  }
1783
- const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
1876
+ const submitData = {
1877
+ stage: "submit",
1878
+ ...uploadData,
1879
+ clientSequenceNumber,
1880
+ submitOpDuration: trace.trace().duration,
1881
+ };
1784
1882
  try {
1785
1883
  // If validateSummaryBeforeUpload is false, the summary should be validated in this step.
1786
1884
  this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
1787
1885
  }
1788
1886
  catch (error) {
1789
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
1887
+ return { stage: "upload", ...uploadData, error };
1790
1888
  }
1791
1889
  return submitData;
1792
1890
  }
@@ -1794,7 +1892,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1794
1892
  // Cleanup wip summary in case of failure
1795
1893
  this.summarizerNode.clearSummary();
1796
1894
  // ! This needs to happen before we resume inbound queues to ensure heuristics are tracked correctly
1797
- (_c = (_b = this._summarizer) === null || _b === void 0 ? void 0 : _b.recordSummaryAttempt) === null || _c === void 0 ? void 0 : _c.call(_b, summaryRefSeqNum);
1895
+ this._summarizer?.recordSummaryAttempt?.(summaryRefSeqNum);
1798
1896
  // Restart the delta manager
1799
1897
  this.deltaManager.inbound.resume();
1800
1898
  if (shouldPauseInboundSignal) {
@@ -1819,7 +1917,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1819
1917
  this.dirtyContainer = dirty;
1820
1918
  if (this.emitDirtyDocumentEvent) {
1821
1919
  this.emit(dirty ? "dirty" : "saved");
1822
- this.context.updateDirtyContainerState(dirty);
1823
1920
  }
1824
1921
  }
1825
1922
  submitDataStoreOp(id, contents, localOpMetadata = undefined) {
@@ -1827,21 +1924,20 @@ export class ContainerRuntime extends TypedEventEmitter {
1827
1924
  address: id,
1828
1925
  contents,
1829
1926
  };
1830
- this.submit(ContainerMessageType.FluidDataStoreOp, envelope, localOpMetadata);
1927
+ this.submit({ type: ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
1831
1928
  }
1832
1929
  submitDataStoreAliasOp(contents, localOpMetadata) {
1833
1930
  const aliasMessage = contents;
1834
1931
  if (!isDataStoreAliasMessage(aliasMessage)) {
1835
1932
  throw new UsageError("malformedDataStoreAliasMessage");
1836
1933
  }
1837
- this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
1934
+ this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
1838
1935
  }
1839
- async uploadBlob(blob) {
1936
+ async uploadBlob(blob, signal) {
1840
1937
  this.verifyNotClosed();
1841
- return this.blobManager.createBlob(blob);
1938
+ return this.blobManager.createBlob(blob, signal);
1842
1939
  }
1843
1940
  maybeSubmitIdAllocationOp(type) {
1844
- var _a, _b;
1845
1941
  if (type !== ContainerMessageType.IdAllocation) {
1846
1942
  let idAllocationBatchMessage;
1847
1943
  let idRange;
@@ -1849,7 +1945,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1849
1945
  assert(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
1850
1946
  idRange = this.idCompressor.takeNextCreationRange();
1851
1947
  // Don't include the idRange if there weren't any Ids allocated
1852
- idRange = ((_a = idRange === null || idRange === void 0 ? void 0 : idRange.ids) === null || _a === void 0 ? void 0 : _a.first) !== undefined ? idRange : undefined;
1948
+ idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
1853
1949
  }
1854
1950
  if (idRange !== undefined) {
1855
1951
  const idAllocationMessage = {
@@ -1860,7 +1956,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1860
1956
  contents: JSON.stringify(idAllocationMessage),
1861
1957
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
1862
1958
  metadata: undefined,
1863
- localOpMetadata: (_b = this.idCompressor) === null || _b === void 0 ? void 0 : _b.serialize(true),
1959
+ localOpMetadata: this.idCompressor?.serialize(true),
1864
1960
  type: ContainerMessageType.IdAllocation,
1865
1961
  };
1866
1962
  }
@@ -1869,20 +1965,21 @@ export class ContainerRuntime extends TypedEventEmitter {
1869
1965
  }
1870
1966
  }
1871
1967
  }
1872
- submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
1968
+ submit(containerRuntimeMessage, localOpMetadata = undefined, metadata = undefined) {
1873
1969
  this.verifyNotClosed();
1874
1970
  this.verifyCanSubmitOps();
1875
1971
  // There should be no ops in detached container state!
1876
1972
  assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1877
- const serializedContent = JSON.stringify({ type, contents });
1973
+ const serializedContent = JSON.stringify(containerRuntimeMessage);
1878
1974
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
1879
1975
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
1880
1976
  if (this.innerDeltaManager.readOnlyInfo.readonly) {
1881
- this.logger.sendTelemetryEvent({
1977
+ this.mc.logger.sendTelemetryEvent({
1882
1978
  eventName: "SubmitOpInReadonly",
1883
1979
  connected: this.connected,
1884
1980
  });
1885
1981
  }
1982
+ const type = containerRuntimeMessage.type;
1886
1983
  const message = {
1887
1984
  contents: serializedContent,
1888
1985
  type,
@@ -1939,7 +2036,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1939
2036
  this.closeFn(error);
1940
2037
  throw error;
1941
2038
  }
1942
- if (this.isContainerMessageDirtyable(type, contents)) {
2039
+ if (this.isContainerMessageDirtyable(containerRuntimeMessage)) {
1943
2040
  this.updateDocumentDirtyState(true);
1944
2041
  }
1945
2042
  }
@@ -1982,9 +2079,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1982
2079
  // System message should not be sent in the middle of the batch.
1983
2080
  assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
1984
2081
  // back-compat: ADO #1385: Make this call unconditional in the future
1985
- return this.context.submitSummaryFn !== undefined
1986
- ? this.context.submitSummaryFn(contents, referenceSequenceNumber)
1987
- : this.context.submitFn(MessageType.Summarize, contents, false);
2082
+ return this.submitSummaryFn !== undefined
2083
+ ? this.submitSummaryFn(contents, referenceSequenceNumber)
2084
+ : this.submitFn(MessageType.Summarize, contents, false);
1988
2085
  }
1989
2086
  /**
1990
2087
  * Throw an error if the runtime is closed. Methods that are expected to potentially
@@ -2031,32 +2128,33 @@ export class ContainerRuntime extends TypedEventEmitter {
2031
2128
  }
2032
2129
  reSubmit(message) {
2033
2130
  // Need to parse from string for back-compat
2034
- const { contents, type } = this.parseOpContent(message.content);
2035
- this.reSubmitCore(type, contents, message.localOpMetadata, message.opMetadata);
2131
+ const containerRuntimeMessage = this.parseOpContent(message.content);
2132
+ this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
2036
2133
  }
2037
2134
  /**
2038
2135
  * Finds the right store and asks it to resubmit the message. This typically happens when we
2039
2136
  * reconnect and there are pending messages.
2040
- * @param content - The content of the original message.
2137
+ * @param message - The original ContainerRuntimeMessage.
2041
2138
  * @param localOpMetadata - The local metadata associated with the original message.
2042
2139
  */
2043
- reSubmitCore(type, content, localOpMetadata, opMetadata) {
2044
- switch (type) {
2140
+ reSubmitCore(message, localOpMetadata, opMetadata) {
2141
+ const contents = message.contents;
2142
+ switch (message.type) {
2045
2143
  case ContainerMessageType.FluidDataStoreOp:
2046
2144
  // For Operations, call resubmitDataStoreOp which will find the right store
2047
2145
  // and trigger resubmission on it.
2048
- this.dataStores.resubmitDataStoreOp(content, localOpMetadata);
2146
+ this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
2049
2147
  break;
2050
2148
  case ContainerMessageType.Attach:
2051
2149
  case ContainerMessageType.Alias:
2052
- this.submit(type, content, localOpMetadata);
2150
+ this.submit(message, localOpMetadata);
2053
2151
  break;
2054
2152
  case ContainerMessageType.IdAllocation:
2055
2153
  // Remove the stashedState from the op if it's a stashed op
2056
- if (content.stashedState !== undefined) {
2057
- delete content.stashedState;
2154
+ if (contents.stashedState !== undefined) {
2155
+ delete contents.stashedState;
2058
2156
  }
2059
- this.submit(type, content, localOpMetadata);
2157
+ this.submit(message, localOpMetadata);
2060
2158
  break;
2061
2159
  case ContainerMessageType.ChunkedOp:
2062
2160
  throw new Error(`chunkedOp not expected here`);
@@ -2064,10 +2162,10 @@ export class ContainerRuntime extends TypedEventEmitter {
2064
2162
  this.blobManager.reSubmit(opMetadata);
2065
2163
  break;
2066
2164
  case ContainerMessageType.Rejoin:
2067
- this.submit(type, content);
2165
+ this.submit(message);
2068
2166
  break;
2069
2167
  default:
2070
- unreachableCase(type, `Unknown ContainerMessageType: ${type}`);
2168
+ unreachableCase(message.type, `Unknown ContainerMessageType [type: ${message.type}]`);
2071
2169
  }
2072
2170
  }
2073
2171
  rollback(content, localOpMetadata) {
@@ -2114,7 +2212,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2114
2212
  * change that started fetching latest snapshot always.
2115
2213
  */
2116
2214
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2117
- fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2215
+ fetchResult = await this.fetchSnapshotFromStorageAndClose(summaryLogger, {
2118
2216
  eventName: "RefreshLatestSummaryAckFetchBackCompat",
2119
2217
  ackHandle,
2120
2218
  targetSequenceNumber: summaryRefSeq,
@@ -2136,7 +2234,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2136
2234
  summaryRefSeq,
2137
2235
  fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
2138
2236
  });
2139
- this.closeFn(error);
2237
+ this.disposeFn(error);
2140
2238
  throw error;
2141
2239
  }
2142
2240
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
@@ -2172,10 +2270,9 @@ export class ContainerRuntime extends TypedEventEmitter {
2172
2270
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2173
2271
  }
2174
2272
  async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2175
- return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
2273
+ return this.fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, null /* latest */);
2176
2274
  }
2177
- async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
2178
- var _a;
2275
+ async fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, versionId) {
2179
2276
  const snapshotResults = await PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2180
2277
  const stats = {};
2181
2278
  const trace = Trace.start();
@@ -2198,29 +2295,37 @@ export class ContainerRuntime extends TypedEventEmitter {
2198
2295
  // We choose to close the summarizer after the snapshot cache is updated to avoid
2199
2296
  // situations which the main client (which is likely to be re-elected as the leader again)
2200
2297
  // loads the summarizer from cache.
2201
- if (this.summaryStateUpdateMethod === "restart") {
2202
- const error = new GenericError("Restarting summarizer instead of refreshing");
2203
- this.mc.logger.sendTelemetryEvent(Object.assign(Object.assign({}, event), { eventName: "ClosingSummarizerOnSummaryStale", codePath: event.eventName, message: "Stopping fetch from storage", versionId: versionId != null ? versionId : undefined, closeSummarizerDelayMs: this.closeSummarizerDelayMs }), error);
2204
- // Delay 10 seconds before restarting summarizer to prevent the summarizer from restarting too frequently.
2298
+ if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
2299
+ this.mc.logger.sendTelemetryEvent({
2300
+ ...event,
2301
+ eventName: "ClosingSummarizerOnSummaryStale",
2302
+ codePath: event.eventName,
2303
+ message: "Stopping fetch from storage",
2304
+ versionId: versionId != null ? versionId : undefined,
2305
+ closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2306
+ }, new GenericError("Restarting summarizer instead of refreshing"));
2307
+ // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2205
2308
  await delay(this.closeSummarizerDelayMs);
2206
- (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.stop("latestSummaryStateStale");
2207
- this.closeFn();
2208
- throw error;
2309
+ this._summarizer?.stop("latestSummaryStateStale");
2310
+ this.disposeFn();
2209
2311
  }
2210
2312
  return snapshotResults;
2211
2313
  }
2212
2314
  notifyAttaching() { } // do nothing (deprecated method)
2213
- getPendingLocalState() {
2315
+ async getPendingLocalState(props) {
2316
+ this.verifyNotClosed();
2317
+ const waitBlobsToAttach = props?.notifyImminentClosure;
2214
2318
  if (this._orderSequentiallyCalls !== 0) {
2215
2319
  throw new UsageError("can't get state during orderSequentially");
2216
2320
  }
2321
+ const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2217
2322
  // Flush pending batch.
2218
2323
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2219
2324
  // to close current batch.
2220
2325
  this.flush();
2221
2326
  return {
2222
2327
  pending: this.pendingStateManager.getLocalState(),
2223
- pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
2328
+ pendingAttachmentBlobs,
2224
2329
  };
2225
2330
  }
2226
2331
  /**