@fluidframework/container-loader 2.0.0-dev-rc.1.0.0.228517 → 2.0.0-dev-rc.2.0.0.245554

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 +21 -20
  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 +219 -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} +11 -12
  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} +179 -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 +63 -63
  225. package/src/attachment.ts +222 -0
  226. package/src/audience.ts +9 -3
  227. package/src/connectionManager.ts +15 -13
  228. package/src/connectionState.ts +1 -0
  229. package/src/connectionStateHandler.ts +8 -7
  230. package/src/container.ts +297 -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
@@ -3,32 +3,34 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { v4 as uuid } from "uuid";
6
- import { assert, unreachableCase } from "@fluidframework/core-utils";
6
+ import { assert, unreachableCase, isPromiseLike } from "@fluidframework/core-utils";
7
7
  import { TypedEventEmitter, performance } from "@fluid-internal/client-utils";
8
8
  import { LogLevel, } from "@fluidframework/core-interfaces";
9
9
  import { AttachState, isFluidCodeDetails, } from "@fluidframework/container-definitions";
10
- import { readAndParse, OnlineStatus, isOnline, runWithRetry, isCombinedAppAndProtocolSummary, MessageType2, } from "@fluidframework/driver-utils";
10
+ import { readAndParse, OnlineStatus, isOnline, isCombinedAppAndProtocolSummary, MessageType2, isInstanceOfISnapshot, runWithRetry, } from "@fluidframework/driver-utils";
11
11
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
12
12
  import { createChildLogger, EventEmitterWithErrorHandling, PerformanceEvent, raiseConnectedEvent, connectedEventName, normalizeError, createChildMonitoringContext, wrapError, formatTick, GenericError, UsageError, } from "@fluidframework/telemetry-utils";
13
- import { Audience } from "./audience.mjs";
14
- import { ContainerContext } from "./containerContext.mjs";
15
- import { ReconnectMode, getPackageName, } from "./contracts.mjs";
16
- import { DeltaManager } from "./deltaManager.mjs";
17
- import { RelativeLoader } from "./loader.mjs";
18
- import { pkgVersion } from "./packageVersion.mjs";
19
- import { ContainerStorageAdapter, getBlobContentsFromTree, getBlobContentsFromTreeWithBlobContents, } from "./containerStorageAdapter.mjs";
20
- import { createConnectionStateHandler } from "./connectionStateHandler.mjs";
21
- import { combineAppAndProtocolSummary, getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer, } from "./utils.mjs";
22
- import { initQuorumValuesFromCodeDetails } from "./quorum.mjs";
23
- import { NoopHeuristic } from "./noopHeuristic.mjs";
24
- import { ConnectionManager } from "./connectionManager.mjs";
25
- import { ConnectionState } from "./connectionState.mjs";
26
- import { ProtocolHandler, protocolHandlerShouldProcessSignal, } from "./protocol.mjs";
13
+ import structuredClone from "@ungap/structured-clone";
14
+ import { Audience } from "./audience.js";
15
+ import { ContainerContext } from "./containerContext.js";
16
+ import { ReconnectMode, getPackageName, } from "./contracts.js";
17
+ import { DeltaManager } from "./deltaManager.js";
18
+ import { RelativeLoader } from "./loader.js";
19
+ import { pkgVersion } from "./packageVersion.js";
20
+ import { ContainerStorageAdapter } from "./containerStorageAdapter.js";
21
+ import { createConnectionStateHandler } from "./connectionStateHandler.js";
22
+ import { combineAppAndProtocolSummary, getProtocolSnapshotTree, getSnapshotTreeAndBlobsFromSerializedContainer, combineSnapshotTreeAndSnapshotBlobs, getDetachedContainerStateFromSerializedContainer, runSingle, } from "./utils.js";
23
+ import { initQuorumValuesFromCodeDetails } from "./quorum.js";
24
+ import { NoopHeuristic } from "./noopHeuristic.js";
25
+ import { ConnectionManager } from "./connectionManager.js";
26
+ import { ConnectionState } from "./connectionState.js";
27
+ import { ProtocolHandler, protocolHandlerShouldProcessSignal, } from "./protocol.js";
28
+ import { runRetriableAttachProcess } from "./attachment.js";
29
+ import { SerializedStateManager } from "./serializedStateManager.js";
27
30
  const detachedContainerRefSeqNumber = 0;
28
31
  const dirtyContainerEvent = "dirty";
29
32
  const savedContainerEvent = "saved";
30
33
  const packageNotFactoryError = "Code package does not implement IRuntimeFactory";
31
- const hasBlobsSummaryTree = ".hasAttachmentBlobs";
32
34
  /**
33
35
  * Waits until container connects to delta storage and gets up-to-date.
34
36
  *
@@ -103,9 +105,7 @@ export async function waitContainerToCatchUp(container) {
103
105
  }
104
106
  });
105
107
  }
106
- const getCodeProposal =
107
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
108
- (quorum) => quorum.get("code") ?? quorum.get("code2");
108
+ const getCodeProposal = (quorum) => quorum.get("code") ?? quorum.get("code2");
109
109
  /**
110
110
  * Helper function to report to telemetry cases where operation takes longer than expected (200ms)
111
111
  * @param logger - logger to use
@@ -123,7 +123,6 @@ const summarizerClientType = "summarizer";
123
123
  export class Container extends EventEmitterWithErrorHandling {
124
124
  /**
125
125
  * Load an existing container.
126
- * @internal
127
126
  */
128
127
  static async load(loadProps, createProps) {
129
128
  const { version, pendingLocalState, loadMode, resolvedUrl, loadToSequenceNumber } = loadProps;
@@ -180,11 +179,8 @@ export class Container extends EventEmitterWithErrorHandling {
180
179
  static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
181
180
  const container = new Container(createProps);
182
181
  return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
183
- const deserializedSummary = JSON.parse(snapshot);
184
- if (!isCombinedAppAndProtocolSummary(deserializedSummary, hasBlobsSummaryTree)) {
185
- throw new UsageError("Cannot rehydrate detached container. Incorrect format");
186
- }
187
- await container.rehydrateDetachedFromSnapshot(deserializedSummary);
182
+ const detachedContainerState = getDetachedContainerStateFromSerializedContainer(snapshot);
183
+ await container.rehydrateDetachedFromSnapshot(detachedContainerState);
188
184
  return container;
189
185
  }, { start: true, end: true, cancel: "generic" });
190
186
  }
@@ -235,6 +231,9 @@ export class Container extends EventEmitterWithErrorHandling {
235
231
  get readOnlyInfo() {
236
232
  return this._deltaManager.readOnlyInfo;
237
233
  }
234
+ get containerMetadata() {
235
+ return this._containerMetadata;
236
+ }
238
237
  /**
239
238
  * Sends signal to runtime (and data stores) to be read-only.
240
239
  * Hosts may have read only views, indicating to data stores that no edits are allowed.
@@ -271,11 +270,8 @@ export class Container extends EventEmitterWithErrorHandling {
271
270
  get clientId() {
272
271
  return this._clientId;
273
272
  }
274
- get offlineLoadEnabled() {
275
- const enabled = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ??
276
- this.options?.enableOfflineLoad === true;
277
- // summarizer will not have any pending state we want to save
278
- return enabled && this.deltaManager.clientDetails.capabilities.interactive;
273
+ get isInteractiveClient() {
274
+ return this.deltaManager.clientDetails.capabilities.interactive;
279
275
  }
280
276
  /**
281
277
  * Get the code details that are currently specified for the container.
@@ -330,9 +326,6 @@ export class Container extends EventEmitterWithErrorHandling {
330
326
  this._lifecycleEvents.once("disposed", disposedHandler);
331
327
  });
332
328
  }
333
- /**
334
- * @internal
335
- */
336
329
  constructor(createProps, loadProps) {
337
330
  super((name, error) => {
338
331
  this.mc.logger.sendErrorEvent({
@@ -356,24 +349,102 @@ export class Container extends EventEmitterWithErrorHandling {
356
349
  * disposed: Container has been disposed
357
350
  */
358
351
  this._lifecycleState = "loading";
359
- this._attachState = AttachState.Detached;
360
352
  /** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
361
353
  this.inboundQueuePausedFromInit = true;
362
354
  this.firstConnection = true;
363
355
  this.connectionTransitionTimes = [];
364
- this.attachStarted = false;
365
356
  this._dirtyContainer = false;
366
- this.savedOps = [];
357
+ this.attachmentData = { state: AttachState.Detached };
367
358
  this.clientsWhoShouldHaveLeft = new Set();
359
+ this._containerMetadata = {};
368
360
  this.setAutoReconnectTime = performance.now();
369
361
  this._lifecycleEvents = new TypedEventEmitter();
370
362
  this._disposed = false;
363
+ this.attach = runSingle(async (request, attachProps) => {
364
+ await PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
365
+ if (this._lifecycleState !== "loaded" ||
366
+ this.attachmentData.state === AttachState.Attached) {
367
+ // pre-0.58 error message: containerNotValidForAttach
368
+ throw new UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}] and [${this.attachState}]`);
369
+ }
370
+ const normalizeErrorAndClose = (error) => {
371
+ const newError = normalizeError(error);
372
+ this.close(newError);
373
+ // add resolved URL on error object so that host has the ability to find this document and delete it
374
+ newError.addTelemetryProperties({
375
+ resolvedUrl: this.service?.resolvedUrl?.url,
376
+ });
377
+ return newError;
378
+ };
379
+ const setAttachmentData = (attachmentData) => {
380
+ const previousState = this.attachmentData.state;
381
+ this.attachmentData = attachmentData;
382
+ const state = this.attachmentData.state;
383
+ if (state !== previousState && state !== AttachState.Detached) {
384
+ try {
385
+ this.runtime.setAttachState(state);
386
+ this.emit(state.toLocaleLowerCase());
387
+ }
388
+ catch (error) {
389
+ throw normalizeErrorAndClose(error);
390
+ }
391
+ }
392
+ };
393
+ const createAttachmentSummary = (redirectTable) => {
394
+ try {
395
+ assert(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
396
+ return combineAppAndProtocolSummary(this.runtime.createSummary(redirectTable), this.captureProtocolSummary());
397
+ }
398
+ catch (error) {
399
+ throw normalizeErrorAndClose(error);
400
+ }
401
+ };
402
+ const createOrGetStorageService = async (summary) => {
403
+ // Actually go and create the resolved document
404
+ if (this.service === undefined) {
405
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
406
+ assert(this.client.details.type !== summarizerClientType &&
407
+ createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
408
+ this.service = await runWithRetry(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
409
+ cancel: this._deltaManager.closeAbortController.signal,
410
+ });
411
+ }
412
+ this.storageAdapter.connectToService(this.service);
413
+ return this.storageAdapter;
414
+ };
415
+ let attachP = runRetriableAttachProcess({
416
+ initialAttachmentData: this.attachmentData,
417
+ offlineLoadEnabled: this.serializedStateManager.offlineLoadEnabled,
418
+ detachedBlobStorage: this.detachedBlobStorage,
419
+ setAttachmentData,
420
+ createAttachmentSummary,
421
+ createOrGetStorageService,
422
+ });
423
+ // only enable the new behavior if the config is set
424
+ if (this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true) {
425
+ attachP = attachP.catch((error) => {
426
+ throw normalizeErrorAndClose(error);
427
+ });
428
+ }
429
+ this.serializedStateManager.setSnapshot(await attachP);
430
+ if (!this.closed) {
431
+ this.handleDeltaConnectionArg({
432
+ fetchOpsFromStorage: false,
433
+ reason: { text: "createDetached" },
434
+ }, attachProps?.deltaConnection);
435
+ }
436
+ }, { start: true, end: true, cancel: "generic" });
437
+ });
371
438
  this.getAbsoluteUrl = async (relativeUrl) => {
372
439
  if (this.resolvedUrl === undefined) {
373
440
  return undefined;
374
441
  }
375
442
  return this.urlResolver.getAbsoluteUrl(this.resolvedUrl, relativeUrl, getPackageName(this._loadedCodeDetails));
376
443
  };
444
+ this.metadataUpdateHandler = (metadata) => {
445
+ this._containerMetadata = { ...this._containerMetadata, ...metadata };
446
+ this.emit("metadataUpdate", metadata);
447
+ };
377
448
  this.updateDirtyContainerState = (dirty) => {
378
449
  if (this._dirtyContainer === dirty) {
379
450
  return;
@@ -407,7 +478,7 @@ export class Container extends EventEmitterWithErrorHandling {
407
478
  });
408
479
  };
409
480
  this._containerId = uuid();
410
- this.client = Container.setupClient(this._containerId, this.options, this.clientDetailsOverride);
481
+ this.client = Container.setupClient(this._containerId, options.client, this.clientDetailsOverride);
411
482
  // Create logger for data stores to use
412
483
  const type = this.client.details.type;
413
484
  const interactive = this.client.details.capabilities.interactive;
@@ -421,7 +492,7 @@ export class Container extends EventEmitterWithErrorHandling {
421
492
  clientType,
422
493
  containerId: this._containerId,
423
494
  docId: () => this.resolvedUrl?.id,
424
- containerAttachState: () => this._attachState,
495
+ containerAttachState: () => this.attachState,
425
496
  containerLifecycleState: () => this._lifecycleState,
426
497
  containerConnectionState: () => ConnectionState[this.connectionState],
427
498
  serializedContainer: pendingLocalState !== undefined,
@@ -513,6 +584,10 @@ export class Container extends EventEmitterWithErrorHandling {
513
584
  const forceEnableSummarizeProtocolTree = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
514
585
  options.summarizeProtocolTree;
515
586
  this.storageAdapter = new ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState?.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
587
+ const offlineLoadEnabled = (this.isInteractiveClient &&
588
+ this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) ??
589
+ options.enableOfflineLoad === true;
590
+ this.serializedStateManager = new SerializedStateManager(pendingLocalState, this.subLogger, this.storageAdapter, offlineLoadEnabled);
516
591
  const isDomAvailable = typeof document === "object" &&
517
592
  document !== null &&
518
593
  typeof document.addEventListener === "function" &&
@@ -572,6 +647,10 @@ export class Container extends EventEmitterWithErrorHandling {
572
647
  : "generic",
573
648
  }, error);
574
649
  this._lifecycleState = "closing";
650
+ // Back-compat for Old driver
651
+ if (this.service?.off !== undefined) {
652
+ this.service?.off("metadataUpdate", this.metadataUpdateHandler);
653
+ }
575
654
  this._protocolHandler?.close();
576
655
  this.connectionStateHandler.dispose();
577
656
  }
@@ -647,149 +726,35 @@ export class Container extends EventEmitterWithErrorHandling {
647
726
  return this.getPendingLocalStateCore({ notifyImminentClosure: false });
648
727
  }
649
728
  async getPendingLocalStateCore(props) {
650
- return PerformanceEvent.timedExecAsync(this.mc.logger, {
651
- eventName: "getPendingLocalState",
652
- notifyImminentClosure: props.notifyImminentClosure,
653
- savedOpsSize: this.savedOps.length,
654
- clientId: this.clientId,
655
- }, async () => {
656
- if (!this.offlineLoadEnabled) {
657
- throw new UsageError("Can't get pending local state unless offline load is enabled");
658
- }
659
- if (this.closed || this._disposed) {
660
- throw new UsageError("Pending state cannot be retried if the container is closed or disposed");
661
- }
662
- assert(this.attachState === AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
663
- assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
664
- assert(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
665
- assert(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
666
- const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
667
- const pendingState = {
668
- pendingRuntimeState,
669
- baseSnapshot: this.baseSnapshot,
670
- snapshotBlobs: this.baseSnapshotBlobs,
671
- savedOps: this.savedOps,
672
- url: this.resolvedUrl.url,
673
- // no need to save this if there is no pending runtime state
674
- clientId: pendingRuntimeState !== undefined ? this.clientId : undefined,
675
- };
676
- return JSON.stringify(pendingState);
677
- });
729
+ if (this.closed || this._disposed) {
730
+ throw new UsageError("Pending state cannot be retried if the container is closed or disposed");
731
+ }
732
+ assert(this.attachmentData.state === AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
733
+ assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
734
+ const pendingState = await this.serializedStateManager.getPendingLocalStateCore(props, this.clientId, this.runtime, this.resolvedUrl);
735
+ return pendingState;
678
736
  }
679
737
  get attachState() {
680
- return this._attachState;
738
+ return this.attachmentData.state;
681
739
  }
682
740
  serialize() {
683
- assert(this.attachState === AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
684
- const appSummary = this.runtime.createSummary();
685
- const protocolSummary = this.captureProtocolSummary();
686
- const combinedSummary = combineAppAndProtocolSummary(appSummary, protocolSummary);
687
- if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
688
- combinedSummary.tree[hasBlobsSummaryTree] = {
689
- type: SummaryType.Blob,
690
- content: "true",
691
- };
741
+ if (this.attachmentData.state === AttachState.Attached || this.closed) {
742
+ throw new UsageError("Container must not be attached or closed.");
692
743
  }
693
- return JSON.stringify(combinedSummary);
694
- }
695
- async attach(request, attachProps) {
696
- await PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
697
- if (this._lifecycleState !== "loaded") {
698
- // pre-0.58 error message: containerNotValidForAttach
699
- throw new UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
700
- }
701
- // If container is already attached or attach is in progress, throw an error.
702
- assert(this._attachState === AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
703
- this.attachStarted = true;
704
- // If attachment blobs were uploaded in detached state we will go through a different attach flow
705
- const hasAttachmentBlobs = this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0;
706
- try {
707
- assert(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
708
- let summary;
709
- if (!hasAttachmentBlobs) {
710
- // Get the document state post attach - possibly can just call attach but we need to change the
711
- // semantics around what the attach means as far as async code goes.
712
- const appSummary = this.runtime.createSummary();
713
- const protocolSummary = this.captureProtocolSummary();
714
- summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
715
- // Set the state as attaching as we are starting the process of attaching container.
716
- // This should be fired after taking the summary because it is the place where we are
717
- // starting to attach the container to storage.
718
- // Also, this should only be fired in detached container.
719
- this._attachState = AttachState.Attaching;
720
- this.runtime.setAttachState(AttachState.Attaching);
721
- this.emit("attaching");
722
- if (this.offlineLoadEnabled) {
723
- const snapshot = getSnapshotTreeFromSerializedContainer(summary);
724
- this.baseSnapshot = snapshot;
725
- this.baseSnapshotBlobs =
726
- getBlobContentsFromTreeWithBlobContents(snapshot);
727
- }
728
- }
729
- // Actually go and create the resolved document
730
- if (this.service === undefined) {
731
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
732
- assert(this.client.details.type !== summarizerClientType &&
733
- createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
734
- this.service = await runWithRetry(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
735
- cancel: this._deltaManager.closeAbortController.signal,
736
- });
737
- }
738
- this.storageAdapter.connectToService(this.service);
739
- if (hasAttachmentBlobs) {
740
- // upload blobs to storage
741
- assert(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
742
- // build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
743
- // support blob handles that only know about the local IDs
744
- const redirectTable = new Map();
745
- // if new blobs are added while uploading, upload them too
746
- while (redirectTable.size < this.detachedBlobStorage.size) {
747
- const newIds = this.detachedBlobStorage
748
- .getBlobIds()
749
- .filter((id) => !redirectTable.has(id));
750
- for (const id of newIds) {
751
- const blob = await this.detachedBlobStorage.readBlob(id);
752
- const response = await this.storageAdapter.createBlob(blob);
753
- redirectTable.set(id, response.id);
754
- }
755
- }
756
- // take summary and upload
757
- const appSummary = this.runtime.createSummary(redirectTable);
758
- const protocolSummary = this.captureProtocolSummary();
759
- summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
760
- this._attachState = AttachState.Attaching;
761
- this.runtime.setAttachState(AttachState.Attaching);
762
- this.emit("attaching");
763
- if (this.offlineLoadEnabled) {
764
- const snapshot = getSnapshotTreeFromSerializedContainer(summary);
765
- this.baseSnapshot = snapshot;
766
- this.baseSnapshotBlobs =
767
- getBlobContentsFromTreeWithBlobContents(snapshot);
768
- }
769
- await this.storageAdapter.uploadSummaryWithContext(summary, {
770
- referenceSequenceNumber: 0,
771
- ackHandle: undefined,
772
- proposalHandle: undefined,
773
- });
774
- }
775
- this._attachState = AttachState.Attached;
776
- this.runtime.setAttachState(AttachState.Attached);
777
- this.emit("attached");
778
- if (!this.closed) {
779
- this.handleDeltaConnectionArg({
780
- fetchOpsFromStorage: false,
781
- reason: { text: "createDetached" },
782
- }, attachProps?.deltaConnection);
783
- }
784
- }
785
- catch (error) {
786
- // add resolved URL on error object so that host has the ability to find this document and delete it
787
- const newError = normalizeError(error);
788
- newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
789
- this.close(newError);
790
- throw newError;
791
- }
792
- }, { start: true, end: true, cancel: "generic" });
744
+ const attachingData = this.attachmentData.state === AttachState.Attaching ? this.attachmentData : undefined;
745
+ const combinedSummary = attachingData?.summary ??
746
+ combineAppAndProtocolSummary(this.runtime.createSummary(), this.captureProtocolSummary());
747
+ const { tree: snapshot, blobs } = getSnapshotTreeAndBlobsFromSerializedContainer(combinedSummary);
748
+ const pendingRuntimeState = attachingData !== undefined ? this.runtime.getPendingLocalState() : undefined;
749
+ assert(!isPromiseLike(pendingRuntimeState), 0x8e3 /* should not be a promise */);
750
+ const detachedContainerState = {
751
+ attached: false,
752
+ baseSnapshot: snapshot,
753
+ snapshotBlobs: blobs,
754
+ pendingRuntimeState,
755
+ hasAttachmentBlobs: !!this.detachedBlobStorage && this.detachedBlobStorage.size > 0,
756
+ };
757
+ return JSON.stringify(detachedContainerState);
793
758
  }
794
759
  setAutoReconnectInternal(mode, reason) {
795
760
  const currentMode = this._deltaManager.connectionManager.reconnectMode;
@@ -811,7 +776,7 @@ export class Container extends EventEmitterWithErrorHandling {
811
776
  if (this.closed) {
812
777
  throw new UsageError(`The Container is closed and cannot be connected`);
813
778
  }
814
- else if (this._attachState !== AttachState.Attached) {
779
+ else if (this.attachState !== AttachState.Attached) {
815
780
  throw new UsageError(`The Container is not attached and cannot be connected`);
816
781
  }
817
782
  else if (!this.connected) {
@@ -826,7 +791,7 @@ export class Container extends EventEmitterWithErrorHandling {
826
791
  }
827
792
  connectInternal(args) {
828
793
  assert(!this.closed, 0x2c5 /* "Attempting to connect() a closed Container" */);
829
- assert(this._attachState === AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
794
+ assert(this.attachState === AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
830
795
  // Resume processing ops and connect to delta stream
831
796
  this.resumeInternal(args);
832
797
  // Set Auto Reconnect Mode
@@ -919,10 +884,6 @@ export class Container extends EventEmitterWithErrorHandling {
919
884
  }
920
885
  return true;
921
886
  }
922
- async getVersion(version) {
923
- const versions = await this.storageAdapter.getVersions(version, 1);
924
- return versions[0];
925
- }
926
887
  connectToDeltaStream(args) {
927
888
  // All agents need "write" access, including summarizer.
928
889
  if (!this._canReconnect || !this.client.details.capabilities.interactive) {
@@ -930,6 +891,14 @@ export class Container extends EventEmitterWithErrorHandling {
930
891
  }
931
892
  this._deltaManager.connect(args);
932
893
  }
894
+ async createDocumentService(serviceProvider) {
895
+ const service = await serviceProvider();
896
+ // Back-compat for Old driver
897
+ if (service.on !== undefined) {
898
+ service.on("metadataUpdate", this.metadataUpdateHandler);
899
+ }
900
+ return service;
901
+ }
933
902
  /**
934
903
  * Load container.
935
904
  *
@@ -937,7 +906,7 @@ export class Container extends EventEmitterWithErrorHandling {
937
906
  */
938
907
  async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
939
908
  const timings = { phase1: performance.now() };
940
- this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
909
+ this.service = await this.createDocumentService(async () => this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType));
941
910
  // Except in cases where it has stashed ops or requested by feature gate, the container will connect in "read" mode
942
911
  const mode = this.mc.config.getBoolean("Fluid.Container.ForceWriteConnection") === true ||
943
912
  (pendingLocalState?.savedOps.length ?? 0) > 0
@@ -954,25 +923,14 @@ export class Container extends EventEmitterWithErrorHandling {
954
923
  this.connectToDeltaStream(connectionArgs);
955
924
  }
956
925
  this.storageAdapter.connectToService(this.service);
957
- this._attachState = AttachState.Attached;
926
+ this.attachmentData = {
927
+ state: AttachState.Attached,
928
+ };
958
929
  timings.phase2 = performance.now();
959
930
  // Fetch specified snapshot.
960
- const { snapshot, versionId } = pendingLocalState === undefined
961
- ? await this.fetchSnapshotTree(specifiedVersion)
962
- : { snapshot: pendingLocalState.baseSnapshot, versionId: undefined };
963
- if (pendingLocalState) {
964
- this.baseSnapshot = pendingLocalState.baseSnapshot;
965
- this.baseSnapshotBlobs = pendingLocalState.snapshotBlobs;
966
- }
967
- else {
968
- assert(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
969
- if (this.offlineLoadEnabled) {
970
- this.baseSnapshot = snapshot;
971
- // Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
972
- this.baseSnapshotBlobs = await getBlobContentsFromTree(snapshot, this.storageAdapter);
973
- }
974
- }
975
- const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
931
+ const { snapshotTree, version } = await this.serializedStateManager.fetchSnapshot(specifiedVersion, this.service?.policies?.supportGetSnapshotApi);
932
+ this._loadedFromVersion = version;
933
+ const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTree);
976
934
  // If we saved ops, we will replay them and don't need DeltaManager to fetch them
977
935
  const sequenceNumber = pendingLocalState?.savedOps[pendingLocalState.savedOps.length - 1]?.sequenceNumber;
978
936
  const dmAttributes = sequenceNumber !== undefined ? { ...attributes, sequenceNumber } : attributes;
@@ -1037,12 +995,12 @@ export class Container extends EventEmitterWithErrorHandling {
1037
995
  }
1038
996
  // ...load in the existing quorum
1039
997
  // Initialize the protocol handler
1040
- await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
998
+ await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshotTree);
1041
999
  timings.phase3 = performance.now();
1042
1000
  const codeDetails = this.getCodeDetailsFromQuorum();
1043
- await this.instantiateRuntime(codeDetails, snapshot,
1001
+ await this.instantiateRuntime(codeDetails, snapshotTree,
1044
1002
  // give runtime a dummy value so it knows we're loading from a stash blob
1045
- pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined);
1003
+ pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined, isInstanceOfISnapshot(snapshotTree) ? snapshotTree : undefined);
1046
1004
  // replay saved ops
1047
1005
  if (pendingLocalState) {
1048
1006
  for (const message of pendingLocalState.savedOps) {
@@ -1097,7 +1055,7 @@ export class Container extends EventEmitterWithErrorHandling {
1097
1055
  }, undefined, LogLevel.verbose);
1098
1056
  return {
1099
1057
  sequenceNumber: attributes.sequenceNumber,
1100
- version: versionId,
1058
+ version: version?.id,
1101
1059
  dmLastProcessedSeqNumber: this._deltaManager.lastSequenceNumber,
1102
1060
  dmLastKnownSeqNumber: this._deltaManager.lastKnownSeqNumber,
1103
1061
  };
@@ -1118,18 +1076,16 @@ export class Container extends EventEmitterWithErrorHandling {
1118
1076
  await this.instantiateRuntime(codeDetails, undefined);
1119
1077
  this.setLoaded();
1120
1078
  }
1121
- async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
1122
- if (detachedContainerSnapshot.tree[hasBlobsSummaryTree] !== undefined) {
1079
+ async rehydrateDetachedFromSnapshot({ baseSnapshot, snapshotBlobs, hasAttachmentBlobs, pendingRuntimeState, }) {
1080
+ if (hasAttachmentBlobs) {
1123
1081
  assert(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1124
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
1125
- delete detachedContainerSnapshot.tree[hasBlobsSummaryTree];
1126
1082
  }
1127
- const snapshotTree = getSnapshotTreeFromSerializedContainer(detachedContainerSnapshot);
1128
- this.storageAdapter.loadSnapshotForRehydratingContainer(snapshotTree);
1129
- const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTree);
1083
+ const snapshotTreeWithBlobContents = combineSnapshotTreeAndSnapshotBlobs(baseSnapshot, snapshotBlobs);
1084
+ this.storageAdapter.loadSnapshotFromSnapshotBlobs(snapshotBlobs);
1085
+ const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshotTreeWithBlobContents);
1130
1086
  await this.attachDeltaManagerOpHandler(attributes);
1131
1087
  // Initialize the protocol handler
1132
- const baseTree = getProtocolSnapshotTree(snapshotTree);
1088
+ const baseTree = getProtocolSnapshotTree(snapshotTreeWithBlobContents);
1133
1089
  const qValues = await readAndParse(this.storageAdapter, baseTree.blobs.quorumValues);
1134
1090
  this.initializeProtocolState(attributes, {
1135
1091
  members: [],
@@ -1137,7 +1093,7 @@ export class Container extends EventEmitterWithErrorHandling {
1137
1093
  values: qValues,
1138
1094
  });
1139
1095
  const codeDetails = this.getCodeDetailsFromQuorum();
1140
- await this.instantiateRuntime(codeDetails, snapshotTree);
1096
+ await this.instantiateRuntime(codeDetails, snapshotTreeWithBlobContents, pendingRuntimeState);
1141
1097
  this.setLoaded();
1142
1098
  }
1143
1099
  async getDocumentAttributes(storage, tree) {
@@ -1237,10 +1193,9 @@ export class Container extends EventEmitterWithErrorHandling {
1237
1193
  const pkg = getCodeProposal(quorum);
1238
1194
  return pkg;
1239
1195
  }
1240
- static setupClient(containerId, options, clientDetailsOverride) {
1241
- const loaderOptionsClient = structuredClone(options?.client);
1196
+ static setupClient(containerId, loaderOptionsClient, clientDetailsOverride) {
1242
1197
  const client = loaderOptionsClient !== undefined
1243
- ? loaderOptionsClient
1198
+ ? structuredClone(loaderOptionsClient)
1244
1199
  : {
1245
1200
  details: {
1246
1201
  capabilities: { interactive: true },
@@ -1294,10 +1249,10 @@ export class Container extends EventEmitterWithErrorHandling {
1294
1249
  deltaManager.on("cancelEstablishingConnection", (reason) => {
1295
1250
  this.connectionStateHandler.cancelEstablishingConnection(reason);
1296
1251
  });
1297
- deltaManager.on("disconnect", (reason) => {
1252
+ deltaManager.on("disconnect", (text, error) => {
1298
1253
  this.noopHeuristic?.notifyDisconnect();
1299
1254
  if (!this.closed) {
1300
- this.connectionStateHandler.receivedDisconnectEvent(reason);
1255
+ this.connectionStateHandler.receivedDisconnectEvent({ text, error });
1301
1256
  }
1302
1257
  });
1303
1258
  deltaManager.on("throttled", (warning) => {
@@ -1442,14 +1397,12 @@ export class Container extends EventEmitterWithErrorHandling {
1442
1397
  return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
1443
1398
  }
1444
1399
  processRemoteMessage(message) {
1445
- if (this.offlineLoadEnabled) {
1446
- this.savedOps.push(message);
1447
- }
1448
1400
  const local = this.clientId === message.clientId;
1449
1401
  // Allow the protocol handler to process the message
1450
1402
  const result = this.protocolHandler.processMessage(message, local);
1451
1403
  // Forward messages to the loaded runtime for processing
1452
1404
  this.runtime.process(message, local);
1405
+ this.serializedStateManager.addProcessedOp(message);
1453
1406
  // Inactive (not in quorum or not writers) clients don't take part in the minimum sequence number calculation.
1454
1407
  if (this.activeConnection()) {
1455
1408
  if (this.noopHeuristic === undefined) {
@@ -1490,28 +1443,7 @@ export class Container extends EventEmitterWithErrorHandling {
1490
1443
  this.runtime.processSignal(message, local);
1491
1444
  }
1492
1445
  }
1493
- /**
1494
- * Get the most recent snapshot, or a specific version.
1495
- * @param specifiedVersion - The specific version of the snapshot to retrieve
1496
- * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
1497
- */
1498
- async fetchSnapshotTree(specifiedVersion) {
1499
- const version = await this.getVersion(specifiedVersion ?? null);
1500
- if (version === undefined && specifiedVersion !== undefined) {
1501
- // We should have a defined version to load from if specified version requested
1502
- this.mc.logger.sendErrorEvent({
1503
- eventName: "NoVersionFoundWhenSpecified",
1504
- id: specifiedVersion,
1505
- });
1506
- }
1507
- this._loadedFromVersion = version;
1508
- const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
1509
- if (snapshot === undefined && version !== undefined) {
1510
- this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
1511
- }
1512
- return { snapshot, versionId: version?.id };
1513
- }
1514
- async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
1446
+ async instantiateRuntime(codeDetails, snapshotTree, pendingLocalState, snapshot) {
1515
1447
  assert(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
1516
1448
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1517
1449
  // are set. Global requests will still go directly to the loader
@@ -1532,8 +1464,8 @@ export class Container extends EventEmitterWithErrorHandling {
1532
1464
  }
1533
1465
  const getSpecifiedCodeDetails = () => (this.protocolHandler.quorum.get("code") ??
1534
1466
  this.protocolHandler.quorum.get("code2"));
1535
- const existing = snapshot !== undefined;
1536
- const context = new 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);
1467
+ const existing = snapshotTree !== undefined;
1468
+ const context = new 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);
1537
1469
  this._runtime = await PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
1538
1470
  this._lifecycleEvents.emit("runtimeInstantiated");
1539
1471
  this._loadedCodeDetails = codeDetails;
@@ -1576,4 +1508,4 @@ export class Container extends EventEmitterWithErrorHandling {
1576
1508
  }
1577
1509
  }
1578
1510
  }
1579
- //# sourceMappingURL=container.mjs.map
1511
+ //# sourceMappingURL=container.js.map