@fluidframework/container-loader 2.0.0-rc.1.0.6 → 2.0.0-rc.2.0.1

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 (298) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +5 -6
  2. package/{.mocharc.js → .mocharc.cjs} +1 -1
  3. package/CHANGELOG.md +48 -0
  4. package/README.md +3 -3
  5. package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
  6. package/api-extractor-lint.json +1 -1
  7. package/api-extractor.json +1 -1
  8. package/api-report/container-loader.api.md +2 -2
  9. package/dist/attachment.d.ts +115 -0
  10. package/dist/attachment.d.ts.map +1 -0
  11. package/dist/attachment.js +83 -0
  12. package/dist/attachment.js.map +1 -0
  13. package/dist/audience.d.ts +9 -4
  14. package/dist/audience.d.ts.map +1 -1
  15. package/dist/audience.js +10 -4
  16. package/dist/audience.js.map +1 -1
  17. package/dist/connectionManager.d.ts +3 -3
  18. package/dist/connectionManager.d.ts.map +1 -1
  19. package/dist/connectionManager.js +17 -18
  20. package/dist/connectionManager.js.map +1 -1
  21. package/dist/connectionState.d.ts +1 -0
  22. package/dist/connectionState.d.ts.map +1 -1
  23. package/dist/connectionState.js +1 -0
  24. package/dist/connectionState.js.map +1 -1
  25. package/dist/connectionStateHandler.d.ts +7 -7
  26. package/dist/connectionStateHandler.d.ts.map +1 -1
  27. package/dist/connectionStateHandler.js +32 -32
  28. package/dist/connectionStateHandler.js.map +1 -1
  29. package/dist/container-loader-alpha.d.ts +2 -1
  30. package/dist/container-loader-beta.d.ts +3 -0
  31. package/dist/container-loader-public.d.ts +3 -0
  32. package/dist/container-loader-untrimmed.d.ts +5 -5
  33. package/dist/container.d.ts +29 -27
  34. package/dist/container.d.ts.map +1 -1
  35. package/dist/container.js +215 -284
  36. package/dist/container.js.map +1 -1
  37. package/dist/containerContext.d.ts +3 -2
  38. package/dist/containerContext.d.ts.map +1 -1
  39. package/dist/containerContext.js +2 -1
  40. package/dist/containerContext.js.map +1 -1
  41. package/dist/containerStorageAdapter.d.ts +5 -6
  42. package/dist/containerStorageAdapter.d.ts.map +1 -1
  43. package/dist/containerStorageAdapter.js +14 -21
  44. package/dist/containerStorageAdapter.js.map +1 -1
  45. package/dist/contracts.d.ts +3 -3
  46. package/dist/contracts.d.ts.map +1 -1
  47. package/dist/contracts.js.map +1 -1
  48. package/dist/debugLogger.js.map +1 -1
  49. package/dist/deltaManager.d.ts +5 -5
  50. package/dist/deltaManager.d.ts.map +1 -1
  51. package/dist/deltaManager.js +6 -6
  52. package/dist/deltaManager.js.map +1 -1
  53. package/dist/error.d.ts.map +1 -1
  54. package/dist/error.js.map +1 -1
  55. package/dist/index.d.ts +6 -6
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +11 -11
  58. package/dist/index.js.map +1 -1
  59. package/dist/loader.d.ts +3 -3
  60. package/dist/loader.d.ts.map +1 -1
  61. package/dist/loader.js +13 -17
  62. package/dist/loader.js.map +1 -1
  63. package/dist/location-redirection-utilities/index.d.ts +1 -1
  64. package/dist/location-redirection-utilities/index.d.ts.map +1 -1
  65. package/dist/location-redirection-utilities/index.js +3 -3
  66. package/dist/location-redirection-utilities/index.js.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/dist/packageVersion.d.ts +1 -1
  69. package/dist/packageVersion.js +1 -1
  70. package/dist/packageVersion.js.map +1 -1
  71. package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
  72. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  73. package/dist/protocolTreeDocumentStorageService.js +1 -3
  74. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  75. package/dist/retriableDocumentStorageService.d.ts +2 -2
  76. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  77. package/dist/retriableDocumentStorageService.js +8 -6
  78. package/dist/retriableDocumentStorageService.js.map +1 -1
  79. package/dist/serializedStateManager.d.ts +44 -0
  80. package/dist/serializedStateManager.d.ts.map +1 -0
  81. package/dist/serializedStateManager.js +149 -0
  82. package/dist/serializedStateManager.js.map +1 -0
  83. package/dist/tsdoc-metadata.json +1 -1
  84. package/dist/utils.d.ts +16 -11
  85. package/dist/utils.d.ts.map +1 -1
  86. package/dist/utils.js +107 -32
  87. package/dist/utils.js.map +1 -1
  88. package/lib/attachment.d.ts +115 -0
  89. package/lib/attachment.d.ts.map +1 -0
  90. package/lib/attachment.js +79 -0
  91. package/lib/attachment.js.map +1 -0
  92. package/lib/{audience.d.mts → audience.d.ts} +14 -5
  93. package/lib/audience.d.ts.map +1 -0
  94. package/lib/{audience.mjs → audience.js} +14 -4
  95. package/lib/audience.js.map +1 -0
  96. package/lib/{catchUpMonitor.d.mts → catchUpMonitor.d.ts} +1 -1
  97. package/lib/catchUpMonitor.d.ts.map +1 -0
  98. package/lib/{catchUpMonitor.mjs → catchUpMonitor.js} +1 -1
  99. package/lib/catchUpMonitor.js.map +1 -0
  100. package/lib/{connectionManager.d.mts → connectionManager.d.ts} +4 -4
  101. package/lib/connectionManager.d.ts.map +1 -0
  102. package/lib/{connectionManager.mjs → connectionManager.js} +7 -10
  103. package/lib/connectionManager.js.map +1 -0
  104. package/lib/{connectionState.d.mts → connectionState.d.ts} +2 -1
  105. package/lib/connectionState.d.ts.map +1 -0
  106. package/lib/{connectionState.mjs → connectionState.js} +2 -1
  107. package/lib/connectionState.js.map +1 -0
  108. package/lib/{connectionStateHandler.d.mts → connectionStateHandler.d.ts} +8 -8
  109. package/lib/connectionStateHandler.d.ts.map +1 -0
  110. package/lib/{connectionStateHandler.mjs → connectionStateHandler.js} +3 -3
  111. package/lib/connectionStateHandler.js.map +1 -0
  112. package/lib/{container-loader-alpha.d.mts → container-loader-alpha.d.ts} +2 -1
  113. package/lib/{container-loader-beta.d.mts → container-loader-beta.d.ts} +3 -0
  114. package/lib/{container-loader-public.d.mts → container-loader-public.d.ts} +3 -0
  115. package/lib/{container-loader-untrimmed.d.mts → container-loader-untrimmed.d.ts} +5 -5
  116. package/lib/{container.d.mts → container.d.ts} +30 -28
  117. package/lib/container.d.ts.map +1 -0
  118. package/lib/{container.mjs → container.js} +178 -247
  119. package/lib/container.js.map +1 -0
  120. package/lib/{containerContext.d.mts → containerContext.d.ts} +4 -3
  121. package/lib/containerContext.d.ts.map +1 -0
  122. package/lib/{containerContext.mjs → containerContext.js} +3 -2
  123. package/lib/containerContext.js.map +1 -0
  124. package/lib/{containerStorageAdapter.d.mts → containerStorageAdapter.d.ts} +6 -7
  125. package/lib/containerStorageAdapter.d.ts.map +1 -0
  126. package/lib/{containerStorageAdapter.mjs → containerStorageAdapter.js} +13 -20
  127. package/lib/containerStorageAdapter.js.map +1 -0
  128. package/lib/{contracts.d.mts → contracts.d.ts} +4 -4
  129. package/lib/contracts.d.ts.map +1 -0
  130. package/lib/{contracts.mjs → contracts.js} +1 -1
  131. package/lib/contracts.js.map +1 -0
  132. package/lib/{debugLogger.d.mts → debugLogger.d.ts} +1 -1
  133. package/lib/debugLogger.d.ts.map +1 -0
  134. package/lib/{debugLogger.mjs → debugLogger.js} +2 -1
  135. package/lib/debugLogger.js.map +1 -0
  136. package/lib/{deltaManager.d.mts → deltaManager.d.ts} +6 -6
  137. package/lib/deltaManager.d.ts.map +1 -0
  138. package/lib/{deltaManager.mjs → deltaManager.js} +4 -4
  139. package/lib/deltaManager.js.map +1 -0
  140. package/lib/{deltaQueue.d.mts → deltaQueue.d.ts} +1 -1
  141. package/lib/deltaQueue.d.ts.map +1 -0
  142. package/lib/{deltaQueue.mjs → deltaQueue.js} +1 -1
  143. package/lib/deltaQueue.js.map +1 -0
  144. package/lib/{disposal.d.mts → disposal.d.ts} +1 -1
  145. package/lib/disposal.d.ts.map +1 -0
  146. package/lib/{disposal.mjs → disposal.js} +1 -1
  147. package/lib/disposal.js.map +1 -0
  148. package/lib/{error.d.mts → error.d.ts} +1 -1
  149. package/lib/error.d.ts.map +1 -0
  150. package/lib/{error.mjs → error.js} +1 -1
  151. package/lib/error.js.map +1 -0
  152. package/lib/{index.d.mts → index.d.ts} +7 -7
  153. package/lib/index.d.ts.map +1 -0
  154. package/lib/index.js +10 -0
  155. package/lib/index.js.map +1 -0
  156. package/lib/{loader.d.mts → loader.d.ts} +4 -4
  157. package/lib/loader.d.ts.map +1 -0
  158. package/lib/{loader.mjs → loader.js} +7 -11
  159. package/lib/loader.js.map +1 -0
  160. package/lib/location-redirection-utilities/{index.mjs → index.d.ts} +2 -2
  161. package/lib/location-redirection-utilities/index.d.ts.map +1 -0
  162. package/lib/location-redirection-utilities/{index.d.mts → index.js} +2 -2
  163. package/lib/location-redirection-utilities/index.js.map +1 -0
  164. package/lib/location-redirection-utilities/{resolveWithLocationRedirection.d.mts → resolveWithLocationRedirection.d.ts} +1 -1
  165. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
  166. package/lib/location-redirection-utilities/{resolveWithLocationRedirection.mjs → resolveWithLocationRedirection.js} +1 -1
  167. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -0
  168. package/lib/{noopHeuristic.d.mts → noopHeuristic.d.ts} +1 -1
  169. package/lib/noopHeuristic.d.ts.map +1 -0
  170. package/lib/{noopHeuristic.mjs → noopHeuristic.js} +1 -1
  171. package/lib/noopHeuristic.js.map +1 -0
  172. package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
  173. package/lib/packageVersion.d.ts.map +1 -0
  174. package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
  175. package/lib/packageVersion.js.map +1 -0
  176. package/lib/{protocol.d.mts → protocol.d.ts} +1 -1
  177. package/lib/protocol.d.ts.map +1 -0
  178. package/lib/{protocol.mjs → protocol.js} +1 -1
  179. package/lib/protocol.js.map +1 -0
  180. package/lib/{protocolTreeDocumentStorageService.d.mts → protocolTreeDocumentStorageService.d.ts} +2 -2
  181. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -0
  182. package/lib/{protocolTreeDocumentStorageService.mjs → protocolTreeDocumentStorageService.js} +2 -4
  183. package/lib/protocolTreeDocumentStorageService.js.map +1 -0
  184. package/lib/{quorum.d.mts → quorum.d.ts} +5 -1
  185. package/lib/quorum.d.ts.map +1 -0
  186. package/lib/{quorum.mjs → quorum.js} +1 -1
  187. package/lib/quorum.js.map +1 -0
  188. package/lib/{retriableDocumentStorageService.d.mts → retriableDocumentStorageService.d.ts} +3 -3
  189. package/lib/retriableDocumentStorageService.d.ts.map +1 -0
  190. package/lib/{retriableDocumentStorageService.mjs → retriableDocumentStorageService.js} +10 -8
  191. package/lib/retriableDocumentStorageService.js.map +1 -0
  192. package/lib/serializedStateManager.d.ts +44 -0
  193. package/lib/serializedStateManager.d.ts.map +1 -0
  194. package/lib/serializedStateManager.js +145 -0
  195. package/lib/serializedStateManager.js.map +1 -0
  196. package/lib/test/attachment.spec.js +380 -0
  197. package/lib/test/attachment.spec.js.map +1 -0
  198. package/lib/test/catchUpMonitor.spec.js +88 -0
  199. package/lib/test/catchUpMonitor.spec.js.map +1 -0
  200. package/lib/test/connectionManager.spec.js +201 -0
  201. package/lib/test/connectionManager.spec.js.map +1 -0
  202. package/lib/test/connectionStateHandler.spec.js +555 -0
  203. package/lib/test/connectionStateHandler.spec.js.map +1 -0
  204. package/lib/test/container.spec.js +64 -0
  205. package/lib/test/container.spec.js.map +1 -0
  206. package/lib/test/deltaManager.spec.js +405 -0
  207. package/lib/test/deltaManager.spec.js.map +1 -0
  208. package/lib/test/loader.spec.js +212 -0
  209. package/lib/test/loader.spec.js.map +1 -0
  210. package/lib/test/locationRedirectionTests.spec.js +44 -0
  211. package/lib/test/locationRedirectionTests.spec.js.map +1 -0
  212. package/lib/test/serializedStateManager.spec.js +148 -0
  213. package/lib/test/serializedStateManager.spec.js.map +1 -0
  214. package/lib/test/snapshotConversionTest.spec.js +79 -0
  215. package/lib/test/snapshotConversionTest.spec.js.map +1 -0
  216. package/lib/test/types/validateContainerLoaderPrevious.generated.js +38 -0
  217. package/lib/test/types/validateContainerLoaderPrevious.generated.js.map +1 -0
  218. package/lib/test/utils.spec.js +31 -0
  219. package/lib/test/utils.spec.js.map +1 -0
  220. package/lib/{utils.d.mts → utils.d.ts} +17 -12
  221. package/lib/utils.d.ts.map +1 -0
  222. package/lib/utils.js +206 -0
  223. package/lib/utils.js.map +1 -0
  224. package/package.json +61 -63
  225. package/src/attachment.ts +222 -0
  226. package/src/audience.ts +9 -3
  227. package/src/connectionManager.ts +9 -11
  228. package/src/connectionState.ts +1 -0
  229. package/src/connectionStateHandler.ts +8 -7
  230. package/src/container.ts +296 -323
  231. package/src/containerContext.ts +2 -1
  232. package/src/containerStorageAdapter.ts +21 -26
  233. package/src/contracts.ts +3 -3
  234. package/src/debugLogger.ts +2 -2
  235. package/src/deltaManager.ts +8 -8
  236. package/src/error.ts +2 -2
  237. package/src/index.ts +6 -6
  238. package/src/loader.ts +9 -13
  239. package/src/location-redirection-utilities/index.ts +1 -1
  240. package/src/packageVersion.ts +1 -1
  241. package/src/protocolTreeDocumentStorageService.ts +1 -3
  242. package/src/retriableDocumentStorageService.ts +18 -8
  243. package/src/serializedStateManager.ts +217 -0
  244. package/src/utils.ts +140 -43
  245. package/tsconfig.cjs.json +7 -0
  246. package/tsconfig.json +2 -5
  247. package/lib/audience.d.mts.map +0 -1
  248. package/lib/audience.mjs.map +0 -1
  249. package/lib/catchUpMonitor.d.mts.map +0 -1
  250. package/lib/catchUpMonitor.mjs.map +0 -1
  251. package/lib/connectionManager.d.mts.map +0 -1
  252. package/lib/connectionManager.mjs.map +0 -1
  253. package/lib/connectionState.d.mts.map +0 -1
  254. package/lib/connectionState.mjs.map +0 -1
  255. package/lib/connectionStateHandler.d.mts.map +0 -1
  256. package/lib/connectionStateHandler.mjs.map +0 -1
  257. package/lib/container.d.mts.map +0 -1
  258. package/lib/container.mjs.map +0 -1
  259. package/lib/containerContext.d.mts.map +0 -1
  260. package/lib/containerContext.mjs.map +0 -1
  261. package/lib/containerStorageAdapter.d.mts.map +0 -1
  262. package/lib/containerStorageAdapter.mjs.map +0 -1
  263. package/lib/contracts.d.mts.map +0 -1
  264. package/lib/contracts.mjs.map +0 -1
  265. package/lib/debugLogger.d.mts.map +0 -1
  266. package/lib/debugLogger.mjs.map +0 -1
  267. package/lib/deltaManager.d.mts.map +0 -1
  268. package/lib/deltaManager.mjs.map +0 -1
  269. package/lib/deltaQueue.d.mts.map +0 -1
  270. package/lib/deltaQueue.mjs.map +0 -1
  271. package/lib/disposal.d.mts.map +0 -1
  272. package/lib/disposal.mjs.map +0 -1
  273. package/lib/error.d.mts.map +0 -1
  274. package/lib/error.mjs.map +0 -1
  275. package/lib/index.d.mts.map +0 -1
  276. package/lib/index.mjs +0 -10
  277. package/lib/index.mjs.map +0 -1
  278. package/lib/loader.d.mts.map +0 -1
  279. package/lib/loader.mjs.map +0 -1
  280. package/lib/location-redirection-utilities/index.d.mts.map +0 -1
  281. package/lib/location-redirection-utilities/index.mjs.map +0 -1
  282. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +0 -1
  283. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +0 -1
  284. package/lib/noopHeuristic.d.mts.map +0 -1
  285. package/lib/noopHeuristic.mjs.map +0 -1
  286. package/lib/packageVersion.d.mts.map +0 -1
  287. package/lib/packageVersion.mjs.map +0 -1
  288. package/lib/protocol.d.mts.map +0 -1
  289. package/lib/protocol.mjs.map +0 -1
  290. package/lib/protocolTreeDocumentStorageService.d.mts.map +0 -1
  291. package/lib/protocolTreeDocumentStorageService.mjs.map +0 -1
  292. package/lib/quorum.d.mts.map +0 -1
  293. package/lib/quorum.mjs.map +0 -1
  294. package/lib/retriableDocumentStorageService.d.mts.map +0 -1
  295. package/lib/retriableDocumentStorageService.mjs.map +0 -1
  296. package/lib/utils.d.mts.map +0 -1
  297. package/lib/utils.mjs +0 -133
  298. package/lib/utils.mjs.map +0 -1
package/dist/container.js CHANGED
@@ -17,25 +17,26 @@ const driver_utils_1 = require("@fluidframework/driver-utils");
17
17
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
18
18
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
19
19
  const structured_clone_1 = __importDefault(require("@ungap/structured-clone"));
20
- const audience_1 = require("./audience");
21
- const containerContext_1 = require("./containerContext");
22
- const contracts_1 = require("./contracts");
23
- const deltaManager_1 = require("./deltaManager");
24
- const loader_1 = require("./loader");
25
- const packageVersion_1 = require("./packageVersion");
26
- const containerStorageAdapter_1 = require("./containerStorageAdapter");
27
- const connectionStateHandler_1 = require("./connectionStateHandler");
28
- const utils_1 = require("./utils");
29
- const quorum_1 = require("./quorum");
30
- const noopHeuristic_1 = require("./noopHeuristic");
31
- const connectionManager_1 = require("./connectionManager");
32
- const connectionState_1 = require("./connectionState");
33
- const protocol_1 = require("./protocol");
20
+ const audience_js_1 = require("./audience.js");
21
+ const containerContext_js_1 = require("./containerContext.js");
22
+ const contracts_js_1 = require("./contracts.js");
23
+ const deltaManager_js_1 = require("./deltaManager.js");
24
+ const loader_js_1 = require("./loader.js");
25
+ const packageVersion_js_1 = require("./packageVersion.js");
26
+ const containerStorageAdapter_js_1 = require("./containerStorageAdapter.js");
27
+ const connectionStateHandler_js_1 = require("./connectionStateHandler.js");
28
+ const utils_js_1 = require("./utils.js");
29
+ const quorum_js_1 = require("./quorum.js");
30
+ const noopHeuristic_js_1 = require("./noopHeuristic.js");
31
+ const connectionManager_js_1 = require("./connectionManager.js");
32
+ const connectionState_js_1 = require("./connectionState.js");
33
+ const protocol_js_1 = require("./protocol.js");
34
+ const attachment_js_1 = require("./attachment.js");
35
+ const serializedStateManager_js_1 = require("./serializedStateManager.js");
34
36
  const detachedContainerRefSeqNumber = 0;
35
37
  const dirtyContainerEvent = "dirty";
36
38
  const savedContainerEvent = "saved";
37
39
  const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
38
- const hasBlobsSummaryTree = ".hasAttachmentBlobs";
39
40
  /**
40
41
  * Waits until container connects to delta storage and gets up-to-date.
41
42
  *
@@ -73,8 +74,8 @@ async function waitContainerToCatchUp(container) {
73
74
  // Waiting for "connected" state in either case gets us at least to our own Join op
74
75
  // which is a reasonable approximation of "caught up"
75
76
  const waitForOps = () => {
76
- (0, core_utils_1.assert)(container.connectionState === connectionState_1.ConnectionState.CatchingUp ||
77
- container.connectionState === connectionState_1.ConnectionState.Connected, 0x0cd /* "Container disconnected while waiting for ops!" */);
77
+ (0, core_utils_1.assert)(container.connectionState === connectionState_js_1.ConnectionState.CatchingUp ||
78
+ container.connectionState === connectionState_js_1.ConnectionState.Connected, 0x0cd /* "Container disconnected while waiting for ops!" */);
78
79
  const hasCheckpointSequenceNumber = deltaManager.hasCheckpointSequenceNumber;
79
80
  const connectionOpSeqNumber = deltaManager.lastKnownSeqNumber;
80
81
  (0, core_utils_1.assert)(deltaManager.lastSequenceNumber <= connectionOpSeqNumber, 0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
@@ -96,7 +97,7 @@ async function waitContainerToCatchUp(container) {
96
97
  // But that works only if service provides us checkPointSequenceNumber
97
98
  // Our internal testing is based on R11S that does not, but almost all tests connect as "write" and
98
99
  // use this function to catch up, so leveraging our own join op as a fence/barrier
99
- if (container.connectionState === connectionState_1.ConnectionState.Connected) {
100
+ if (container.connectionState === connectionState_js_1.ConnectionState.Connected) {
100
101
  waitForOps();
101
102
  return;
102
103
  }
@@ -105,15 +106,13 @@ async function waitContainerToCatchUp(container) {
105
106
  waitForOps();
106
107
  };
107
108
  container.on(telemetry_utils_1.connectedEventName, callback);
108
- if (container.connectionState === connectionState_1.ConnectionState.Disconnected) {
109
+ if (container.connectionState === connectionState_js_1.ConnectionState.Disconnected) {
109
110
  container.connect();
110
111
  }
111
112
  });
112
113
  }
113
114
  exports.waitContainerToCatchUp = waitContainerToCatchUp;
114
- const getCodeProposal =
115
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
116
- (quorum) => quorum.get("code") ?? quorum.get("code2");
115
+ const getCodeProposal = (quorum) => quorum.get("code") ?? quorum.get("code2");
117
116
  /**
118
117
  * Helper function to report to telemetry cases where operation takes longer than expected (200ms)
119
118
  * @param logger - logger to use
@@ -132,7 +131,6 @@ const summarizerClientType = "summarizer";
132
131
  class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
133
132
  /**
134
133
  * Load an existing container.
135
- * @internal
136
134
  */
137
135
  static async load(loadProps, createProps) {
138
136
  const { version, pendingLocalState, loadMode, resolvedUrl, loadToSequenceNumber } = loadProps;
@@ -189,11 +187,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
189
187
  static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
190
188
  const container = new Container(createProps);
191
189
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
192
- const deserializedSummary = JSON.parse(snapshot);
193
- if (!(0, driver_utils_1.isCombinedAppAndProtocolSummary)(deserializedSummary, hasBlobsSummaryTree)) {
194
- throw new telemetry_utils_1.UsageError("Cannot rehydrate detached container. Incorrect format");
195
- }
196
- await container.rehydrateDetachedFromSnapshot(deserializedSummary);
190
+ const detachedContainerState = (0, utils_js_1.getDetachedContainerStateFromSerializedContainer)(snapshot);
191
+ await container.rehydrateDetachedFromSnapshot(detachedContainerState);
197
192
  return container;
198
193
  }, { start: true, end: true, cancel: "generic" });
199
194
  }
@@ -244,6 +239,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
244
239
  get readOnlyInfo() {
245
240
  return this._deltaManager.readOnlyInfo;
246
241
  }
242
+ get containerMetadata() {
243
+ return this._containerMetadata;
244
+ }
247
245
  /**
248
246
  * Sends signal to runtime (and data stores) to be read-only.
249
247
  * Hosts may have read only views, indicating to data stores that no edits are allowed.
@@ -271,7 +269,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
271
269
  return this.connectionStateHandler.connectionState;
272
270
  }
273
271
  get connected() {
274
- return this.connectionStateHandler.connectionState === connectionState_1.ConnectionState.Connected;
272
+ return this.connectionStateHandler.connectionState === connectionState_js_1.ConnectionState.Connected;
275
273
  }
276
274
  /**
277
275
  * The server provided id of the client.
@@ -280,11 +278,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
280
278
  get clientId() {
281
279
  return this._clientId;
282
280
  }
283
- get offlineLoadEnabled() {
284
- const enabled = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ??
285
- this.options?.enableOfflineLoad === true;
286
- // summarizer will not have any pending state we want to save
287
- return enabled && this.deltaManager.clientDetails.capabilities.interactive;
281
+ get isInteractiveClient() {
282
+ return this.deltaManager.clientDetails.capabilities.interactive;
288
283
  }
289
284
  /**
290
285
  * Get the code details that are currently specified for the container.
@@ -339,9 +334,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
339
334
  this._lifecycleEvents.once("disposed", disposedHandler);
340
335
  });
341
336
  }
342
- /**
343
- * @internal
344
- */
345
337
  constructor(createProps, loadProps) {
346
338
  super((name, error) => {
347
339
  this.mc.logger.sendErrorEvent({
@@ -365,23 +357,101 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
365
357
  * disposed: Container has been disposed
366
358
  */
367
359
  this._lifecycleState = "loading";
368
- this._attachState = container_definitions_1.AttachState.Detached;
369
360
  /** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
370
361
  this.inboundQueuePausedFromInit = true;
371
362
  this.firstConnection = true;
372
363
  this.connectionTransitionTimes = [];
373
- this.attachStarted = false;
374
364
  this._dirtyContainer = false;
375
- this.savedOps = [];
365
+ this.attachmentData = { state: container_definitions_1.AttachState.Detached };
376
366
  this.clientsWhoShouldHaveLeft = new Set();
367
+ this._containerMetadata = {};
377
368
  this.setAutoReconnectTime = client_utils_1.performance.now();
378
369
  this._lifecycleEvents = new client_utils_1.TypedEventEmitter();
379
370
  this._disposed = false;
371
+ this.attach = (0, utils_js_1.runSingle)(async (request, attachProps) => {
372
+ await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
373
+ if (this._lifecycleState !== "loaded" ||
374
+ this.attachmentData.state === container_definitions_1.AttachState.Attached) {
375
+ // pre-0.58 error message: containerNotValidForAttach
376
+ throw new telemetry_utils_1.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}] and [${this.attachState}]`);
377
+ }
378
+ const normalizeErrorAndClose = (error) => {
379
+ const newError = (0, telemetry_utils_1.normalizeError)(error);
380
+ this.close(newError);
381
+ // add resolved URL on error object so that host has the ability to find this document and delete it
382
+ newError.addTelemetryProperties({
383
+ resolvedUrl: this.service?.resolvedUrl?.url,
384
+ });
385
+ return newError;
386
+ };
387
+ const setAttachmentData = (attachmentData) => {
388
+ const previousState = this.attachmentData.state;
389
+ this.attachmentData = attachmentData;
390
+ const state = this.attachmentData.state;
391
+ if (state !== previousState && state !== container_definitions_1.AttachState.Detached) {
392
+ try {
393
+ this.runtime.setAttachState(state);
394
+ this.emit(state.toLocaleLowerCase());
395
+ }
396
+ catch (error) {
397
+ throw normalizeErrorAndClose(error);
398
+ }
399
+ }
400
+ };
401
+ const createAttachmentSummary = (redirectTable) => {
402
+ try {
403
+ (0, core_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
404
+ return (0, utils_js_1.combineAppAndProtocolSummary)(this.runtime.createSummary(redirectTable), this.captureProtocolSummary());
405
+ }
406
+ catch (error) {
407
+ throw normalizeErrorAndClose(error);
408
+ }
409
+ };
410
+ const createOrGetStorageService = async (summary) => {
411
+ // Actually go and create the resolved document
412
+ if (this.service === undefined) {
413
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
414
+ (0, core_utils_1.assert)(this.client.details.type !== summarizerClientType &&
415
+ createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
416
+ this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
417
+ cancel: this._deltaManager.closeAbortController.signal,
418
+ });
419
+ }
420
+ this.storageAdapter.connectToService(this.service);
421
+ return this.storageAdapter;
422
+ };
423
+ let attachP = (0, attachment_js_1.runRetriableAttachProcess)({
424
+ initialAttachmentData: this.attachmentData,
425
+ offlineLoadEnabled: this.serializedStateManager.offlineLoadEnabled,
426
+ detachedBlobStorage: this.detachedBlobStorage,
427
+ setAttachmentData,
428
+ createAttachmentSummary,
429
+ createOrGetStorageService,
430
+ });
431
+ // only enable the new behavior if the config is set
432
+ if (this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true) {
433
+ attachP = attachP.catch((error) => {
434
+ throw normalizeErrorAndClose(error);
435
+ });
436
+ }
437
+ this.serializedStateManager.setSnapshot(await attachP);
438
+ if (!this.closed) {
439
+ this.handleDeltaConnectionArg({
440
+ fetchOpsFromStorage: false,
441
+ reason: { text: "createDetached" },
442
+ }, attachProps?.deltaConnection);
443
+ }
444
+ }, { start: true, end: true, cancel: "generic" });
445
+ });
380
446
  this.getAbsoluteUrl = async (relativeUrl) => {
381
447
  if (this.resolvedUrl === undefined) {
382
448
  return undefined;
383
449
  }
384
- return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_1.getPackageName)(this._loadedCodeDetails));
450
+ return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, (0, contracts_js_1.getPackageName)(this._loadedCodeDetails));
451
+ };
452
+ this.metadataUpdateHandler = (metadata) => {
453
+ this._containerMetadata = { ...this._containerMetadata, ...metadata };
454
+ this.emit("metadataUpdate", metadata);
385
455
  };
386
456
  this.updateDirtyContainerState = (dirty) => {
387
457
  if (this._dirtyContainer === dirty) {
@@ -391,7 +461,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
391
461
  this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
392
462
  };
393
463
  const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
394
- this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = client_utils_1.performance.now();
464
+ this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected] = client_utils_1.performance.now();
395
465
  const pendingLocalState = loadProps?.pendingLocalState;
396
466
  this._clientId = pendingLocalState?.clientId;
397
467
  this._canReconnect = canReconnect ?? true;
@@ -407,7 +477,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
407
477
  this.detachedBlobStorage = detachedBlobStorage;
408
478
  this.protocolHandlerBuilder =
409
479
  protocolHandlerBuilder ??
410
- ((attributes, quorumSnapshot, sendProposal) => new protocol_1.ProtocolHandler(attributes, quorumSnapshot, sendProposal, new audience_1.Audience(), (clientId) => this.clientsWhoShouldHaveLeft.has(clientId)));
480
+ ((attributes, quorumSnapshot, sendProposal) => new protocol_js_1.ProtocolHandler(attributes, quorumSnapshot, sendProposal, new audience_js_1.Audience(), (clientId) => this.clientsWhoShouldHaveLeft.has(clientId)));
411
481
  // Note that we capture the createProps here so we can replicate the creation call when we want to clone.
412
482
  this.clone = async (_loadProps, createParamOverrides) => {
413
483
  return Container.load(_loadProps, {
@@ -416,7 +486,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
416
486
  });
417
487
  };
418
488
  this._containerId = (0, uuid_1.v4)();
419
- this.client = Container.setupClient(this._containerId, this.options, this.clientDetailsOverride);
489
+ this.client = Container.setupClient(this._containerId, options.client, this.clientDetailsOverride);
420
490
  // Create logger for data stores to use
421
491
  const type = this.client.details.type;
422
492
  const interactive = this.client.details.capabilities.interactive;
@@ -430,9 +500,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
430
500
  clientType,
431
501
  containerId: this._containerId,
432
502
  docId: () => this.resolvedUrl?.id,
433
- containerAttachState: () => this._attachState,
503
+ containerAttachState: () => this.attachState,
434
504
  containerLifecycleState: () => this._lifecycleState,
435
- containerConnectionState: () => connectionState_1.ConnectionState[this.connectionState],
505
+ containerConnectionState: () => connectionState_js_1.ConnectionState[this.connectionState],
436
506
  serializedContainer: pendingLocalState !== undefined,
437
507
  },
438
508
  // we need to be judicious with our logging here to avoid generating too much data
@@ -460,15 +530,15 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
460
530
  // Prefix all events in this file with container-loader
461
531
  this.mc = (0, telemetry_utils_1.createChildMonitoringContext)({ logger: this.subLogger, namespace: "Container" });
462
532
  this._deltaManager = this.createDeltaManager();
463
- this.connectionStateHandler = (0, connectionStateHandler_1.createConnectionStateHandler)({
533
+ this.connectionStateHandler = (0, connectionStateHandler_js_1.createConnectionStateHandler)({
464
534
  logger: this.mc.logger,
465
535
  connectionStateChanged: (value, oldState, reason) => {
466
- if (value === connectionState_1.ConnectionState.Connected) {
536
+ if (value === connectionState_js_1.ConnectionState.Connected) {
467
537
  this._clientId = this.connectionStateHandler.pendingClientId;
468
538
  }
469
539
  this.logConnectionStateChangeTelemetry(value, oldState, reason);
470
540
  if (this._lifecycleState === "loaded") {
471
- this.propagateConnectionState(false /* initial transition */, value === connectionState_1.ConnectionState.Disconnected
541
+ this.propagateConnectionState(false /* initial transition */, value === connectionState_js_1.ConnectionState.Disconnected
472
542
  ? reason
473
543
  : undefined /* disconnectedReason */);
474
544
  }
@@ -487,7 +557,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
487
557
  mode,
488
558
  category: this._lifecycleState === "loading" ? "generic" : category,
489
559
  duration: client_utils_1.performance.now() -
490
- this.connectionTransitionTimes[connectionState_1.ConnectionState.CatchingUp],
560
+ this.connectionTransitionTimes[connectionState_js_1.ConnectionState.CatchingUp],
491
561
  ...(details === undefined ? {} : { details: JSON.stringify(details) }),
492
562
  });
493
563
  // If this is "write" connection, it took too long to receive join op. But in most cases that's due
@@ -516,12 +586,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
516
586
  // using this callback and fix them up.
517
587
  const addProtocolSummaryIfMissing = (summaryTree) => (0, driver_utils_1.isCombinedAppAndProtocolSummary)(summaryTree) === true
518
588
  ? summaryTree
519
- : (0, utils_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
589
+ : (0, utils_js_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
520
590
  // Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
521
591
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
522
592
  const forceEnableSummarizeProtocolTree = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
523
593
  options.summarizeProtocolTree;
524
- this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState?.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
594
+ this.storageAdapter = new containerStorageAdapter_js_1.ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState?.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
595
+ const offlineLoadEnabled = (this.isInteractiveClient &&
596
+ this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) ??
597
+ options.enableOfflineLoad === true;
598
+ this.serializedStateManager = new serializedStateManager_js_1.SerializedStateManager(pendingLocalState, this.subLogger, this.storageAdapter, offlineLoadEnabled);
525
599
  const isDomAvailable = typeof document === "object" &&
526
600
  document !== null &&
527
601
  typeof document.addEventListener === "function" &&
@@ -562,7 +636,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
562
636
  this.verifyClosed();
563
637
  }
564
638
  verifyClosed() {
565
- (0, core_utils_1.assert)(this.connectionState === connectionState_1.ConnectionState.Disconnected, 0x0cf /* "disconnect event was not raised!" */);
639
+ (0, core_utils_1.assert)(this.connectionState === connectionState_js_1.ConnectionState.Disconnected, 0x0cf /* "disconnect event was not raised!" */);
566
640
  (0, core_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
567
641
  }
568
642
  closeCore(error) {
@@ -581,6 +655,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
581
655
  : "generic",
582
656
  }, error);
583
657
  this._lifecycleState = "closing";
658
+ // Back-compat for Old driver
659
+ if (this.service?.off !== undefined) {
660
+ this.service?.off("metadataUpdate", this.metadataUpdateHandler);
661
+ }
584
662
  this._protocolHandler?.close();
585
663
  this.connectionStateHandler.dispose();
586
664
  }
@@ -656,149 +734,35 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
656
734
  return this.getPendingLocalStateCore({ notifyImminentClosure: false });
657
735
  }
658
736
  async getPendingLocalStateCore(props) {
659
- return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
660
- eventName: "getPendingLocalState",
661
- notifyImminentClosure: props.notifyImminentClosure,
662
- savedOpsSize: this.savedOps.length,
663
- clientId: this.clientId,
664
- }, async () => {
665
- if (!this.offlineLoadEnabled) {
666
- throw new telemetry_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
667
- }
668
- if (this.closed || this._disposed) {
669
- throw new telemetry_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
670
- }
671
- (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
672
- (0, core_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
673
- (0, core_utils_1.assert)(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
674
- (0, core_utils_1.assert)(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
675
- const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
676
- const pendingState = {
677
- pendingRuntimeState,
678
- baseSnapshot: this.baseSnapshot,
679
- snapshotBlobs: this.baseSnapshotBlobs,
680
- savedOps: this.savedOps,
681
- url: this.resolvedUrl.url,
682
- // no need to save this if there is no pending runtime state
683
- clientId: pendingRuntimeState !== undefined ? this.clientId : undefined,
684
- };
685
- return JSON.stringify(pendingState);
686
- });
737
+ if (this.closed || this._disposed) {
738
+ throw new telemetry_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
739
+ }
740
+ (0, core_utils_1.assert)(this.attachmentData.state === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
741
+ (0, core_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
742
+ const pendingState = await this.serializedStateManager.getPendingLocalStateCore(props, this.clientId, this.runtime, this.resolvedUrl);
743
+ return pendingState;
687
744
  }
688
745
  get attachState() {
689
- return this._attachState;
746
+ return this.attachmentData.state;
690
747
  }
691
748
  serialize() {
692
- (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
693
- const appSummary = this.runtime.createSummary();
694
- const protocolSummary = this.captureProtocolSummary();
695
- const combinedSummary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
696
- if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
697
- combinedSummary.tree[hasBlobsSummaryTree] = {
698
- type: protocol_definitions_1.SummaryType.Blob,
699
- content: "true",
700
- };
749
+ if (this.attachmentData.state === container_definitions_1.AttachState.Attached || this.closed) {
750
+ throw new telemetry_utils_1.UsageError("Container must not be attached or closed.");
701
751
  }
702
- return JSON.stringify(combinedSummary);
703
- }
704
- async attach(request, attachProps) {
705
- await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
706
- if (this._lifecycleState !== "loaded") {
707
- // pre-0.58 error message: containerNotValidForAttach
708
- throw new telemetry_utils_1.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
709
- }
710
- // If container is already attached or attach is in progress, throw an error.
711
- (0, core_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
712
- this.attachStarted = true;
713
- // If attachment blobs were uploaded in detached state we will go through a different attach flow
714
- const hasAttachmentBlobs = this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0;
715
- try {
716
- (0, core_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
717
- let summary;
718
- if (!hasAttachmentBlobs) {
719
- // Get the document state post attach - possibly can just call attach but we need to change the
720
- // semantics around what the attach means as far as async code goes.
721
- const appSummary = this.runtime.createSummary();
722
- const protocolSummary = this.captureProtocolSummary();
723
- summary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
724
- // Set the state as attaching as we are starting the process of attaching container.
725
- // This should be fired after taking the summary because it is the place where we are
726
- // starting to attach the container to storage.
727
- // Also, this should only be fired in detached container.
728
- this._attachState = container_definitions_1.AttachState.Attaching;
729
- this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
730
- this.emit("attaching");
731
- if (this.offlineLoadEnabled) {
732
- const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
733
- this.baseSnapshot = snapshot;
734
- this.baseSnapshotBlobs =
735
- (0, containerStorageAdapter_1.getBlobContentsFromTreeWithBlobContents)(snapshot);
736
- }
737
- }
738
- // Actually go and create the resolved document
739
- if (this.service === undefined) {
740
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
741
- (0, core_utils_1.assert)(this.client.details.type !== summarizerClientType &&
742
- createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
743
- this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
744
- cancel: this._deltaManager.closeAbortController.signal,
745
- });
746
- }
747
- this.storageAdapter.connectToService(this.service);
748
- if (hasAttachmentBlobs) {
749
- // upload blobs to storage
750
- (0, core_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
751
- // build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
752
- // support blob handles that only know about the local IDs
753
- const redirectTable = new Map();
754
- // if new blobs are added while uploading, upload them too
755
- while (redirectTable.size < this.detachedBlobStorage.size) {
756
- const newIds = this.detachedBlobStorage
757
- .getBlobIds()
758
- .filter((id) => !redirectTable.has(id));
759
- for (const id of newIds) {
760
- const blob = await this.detachedBlobStorage.readBlob(id);
761
- const response = await this.storageAdapter.createBlob(blob);
762
- redirectTable.set(id, response.id);
763
- }
764
- }
765
- // take summary and upload
766
- const appSummary = this.runtime.createSummary(redirectTable);
767
- const protocolSummary = this.captureProtocolSummary();
768
- summary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
769
- this._attachState = container_definitions_1.AttachState.Attaching;
770
- this.runtime.setAttachState(container_definitions_1.AttachState.Attaching);
771
- this.emit("attaching");
772
- if (this.offlineLoadEnabled) {
773
- const snapshot = (0, utils_1.getSnapshotTreeFromSerializedContainer)(summary);
774
- this.baseSnapshot = snapshot;
775
- this.baseSnapshotBlobs =
776
- (0, containerStorageAdapter_1.getBlobContentsFromTreeWithBlobContents)(snapshot);
777
- }
778
- await this.storageAdapter.uploadSummaryWithContext(summary, {
779
- referenceSequenceNumber: 0,
780
- ackHandle: undefined,
781
- proposalHandle: undefined,
782
- });
783
- }
784
- this._attachState = container_definitions_1.AttachState.Attached;
785
- this.runtime.setAttachState(container_definitions_1.AttachState.Attached);
786
- this.emit("attached");
787
- if (!this.closed) {
788
- this.handleDeltaConnectionArg({
789
- fetchOpsFromStorage: false,
790
- reason: { text: "createDetached" },
791
- }, attachProps?.deltaConnection);
792
- }
793
- }
794
- catch (error) {
795
- // add resolved URL on error object so that host has the ability to find this document and delete it
796
- const newError = (0, telemetry_utils_1.normalizeError)(error);
797
- newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
798
- this.close(newError);
799
- throw newError;
800
- }
801
- }, { start: true, end: true, cancel: "generic" });
752
+ const attachingData = this.attachmentData.state === container_definitions_1.AttachState.Attaching ? this.attachmentData : undefined;
753
+ const combinedSummary = attachingData?.summary ??
754
+ (0, utils_js_1.combineAppAndProtocolSummary)(this.runtime.createSummary(), this.captureProtocolSummary());
755
+ const { tree: snapshot, blobs } = (0, utils_js_1.getSnapshotTreeAndBlobsFromSerializedContainer)(combinedSummary);
756
+ const pendingRuntimeState = attachingData !== undefined ? this.runtime.getPendingLocalState() : undefined;
757
+ (0, core_utils_1.assert)(!(0, core_utils_1.isPromiseLike)(pendingRuntimeState), 0x8e3 /* should not be a promise */);
758
+ const detachedContainerState = {
759
+ attached: false,
760
+ baseSnapshot: snapshot,
761
+ snapshotBlobs: blobs,
762
+ pendingRuntimeState,
763
+ hasAttachmentBlobs: !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
764
+ };
765
+ return JSON.stringify(detachedContainerState);
802
766
  }
803
767
  setAutoReconnectInternal(mode, reason) {
804
768
  const currentMode = this._deltaManager.connectionManager.reconnectMode;
@@ -809,9 +773,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
809
773
  const duration = now - this.setAutoReconnectTime;
810
774
  this.setAutoReconnectTime = now;
811
775
  this.mc.logger.sendTelemetryEvent({
812
- eventName: mode === contracts_1.ReconnectMode.Enabled ? "AutoReconnectEnabled" : "AutoReconnectDisabled",
776
+ eventName: mode === contracts_js_1.ReconnectMode.Enabled ? "AutoReconnectEnabled" : "AutoReconnectDisabled",
813
777
  connectionMode: this.connectionMode,
814
- connectionState: connectionState_1.ConnectionState[this.connectionState],
778
+ connectionState: connectionState_js_1.ConnectionState[this.connectionState],
815
779
  duration,
816
780
  });
817
781
  this._deltaManager.connectionManager.setAutoReconnect(mode, reason);
@@ -820,7 +784,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
820
784
  if (this.closed) {
821
785
  throw new telemetry_utils_1.UsageError(`The Container is closed and cannot be connected`);
822
786
  }
823
- else if (this._attachState !== container_definitions_1.AttachState.Attached) {
787
+ else if (this.attachState !== container_definitions_1.AttachState.Attached) {
824
788
  throw new telemetry_utils_1.UsageError(`The Container is not attached and cannot be connected`);
825
789
  }
826
790
  else if (!this.connected) {
@@ -835,11 +799,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
835
799
  }
836
800
  connectInternal(args) {
837
801
  (0, core_utils_1.assert)(!this.closed, 0x2c5 /* "Attempting to connect() a closed Container" */);
838
- (0, core_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
802
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
839
803
  // Resume processing ops and connect to delta stream
840
804
  this.resumeInternal(args);
841
805
  // Set Auto Reconnect Mode
842
- const mode = contracts_1.ReconnectMode.Enabled;
806
+ const mode = contracts_js_1.ReconnectMode.Enabled;
843
807
  this.setAutoReconnectInternal(mode, args.reason);
844
808
  }
845
809
  disconnect() {
@@ -853,7 +817,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
853
817
  disconnectInternal(reason) {
854
818
  (0, core_utils_1.assert)(!this.closed, 0x2c7 /* "Attempting to disconnect() a closed Container" */);
855
819
  // Set Auto Reconnect Mode
856
- const mode = contracts_1.ReconnectMode.Disabled;
820
+ const mode = contracts_js_1.ReconnectMode.Disabled;
857
821
  this.setAutoReconnectInternal(mode, reason);
858
822
  }
859
823
  resumeInternal(args) {
@@ -928,10 +892,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
928
892
  }
929
893
  return true;
930
894
  }
931
- async getVersion(version) {
932
- const versions = await this.storageAdapter.getVersions(version, 1);
933
- return versions[0];
934
- }
935
895
  connectToDeltaStream(args) {
936
896
  // All agents need "write" access, including summarizer.
937
897
  if (!this._canReconnect || !this.client.details.capabilities.interactive) {
@@ -939,6 +899,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
939
899
  }
940
900
  this._deltaManager.connect(args);
941
901
  }
902
+ async createDocumentService(serviceProvider) {
903
+ const service = await serviceProvider();
904
+ // Back-compat for Old driver
905
+ if (service.on !== undefined) {
906
+ service.on("metadataUpdate", this.metadataUpdateHandler);
907
+ }
908
+ return service;
909
+ }
942
910
  /**
943
911
  * Load container.
944
912
  *
@@ -946,7 +914,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
946
914
  */
947
915
  async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
948
916
  const timings = { phase1: client_utils_1.performance.now() };
949
- this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
917
+ this.service = await this.createDocumentService(async () => this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType));
950
918
  // Except in cases where it has stashed ops or requested by feature gate, the container will connect in "read" mode
951
919
  const mode = this.mc.config.getBoolean("Fluid.Container.ForceWriteConnection") === true ||
952
920
  (pendingLocalState?.savedOps.length ?? 0) > 0
@@ -963,25 +931,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
963
931
  this.connectToDeltaStream(connectionArgs);
964
932
  }
965
933
  this.storageAdapter.connectToService(this.service);
966
- this._attachState = container_definitions_1.AttachState.Attached;
934
+ this.attachmentData = {
935
+ state: container_definitions_1.AttachState.Attached,
936
+ };
967
937
  timings.phase2 = client_utils_1.performance.now();
968
938
  // Fetch specified snapshot.
969
- const { snapshot, versionId } = pendingLocalState === undefined
970
- ? await this.fetchSnapshotTree(specifiedVersion)
971
- : { snapshot: pendingLocalState.baseSnapshot, versionId: undefined };
972
- if (pendingLocalState) {
973
- this.baseSnapshot = pendingLocalState.baseSnapshot;
974
- this.baseSnapshotBlobs = pendingLocalState.snapshotBlobs;
975
- }
976
- else {
977
- (0, core_utils_1.assert)(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
978
- if (this.offlineLoadEnabled) {
979
- this.baseSnapshot = snapshot;
980
- // Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
981
- this.baseSnapshotBlobs = await (0, containerStorageAdapter_1.getBlobContentsFromTree)(snapshot, this.storageAdapter);
982
- }
983
- }
984
- const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
939
+ const { snapshotTree, version } = await this.serializedStateManager.fetchSnapshot(specifiedVersion, this.service?.policies?.supportGetSnapshotApi);
940
+ this._loadedFromVersion = version;
941
+ const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTree);
985
942
  // If we saved ops, we will replay them and don't need DeltaManager to fetch them
986
943
  const sequenceNumber = pendingLocalState?.savedOps[pendingLocalState.savedOps.length - 1]?.sequenceNumber;
987
944
  const dmAttributes = sequenceNumber !== undefined ? { ...attributes, sequenceNumber } : attributes;
@@ -1046,12 +1003,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1046
1003
  }
1047
1004
  // ...load in the existing quorum
1048
1005
  // Initialize the protocol handler
1049
- await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
1006
+ await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshotTree);
1050
1007
  timings.phase3 = client_utils_1.performance.now();
1051
1008
  const codeDetails = this.getCodeDetailsFromQuorum();
1052
- await this.instantiateRuntime(codeDetails, snapshot,
1009
+ await this.instantiateRuntime(codeDetails, snapshotTree,
1053
1010
  // give runtime a dummy value so it knows we're loading from a stash blob
1054
- pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined);
1011
+ pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined, (0, driver_utils_1.isInstanceOfISnapshot)(snapshotTree) ? snapshotTree : undefined);
1055
1012
  // replay saved ops
1056
1013
  if (pendingLocalState) {
1057
1014
  for (const message of pendingLocalState.savedOps) {
@@ -1106,7 +1063,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1106
1063
  }, undefined, core_interfaces_1.LogLevel.verbose);
1107
1064
  return {
1108
1065
  sequenceNumber: attributes.sequenceNumber,
1109
- version: versionId,
1066
+ version: version?.id,
1110
1067
  dmLastProcessedSeqNumber: this._deltaManager.lastSequenceNumber,
1111
1068
  dmLastKnownSeqNumber: this._deltaManager.lastKnownSeqNumber,
1112
1069
  };
@@ -1118,7 +1075,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1118
1075
  };
1119
1076
  await this.attachDeltaManagerOpHandler(attributes);
1120
1077
  // Need to just seed the source data in the code quorum. Quorum itself is empty
1121
- const qValues = (0, quorum_1.initQuorumValuesFromCodeDetails)(codeDetails);
1078
+ const qValues = (0, quorum_js_1.initQuorumValuesFromCodeDetails)(codeDetails);
1122
1079
  this.initializeProtocolState(attributes, {
1123
1080
  members: [],
1124
1081
  proposals: [],
@@ -1127,18 +1084,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1127
1084
  await this.instantiateRuntime(codeDetails, undefined);
1128
1085
  this.setLoaded();
1129
1086
  }
1130
- async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
1131
- if (detachedContainerSnapshot.tree[hasBlobsSummaryTree] !== undefined) {
1087
+ async rehydrateDetachedFromSnapshot({ baseSnapshot, snapshotBlobs, hasAttachmentBlobs, pendingRuntimeState, }) {
1088
+ if (hasAttachmentBlobs) {
1132
1089
  (0, core_utils_1.assert)(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1133
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
1134
- delete detachedContainerSnapshot.tree[hasBlobsSummaryTree];
1135
1090
  }
1136
- const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
1137
- this.storageAdapter.loadSnapshotForRehydratingContainer(snapshotTree);
1138
- const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTree);
1091
+ const snapshotTreeWithBlobContents = (0, utils_js_1.combineSnapshotTreeAndSnapshotBlobs)(baseSnapshot, snapshotBlobs);
1092
+ this.storageAdapter.loadSnapshotFromSnapshotBlobs(snapshotBlobs);
1093
+ const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTreeWithBlobContents);
1139
1094
  await this.attachDeltaManagerOpHandler(attributes);
1140
1095
  // Initialize the protocol handler
1141
- const baseTree = (0, utils_1.getProtocolSnapshotTree)(snapshotTree);
1096
+ const baseTree = (0, utils_js_1.getProtocolSnapshotTree)(snapshotTreeWithBlobContents);
1142
1097
  const qValues = await (0, driver_utils_1.readAndParse)(this.storageAdapter, baseTree.blobs.quorumValues);
1143
1098
  this.initializeProtocolState(attributes, {
1144
1099
  members: [],
@@ -1146,7 +1101,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1146
1101
  values: qValues,
1147
1102
  });
1148
1103
  const codeDetails = this.getCodeDetailsFromQuorum();
1149
- await this.instantiateRuntime(codeDetails, snapshotTree);
1104
+ await this.instantiateRuntime(codeDetails, snapshotTreeWithBlobContents, pendingRuntimeState);
1150
1105
  this.setLoaded();
1151
1106
  }
1152
1107
  async getDocumentAttributes(storage, tree) {
@@ -1170,7 +1125,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1170
1125
  values: [],
1171
1126
  };
1172
1127
  if (snapshot !== undefined) {
1173
- const baseTree = (0, utils_1.getProtocolSnapshotTree)(snapshot);
1128
+ const baseTree = (0, utils_js_1.getProtocolSnapshotTree)(snapshot);
1174
1129
  [quorumSnapshot.members, quorumSnapshot.proposals, quorumSnapshot.values] =
1175
1130
  await Promise.all([
1176
1131
  (0, driver_utils_1.readAndParse)(storage, baseTree.blobs.quorumMembers),
@@ -1246,10 +1201,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1246
1201
  const pkg = getCodeProposal(quorum);
1247
1202
  return pkg;
1248
1203
  }
1249
- static setupClient(containerId, options, clientDetailsOverride) {
1250
- const loaderOptionsClient = (0, structured_clone_1.default)(options?.client);
1204
+ static setupClient(containerId, loaderOptionsClient, clientDetailsOverride) {
1251
1205
  const client = loaderOptionsClient !== undefined
1252
- ? loaderOptionsClient
1206
+ ? (0, structured_clone_1.default)(loaderOptionsClient)
1253
1207
  : {
1254
1208
  details: {
1255
1209
  capabilities: { interactive: true },
@@ -1271,7 +1225,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1271
1225
  }
1272
1226
  client.details.environment = [
1273
1227
  client.details.environment,
1274
- ` loaderVersion:${packageVersion_1.pkgVersion}`,
1228
+ ` loaderVersion:${packageVersion_js_1.pkgVersion}`,
1275
1229
  ` containerId:${containerId}`,
1276
1230
  ].join(";");
1277
1231
  return client;
@@ -1283,11 +1237,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1283
1237
  * If it's not true, runtime is not in position to send ops.
1284
1238
  */
1285
1239
  activeConnection() {
1286
- return (this.connectionState === connectionState_1.ConnectionState.Connected && this.connectionMode === "write");
1240
+ return (this.connectionState === connectionState_js_1.ConnectionState.Connected && this.connectionMode === "write");
1287
1241
  }
1288
1242
  createDeltaManager() {
1289
1243
  const serviceProvider = () => this.service;
1290
- const deltaManager = new deltaManager_1.DeltaManager(serviceProvider, (0, telemetry_utils_1.createChildLogger)({ logger: this.subLogger, namespace: "DeltaManager" }), () => this.activeConnection(), (props) => new connectionManager_1.ConnectionManager(serviceProvider, () => this.isDirty, this.client, this._canReconnect, (0, telemetry_utils_1.createChildLogger)({ logger: this.subLogger, namespace: "ConnectionManager" }), props));
1244
+ const deltaManager = new deltaManager_js_1.DeltaManager(serviceProvider, (0, telemetry_utils_1.createChildLogger)({ logger: this.subLogger, namespace: "DeltaManager" }), () => this.activeConnection(), (props) => new connectionManager_js_1.ConnectionManager(serviceProvider, () => this.isDirty, this.client, this._canReconnect, (0, telemetry_utils_1.createChildLogger)({ logger: this.subLogger, namespace: "ConnectionManager" }), props));
1291
1245
  // Disable inbound queues as Container is not ready to accept any ops until we are fully loaded!
1292
1246
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1293
1247
  deltaManager.inbound.pause();
@@ -1303,10 +1257,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1303
1257
  deltaManager.on("cancelEstablishingConnection", (reason) => {
1304
1258
  this.connectionStateHandler.cancelEstablishingConnection(reason);
1305
1259
  });
1306
- deltaManager.on("disconnect", (reason) => {
1260
+ deltaManager.on("disconnect", (text, error) => {
1307
1261
  this.noopHeuristic?.notifyDisconnect();
1308
1262
  if (!this.closed) {
1309
- this.connectionStateHandler.receivedDisconnectEvent(reason);
1263
+ this.connectionStateHandler.receivedDisconnectEvent({ text, error });
1310
1264
  }
1311
1265
  });
1312
1266
  deltaManager.on("throttled", (warning) => {
@@ -1319,7 +1273,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1319
1273
  this.emit("warning", warn);
1320
1274
  });
1321
1275
  deltaManager.on("readonly", (readonly) => {
1322
- this.setContextConnectedState(this.connectionState === connectionState_1.ConnectionState.Connected, readonly);
1276
+ this.setContextConnectedState(this.connectionState === connectionState_js_1.ConnectionState.Connected, readonly);
1323
1277
  this.emit("readonly", readonly);
1324
1278
  });
1325
1279
  deltaManager.on("closed", (error) => {
@@ -1348,16 +1302,16 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1348
1302
  let autoReconnect;
1349
1303
  let checkpointSequenceNumber;
1350
1304
  let opsBehind;
1351
- if (value === connectionState_1.ConnectionState.Disconnected) {
1305
+ if (value === connectionState_js_1.ConnectionState.Disconnected) {
1352
1306
  autoReconnect = this._deltaManager.connectionManager.reconnectMode;
1353
1307
  }
1354
1308
  else {
1355
- if (value === connectionState_1.ConnectionState.Connected) {
1309
+ if (value === connectionState_js_1.ConnectionState.Connected) {
1356
1310
  durationFromDisconnected =
1357
- time - this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected];
1311
+ time - this.connectionTransitionTimes[connectionState_js_1.ConnectionState.Disconnected];
1358
1312
  durationFromDisconnected = (0, telemetry_utils_1.formatTick)(durationFromDisconnected);
1359
1313
  }
1360
- else if (value === connectionState_1.ConnectionState.CatchingUp) {
1314
+ else if (value === connectionState_js_1.ConnectionState.CatchingUp) {
1361
1315
  // This info is of most interesting while Catching Up.
1362
1316
  checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
1363
1317
  // Need to check that we have already loaded and fetched the snapshot.
@@ -1369,8 +1323,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1369
1323
  connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
1370
1324
  }
1371
1325
  this.mc.logger.sendPerformanceEvent({
1372
- eventName: `ConnectionStateChange_${connectionState_1.ConnectionState[value]}`,
1373
- from: connectionState_1.ConnectionState[oldState],
1326
+ eventName: `ConnectionStateChange_${connectionState_js_1.ConnectionState[value]}`,
1327
+ from: connectionState_js_1.ConnectionState[oldState],
1374
1328
  duration,
1375
1329
  durationFromDisconnected,
1376
1330
  reason: reason?.text,
@@ -1388,7 +1342,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1388
1342
  isDirty: this.isDirty,
1389
1343
  ...this._deltaManager.connectionProps,
1390
1344
  }, reason?.error);
1391
- if (value === connectionState_1.ConnectionState.Connected) {
1345
+ if (value === connectionState_js_1.ConnectionState.Connected) {
1392
1346
  this.firstConnection = false;
1393
1347
  }
1394
1348
  }
@@ -1397,11 +1351,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1397
1351
  // After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
1398
1352
  // This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
1399
1353
  if (!initialTransition &&
1400
- this.connectionState !== connectionState_1.ConnectionState.Connected &&
1401
- this.connectionState !== connectionState_1.ConnectionState.Disconnected) {
1354
+ this.connectionState !== connectionState_js_1.ConnectionState.Connected &&
1355
+ this.connectionState !== connectionState_js_1.ConnectionState.Disconnected) {
1402
1356
  return;
1403
1357
  }
1404
- const state = this.connectionState === connectionState_1.ConnectionState.Connected;
1358
+ const state = this.connectionState === connectionState_js_1.ConnectionState.Connected;
1405
1359
  // Both protocol and context should not be undefined if we got so far.
1406
1360
  this.setContextConnectedState(state, this.readOnlyInfo.readonly ?? false);
1407
1361
  this.protocolHandler.setConnectionState(state, this.clientId);
@@ -1443,7 +1397,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1443
1397
  return this.submitMessage(protocol_definitions_1.MessageType.Summarize, JSON.stringify(summary), false /* batch */, undefined /* metadata */, undefined /* compression */, referenceSequenceNumber);
1444
1398
  }
1445
1399
  submitMessage(type, contents, batch, metadata, compression, referenceSequenceNumber) {
1446
- if (this.connectionState !== connectionState_1.ConnectionState.Connected) {
1400
+ if (this.connectionState !== connectionState_js_1.ConnectionState.Connected) {
1447
1401
  this.mc.logger.sendErrorEvent({ eventName: "SubmitMessageWithNoConnection", type });
1448
1402
  return -1;
1449
1403
  }
@@ -1451,14 +1405,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1451
1405
  return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
1452
1406
  }
1453
1407
  processRemoteMessage(message) {
1454
- if (this.offlineLoadEnabled) {
1455
- this.savedOps.push(message);
1456
- }
1457
1408
  const local = this.clientId === message.clientId;
1458
1409
  // Allow the protocol handler to process the message
1459
1410
  const result = this.protocolHandler.processMessage(message, local);
1460
1411
  // Forward messages to the loaded runtime for processing
1461
1412
  this.runtime.process(message, local);
1413
+ this.serializedStateManager.addProcessedOp(message);
1462
1414
  // Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
1463
1415
  if (this.activeConnection()) {
1464
1416
  if (this.noopHeuristic === undefined) {
@@ -1468,7 +1420,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1468
1420
  // clients.
1469
1421
  // All existing will continue to use settings they got earlier.
1470
1422
  (0, core_utils_1.assert)(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
1471
- this.noopHeuristic = new noopHeuristic_1.NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
1423
+ this.noopHeuristic = new noopHeuristic_js_1.NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
1472
1424
  this.noopHeuristic.on("wantsNoop", () => {
1473
1425
  // On disconnect we notify the heuristic which should prevent it from wanting a noop.
1474
1426
  // Hitting this assert would imply we lost activeConnection between notifying the heuristic of a processed message and
@@ -1491,7 +1443,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1491
1443
  }
1492
1444
  processSignal(message) {
1493
1445
  // No clientId indicates a system signal message.
1494
- if ((0, protocol_1.protocolHandlerShouldProcessSignal)(message)) {
1446
+ if ((0, protocol_js_1.protocolHandlerShouldProcessSignal)(message)) {
1495
1447
  this.protocolHandler.processSignal(message);
1496
1448
  }
1497
1449
  else {
@@ -1499,33 +1451,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1499
1451
  this.runtime.processSignal(message, local);
1500
1452
  }
1501
1453
  }
1502
- /**
1503
- * Get the most recent snapshot, or a specific version.
1504
- * @param specifiedVersion - The specific version of the snapshot to retrieve
1505
- * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
1506
- */
1507
- async fetchSnapshotTree(specifiedVersion) {
1508
- const version = await this.getVersion(specifiedVersion ?? null);
1509
- if (version === undefined && specifiedVersion !== undefined) {
1510
- // We should have a defined version to load from if specified version requested
1511
- this.mc.logger.sendErrorEvent({
1512
- eventName: "NoVersionFoundWhenSpecified",
1513
- id: specifiedVersion,
1514
- });
1515
- }
1516
- this._loadedFromVersion = version;
1517
- const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
1518
- if (snapshot === undefined && version !== undefined) {
1519
- this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
1520
- }
1521
- return { snapshot, versionId: version?.id };
1522
- }
1523
- async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
1454
+ async instantiateRuntime(codeDetails, snapshotTree, pendingLocalState, snapshot) {
1524
1455
  (0, core_utils_1.assert)(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
1525
1456
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1526
1457
  // are set. Global requests will still go directly to the loader
1527
1458
  const maybeLoader = this.scope;
1528
- const loader = new loader_1.RelativeLoader(this, maybeLoader.ILoader);
1459
+ const loader = new loader_js_1.RelativeLoader(this, maybeLoader.ILoader);
1529
1460
  const loadCodeResult = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "CodeLoad" }, async () => this.codeLoader.load(codeDetails));
1530
1461
  this._loadedModule = {
1531
1462
  module: loadCodeResult.module,
@@ -1541,8 +1472,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1541
1472
  }
1542
1473
  const getSpecifiedCodeDetails = () => (this.protocolHandler.quorum.get("code") ??
1543
1474
  this.protocolHandler.quorum.get("code2"));
1544
- const existing = snapshot !== undefined;
1545
- const context = new containerContext_1.ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (content, targetClientId) => this.submitSignal(content, targetClientId), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => this.resolvedUrl?.id, () => this.clientId, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState);
1475
+ const existing = snapshotTree !== undefined;
1476
+ const context = new containerContext_js_1.ContainerContext(this.options, this.scope, snapshotTree, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (content, targetClientId) => this.submitSignal(content, targetClientId), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => this.resolvedUrl?.id, () => this.clientId, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState, snapshot);
1546
1477
  this._runtime = await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
1547
1478
  this._lifecycleEvents.emit("runtimeInstantiated");
1548
1479
  this._loadedCodeDetails = codeDetails;