@fluidframework/container-loader 2.0.0-dev-rc.2.0.0.246488 → 2.0.0-dev-rc.3.0.0.253463

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 (236) hide show
  1. package/api-report/container-loader.api.md +11 -11
  2. package/dist/attachment.d.ts +6 -9
  3. package/dist/attachment.d.ts.map +1 -1
  4. package/dist/attachment.js +3 -3
  5. package/dist/attachment.js.map +1 -1
  6. package/dist/audience.d.ts +1 -1
  7. package/dist/audience.d.ts.map +1 -1
  8. package/dist/audience.js +2 -2
  9. package/dist/audience.js.map +1 -1
  10. package/dist/catchUpMonitor.d.ts +1 -1
  11. package/dist/catchUpMonitor.d.ts.map +1 -1
  12. package/dist/catchUpMonitor.js +2 -2
  13. package/dist/catchUpMonitor.js.map +1 -1
  14. package/dist/connectionManager.d.ts +4 -4
  15. package/dist/connectionManager.d.ts.map +1 -1
  16. package/dist/connectionManager.js +42 -42
  17. package/dist/connectionManager.js.map +1 -1
  18. package/dist/connectionStateHandler.d.ts +3 -3
  19. package/dist/connectionStateHandler.d.ts.map +1 -1
  20. package/dist/connectionStateHandler.js +27 -27
  21. package/dist/connectionStateHandler.js.map +1 -1
  22. package/dist/container-loader-alpha.d.ts +11 -11
  23. package/dist/container-loader-beta.d.ts +11 -11
  24. package/dist/container-loader-public.d.ts +11 -11
  25. package/dist/container-loader-untrimmed.d.ts +11 -11
  26. package/dist/container.d.ts +9 -46
  27. package/dist/container.d.ts.map +1 -1
  28. package/dist/container.js +96 -108
  29. package/dist/container.js.map +1 -1
  30. package/dist/containerContext.d.ts +19 -7
  31. package/dist/containerContext.d.ts.map +1 -1
  32. package/dist/containerContext.js +7 -2
  33. package/dist/containerContext.js.map +1 -1
  34. package/dist/containerStorageAdapter.d.ts +3 -3
  35. package/dist/containerStorageAdapter.d.ts.map +1 -1
  36. package/dist/containerStorageAdapter.js +6 -6
  37. package/dist/containerStorageAdapter.js.map +1 -1
  38. package/dist/contracts.d.ts +4 -3
  39. package/dist/contracts.d.ts.map +1 -1
  40. package/dist/contracts.js +2 -2
  41. package/dist/contracts.js.map +1 -1
  42. package/dist/debugLogger.d.ts +2 -1
  43. package/dist/debugLogger.d.ts.map +1 -1
  44. package/dist/debugLogger.js +4 -4
  45. package/dist/debugLogger.js.map +1 -1
  46. package/dist/deltaManager.d.ts +7 -6
  47. package/dist/deltaManager.d.ts.map +1 -1
  48. package/dist/deltaManager.js +45 -45
  49. package/dist/deltaManager.js.map +1 -1
  50. package/dist/deltaQueue.d.ts +1 -1
  51. package/dist/deltaQueue.d.ts.map +1 -1
  52. package/dist/deltaQueue.js +5 -5
  53. package/dist/deltaQueue.js.map +1 -1
  54. package/dist/error.d.ts +3 -2
  55. package/dist/error.d.ts.map +1 -1
  56. package/dist/error.js +5 -5
  57. package/dist/error.js.map +1 -1
  58. package/dist/loader.d.ts +4 -4
  59. package/dist/loader.d.ts.map +1 -1
  60. package/dist/loader.js +23 -23
  61. package/dist/loader.js.map +1 -1
  62. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +2 -2
  63. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  64. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +2 -2
  65. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  66. package/dist/noopHeuristic.d.ts +1 -1
  67. package/dist/noopHeuristic.d.ts.map +1 -1
  68. package/dist/noopHeuristic.js +6 -6
  69. package/dist/noopHeuristic.js.map +1 -1
  70. package/dist/packageVersion.d.ts +1 -1
  71. package/dist/packageVersion.js +1 -1
  72. package/dist/packageVersion.js.map +1 -1
  73. package/dist/protocol.d.ts +1 -1
  74. package/dist/protocol.d.ts.map +1 -1
  75. package/dist/protocol.js +2 -2
  76. package/dist/protocol.js.map +1 -1
  77. package/dist/protocolTreeDocumentStorageService.d.ts +4 -4
  78. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  79. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  80. package/dist/quorum.d.ts +1 -1
  81. package/dist/quorum.d.ts.map +1 -1
  82. package/dist/quorum.js.map +1 -1
  83. package/dist/retriableDocumentStorageService.d.ts +2 -2
  84. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  85. package/dist/retriableDocumentStorageService.js +7 -7
  86. package/dist/retriableDocumentStorageService.js.map +1 -1
  87. package/dist/serializedStateManager.d.ts +87 -16
  88. package/dist/serializedStateManager.d.ts.map +1 -1
  89. package/dist/serializedStateManager.js +164 -80
  90. package/dist/serializedStateManager.js.map +1 -1
  91. package/dist/utils.d.ts +6 -7
  92. package/dist/utils.d.ts.map +1 -1
  93. package/dist/utils.js +39 -23
  94. package/dist/utils.js.map +1 -1
  95. package/lib/attachment.d.ts +6 -9
  96. package/lib/attachment.d.ts.map +1 -1
  97. package/lib/attachment.js +1 -1
  98. package/lib/attachment.js.map +1 -1
  99. package/lib/audience.d.ts +1 -1
  100. package/lib/audience.d.ts.map +1 -1
  101. package/lib/audience.js +1 -1
  102. package/lib/audience.js.map +1 -1
  103. package/lib/catchUpMonitor.d.ts +1 -1
  104. package/lib/catchUpMonitor.d.ts.map +1 -1
  105. package/lib/catchUpMonitor.js +1 -1
  106. package/lib/catchUpMonitor.js.map +1 -1
  107. package/lib/connectionManager.d.ts +4 -4
  108. package/lib/connectionManager.d.ts.map +1 -1
  109. package/lib/connectionManager.js +5 -5
  110. package/lib/connectionManager.js.map +1 -1
  111. package/lib/connectionStateHandler.d.ts +3 -3
  112. package/lib/connectionStateHandler.d.ts.map +1 -1
  113. package/lib/connectionStateHandler.js +2 -2
  114. package/lib/connectionStateHandler.js.map +1 -1
  115. package/lib/container-loader-alpha.d.ts +11 -11
  116. package/lib/container-loader-beta.d.ts +11 -11
  117. package/lib/container-loader-public.d.ts +11 -11
  118. package/lib/container-loader-untrimmed.d.ts +11 -11
  119. package/lib/container.d.ts +9 -46
  120. package/lib/container.d.ts.map +1 -1
  121. package/lib/container.js +28 -40
  122. package/lib/container.js.map +1 -1
  123. package/lib/containerContext.d.ts +19 -7
  124. package/lib/containerContext.d.ts.map +1 -1
  125. package/lib/containerContext.js +7 -2
  126. package/lib/containerContext.js.map +1 -1
  127. package/lib/containerStorageAdapter.d.ts +3 -3
  128. package/lib/containerStorageAdapter.d.ts.map +1 -1
  129. package/lib/containerStorageAdapter.js +2 -2
  130. package/lib/containerStorageAdapter.js.map +1 -1
  131. package/lib/contracts.d.ts +4 -3
  132. package/lib/contracts.d.ts.map +1 -1
  133. package/lib/contracts.js +1 -1
  134. package/lib/contracts.js.map +1 -1
  135. package/lib/debugLogger.d.ts +2 -1
  136. package/lib/debugLogger.d.ts.map +1 -1
  137. package/lib/debugLogger.js +1 -1
  138. package/lib/debugLogger.js.map +1 -1
  139. package/lib/deltaManager.d.ts +7 -6
  140. package/lib/deltaManager.d.ts.map +1 -1
  141. package/lib/deltaManager.js +5 -5
  142. package/lib/deltaManager.js.map +1 -1
  143. package/lib/deltaQueue.d.ts +1 -1
  144. package/lib/deltaQueue.d.ts.map +1 -1
  145. package/lib/deltaQueue.js +2 -2
  146. package/lib/deltaQueue.js.map +1 -1
  147. package/lib/error.d.ts +3 -2
  148. package/lib/error.d.ts.map +1 -1
  149. package/lib/error.js +2 -2
  150. package/lib/error.js.map +1 -1
  151. package/lib/loader.d.ts +4 -4
  152. package/lib/loader.d.ts.map +1 -1
  153. package/lib/loader.js +4 -4
  154. package/lib/loader.js.map +1 -1
  155. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts +2 -2
  156. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  157. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +2 -2
  158. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  159. package/lib/noopHeuristic.d.ts +1 -1
  160. package/lib/noopHeuristic.d.ts.map +1 -1
  161. package/lib/noopHeuristic.js +2 -2
  162. package/lib/noopHeuristic.js.map +1 -1
  163. package/lib/packageVersion.d.ts +1 -1
  164. package/lib/packageVersion.js +1 -1
  165. package/lib/packageVersion.js.map +1 -1
  166. package/lib/protocol.d.ts +1 -1
  167. package/lib/protocol.d.ts.map +1 -1
  168. package/lib/protocol.js +1 -1
  169. package/lib/protocol.js.map +1 -1
  170. package/lib/protocolTreeDocumentStorageService.d.ts +4 -4
  171. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  172. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  173. package/lib/quorum.d.ts +1 -1
  174. package/lib/quorum.d.ts.map +1 -1
  175. package/lib/quorum.js.map +1 -1
  176. package/lib/retriableDocumentStorageService.d.ts +2 -2
  177. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  178. package/lib/retriableDocumentStorageService.js +3 -3
  179. package/lib/retriableDocumentStorageService.js.map +1 -1
  180. package/lib/serializedStateManager.d.ts +87 -16
  181. package/lib/serializedStateManager.d.ts.map +1 -1
  182. package/lib/serializedStateManager.js +156 -75
  183. package/lib/serializedStateManager.js.map +1 -1
  184. package/lib/tsdoc-metadata.json +11 -0
  185. package/lib/utils.d.ts +6 -7
  186. package/lib/utils.d.ts.map +1 -1
  187. package/lib/utils.js +27 -12
  188. package/lib/utils.js.map +1 -1
  189. package/package.json +19 -28
  190. package/src/attachment.ts +9 -8
  191. package/src/audience.ts +2 -2
  192. package/src/catchUpMonitor.ts +2 -2
  193. package/src/connectionManager.ts +19 -19
  194. package/src/connectionStateHandler.ts +7 -7
  195. package/src/container.ts +78 -133
  196. package/src/containerContext.ts +22 -12
  197. package/src/containerStorageAdapter.ts +7 -6
  198. package/src/contracts.ts +4 -5
  199. package/src/debugLogger.ts +3 -4
  200. package/src/deltaManager.ts +31 -25
  201. package/src/deltaQueue.ts +2 -2
  202. package/src/error.ts +5 -4
  203. package/src/loader.ts +25 -23
  204. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +4 -4
  205. package/src/noopHeuristic.ts +3 -3
  206. package/src/packageVersion.ts +1 -1
  207. package/src/protocol.ts +2 -2
  208. package/src/protocolTreeDocumentStorageService.ts +4 -1
  209. package/src/quorum.ts +1 -1
  210. package/src/retriableDocumentStorageService.ts +6 -5
  211. package/src/serializedStateManager.ts +276 -110
  212. package/src/utils.ts +51 -20
  213. package/lib/test/attachment.spec.js +0 -380
  214. package/lib/test/attachment.spec.js.map +0 -1
  215. package/lib/test/catchUpMonitor.spec.js +0 -88
  216. package/lib/test/catchUpMonitor.spec.js.map +0 -1
  217. package/lib/test/connectionManager.spec.js +0 -201
  218. package/lib/test/connectionManager.spec.js.map +0 -1
  219. package/lib/test/connectionStateHandler.spec.js +0 -555
  220. package/lib/test/connectionStateHandler.spec.js.map +0 -1
  221. package/lib/test/container.spec.js +0 -64
  222. package/lib/test/container.spec.js.map +0 -1
  223. package/lib/test/deltaManager.spec.js +0 -405
  224. package/lib/test/deltaManager.spec.js.map +0 -1
  225. package/lib/test/loader.spec.js +0 -212
  226. package/lib/test/loader.spec.js.map +0 -1
  227. package/lib/test/locationRedirectionTests.spec.js +0 -44
  228. package/lib/test/locationRedirectionTests.spec.js.map +0 -1
  229. package/lib/test/serializedStateManager.spec.js +0 -148
  230. package/lib/test/serializedStateManager.spec.js.map +0 -1
  231. package/lib/test/snapshotConversionTest.spec.js +0 -79
  232. package/lib/test/snapshotConversionTest.spec.js.map +0 -1
  233. package/lib/test/types/validateContainerLoaderPrevious.generated.js +0 -38
  234. package/lib/test/types/validateContainerLoaderPrevious.generated.js.map +0 -1
  235. package/lib/test/utils.spec.js +0 -31
  236. package/lib/test/utils.spec.js.map +0 -1
@@ -5,9 +5,9 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.RetriableDocumentStorageService = void 0;
8
- const core_utils_1 = require("@fluidframework/core-utils");
9
- const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
10
- const driver_utils_1 = require("@fluidframework/driver-utils");
8
+ const internal_1 = require("@fluidframework/core-utils/internal");
9
+ const internal_2 = require("@fluidframework/driver-utils/internal");
10
+ const internal_3 = require("@fluidframework/telemetry-utils/internal");
11
11
  class RetriableDocumentStorageService {
12
12
  constructor(internalStorageServiceP, logger) {
13
13
  this.internalStorageServiceP = internalStorageServiceP;
@@ -35,7 +35,7 @@ class RetriableDocumentStorageService {
35
35
  if (s.getSnapshot !== undefined) {
36
36
  return s.getSnapshot(snapshotFetchOptions);
37
37
  }
38
- throw new telemetry_utils_1.UsageError("getSnapshot api should exist on internal storage in RetriableDocStorageService class");
38
+ throw new internal_3.UsageError("getSnapshot api should exist on internal storage in RetriableDocStorageService class");
39
39
  }), "storage_getSnapshot");
40
40
  }
41
41
  async readBlob(id) {
@@ -54,7 +54,7 @@ class RetriableDocumentStorageService {
54
54
  // upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take
55
55
  // retryAfter into account!
56
56
  // But retry loop is required for creation flow (Container.attach)
57
- (0, core_utils_1.assert)((context.referenceSequenceNumber === 0) === (context.ackHandle === undefined), 0x251 /* "creation summary has to have seq=0 && handle === undefined" */);
57
+ (0, internal_1.assert)((context.referenceSequenceNumber === 0) === (context.ackHandle === undefined), 0x251 /* "creation summary has to have seq=0 && handle === undefined" */);
58
58
  if (context.referenceSequenceNumber !== 0) {
59
59
  return this.internalStorageServiceP.then(async (s) => s.uploadSummaryWithContext(summary, context));
60
60
  }
@@ -74,14 +74,14 @@ class RetriableDocumentStorageService {
74
74
  fetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts
75
75
  }, error);
76
76
  // pre-0.58 error message: storageServiceDisposedCannotRetry
77
- throw new telemetry_utils_1.GenericError("Storage Service is disposed. Cannot retry", {
77
+ throw new internal_3.GenericError("Storage Service is disposed. Cannot retry", {
78
78
  canRetry: false,
79
79
  });
80
80
  }
81
81
  return;
82
82
  }
83
83
  async runWithRetry(api, callName) {
84
- return (0, driver_utils_1.runWithRetry)(api, callName, this.logger, {
84
+ return (0, internal_2.runWithRetry)(api, callName, this.logger, {
85
85
  onRetry: (_delayInMs, error) => this.checkStorageDisposed(callName, error),
86
86
  });
87
87
  }
@@ -1 +1 @@
1
- {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils\";\nimport {\n\tFetchSource,\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n\tISnapshot,\n\tISnapshotFetchOptions,\n\tISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n\tICreateBlobResponse,\n\tISnapshotTree,\n\tISummaryHandle,\n\tISummaryTree,\n\tIVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { GenericError, ITelemetryLoggerExt, UsageError } from \"@fluidframework/telemetry-utils\";\nimport { runWithRetry } from \"@fluidframework/driver-utils\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n\tprivate _disposed = false;\n\tprivate internalStorageService: IDocumentStorageService | undefined;\n\tconstructor(\n\t\tprivate readonly internalStorageServiceP: Promise<IDocumentStorageService>,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.internalStorageServiceP.then((s) => (this.internalStorageService = s)).catch(() => {});\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\tif (this.internalStorageService) {\n\t\t\treturn this.internalStorageService.policies;\n\t\t}\n\t\tthrow new Error(\"storage service not yet instantiated\");\n\t}\n\tpublic get disposed() {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose() {\n\t\tthis._disposed = true;\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t): Promise<ISnapshotTree | null> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getSnapshotTree(version, scenarioName),\n\t\t\t\t),\n\t\t\t\"storage_getSnapshotTree\",\n\t\t);\n\t}\n\n\tpublic async getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) => {\n\t\t\t\t\tif (s.getSnapshot !== undefined) {\n\t\t\t\t\t\treturn s.getSnapshot(snapshotFetchOptions);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"getSnapshot api should exist on internal storage in RetriableDocStorageService class\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t\"storage_getSnapshot\",\n\t\t);\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),\n\t\t\t\"storage_readBlob\",\n\t\t);\n\t}\n\n\tpublic async getVersions(\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getVersions(versionId, count, scenarioName, fetchSource),\n\t\t\t\t),\n\t\t\t\"storage_getVersions\",\n\t\t);\n\t}\n\n\tpublic async uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> {\n\t\t// Not using retry loop here. Couple reasons:\n\t\t// 1. If client lost connectivity, then retry loop will result in uploading stale summary\n\t\t// by stale summarizer after connectivity comes back. It will cause failures for this client and for\n\t\t// real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n\t\t// on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n\t\t// 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n\t\t// upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n\t\t// retryAfter into account!\n\t\t// But retry loop is required for creation flow (Container.attach)\n\t\tassert(\n\t\t\t(context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n\t\t\t0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */,\n\t\t);\n\t\tif (context.referenceSequenceNumber !== 0) {\n\t\t\treturn this.internalStorageServiceP.then(async (s) =>\n\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t);\n\t\t}\n\n\t\t// Creation flow with attachment blobs - need to do retries!\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t\t),\n\t\t\t\"storage_uploadSummaryWithContext\",\n\t\t);\n\t}\n\n\tpublic async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),\n\t\t\t\"storage_downloadSummary\",\n\t\t);\n\t}\n\n\tpublic async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),\n\t\t\t\"storage_createBlob\",\n\t\t);\n\t}\n\n\tprivate checkStorageDisposed(callName: string, error: unknown) {\n\t\tif (this._disposed) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: `${callName}_abortedStorageDisposed`,\n\t\t\t\t\tfetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\t// pre-0.58 error message: storageServiceDisposedCannotRetry\n\t\t\tthrow new GenericError(\"Storage Service is disposed. Cannot retry\", {\n\t\t\t\tcanRetry: false,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\tprivate async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n\t\treturn runWithRetry(api, callName, this.logger, {\n\t\t\tonRetry: (_delayInMs: number, error: unknown) =>\n\t\t\t\tthis.checkStorageDisposed(callName, error),\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFetchSource,\n\tIDocumentStorageService,\n\tIDocumentStorageServicePolicies,\n\tISnapshot,\n\tISnapshotFetchOptions,\n\tISummaryContext,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { runWithRetry } from \"@fluidframework/driver-utils/internal\";\nimport {\n\tICreateBlobResponse,\n\tISnapshotTree,\n\tISummaryHandle,\n\tISummaryTree,\n\tIVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\nimport { GenericError, UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n\tprivate _disposed = false;\n\tprivate internalStorageService: IDocumentStorageService | undefined;\n\tconstructor(\n\t\tprivate readonly internalStorageServiceP: Promise<IDocumentStorageService>,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t) {\n\t\tthis.internalStorageServiceP.then((s) => (this.internalStorageService = s)).catch(() => {});\n\t}\n\n\tpublic get policies(): IDocumentStorageServicePolicies | undefined {\n\t\tif (this.internalStorageService) {\n\t\t\treturn this.internalStorageService.policies;\n\t\t}\n\t\tthrow new Error(\"storage service not yet instantiated\");\n\t}\n\tpublic get disposed() {\n\t\treturn this._disposed;\n\t}\n\tpublic dispose() {\n\t\tthis._disposed = true;\n\t}\n\n\tpublic async getSnapshotTree(\n\t\tversion?: IVersion,\n\t\tscenarioName?: string,\n\t): Promise<ISnapshotTree | null> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getSnapshotTree(version, scenarioName),\n\t\t\t\t),\n\t\t\t\"storage_getSnapshotTree\",\n\t\t);\n\t}\n\n\tpublic async getSnapshot(snapshotFetchOptions?: ISnapshotFetchOptions): Promise<ISnapshot> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) => {\n\t\t\t\t\tif (s.getSnapshot !== undefined) {\n\t\t\t\t\t\treturn s.getSnapshot(snapshotFetchOptions);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"getSnapshot api should exist on internal storage in RetriableDocStorageService class\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t\"storage_getSnapshot\",\n\t\t);\n\t}\n\n\tpublic async readBlob(id: string): Promise<ArrayBufferLike> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),\n\t\t\t\"storage_readBlob\",\n\t\t);\n\t}\n\n\tpublic async getVersions(\n\t\tversionId: string | null,\n\t\tcount: number,\n\t\tscenarioName?: string,\n\t\tfetchSource?: FetchSource,\n\t): Promise<IVersion[]> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.getVersions(versionId, count, scenarioName, fetchSource),\n\t\t\t\t),\n\t\t\t\"storage_getVersions\",\n\t\t);\n\t}\n\n\tpublic async uploadSummaryWithContext(\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> {\n\t\t// Not using retry loop here. Couple reasons:\n\t\t// 1. If client lost connectivity, then retry loop will result in uploading stale summary\n\t\t// by stale summarizer after connectivity comes back. It will cause failures for this client and for\n\t\t// real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n\t\t// on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n\t\t// 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n\t\t// upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n\t\t// retryAfter into account!\n\t\t// But retry loop is required for creation flow (Container.attach)\n\t\tassert(\n\t\t\t(context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n\t\t\t0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */,\n\t\t);\n\t\tif (context.referenceSequenceNumber !== 0) {\n\t\t\treturn this.internalStorageServiceP.then(async (s) =>\n\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t);\n\t\t}\n\n\t\t// Creation flow with attachment blobs - need to do retries!\n\t\treturn this.runWithRetry(\n\t\t\tasync () =>\n\t\t\t\tthis.internalStorageServiceP.then(async (s) =>\n\t\t\t\t\ts.uploadSummaryWithContext(summary, context),\n\t\t\t\t),\n\t\t\t\"storage_uploadSummaryWithContext\",\n\t\t);\n\t}\n\n\tpublic async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),\n\t\t\t\"storage_downloadSummary\",\n\t\t);\n\t}\n\n\tpublic async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n\t\treturn this.runWithRetry(\n\t\t\tasync () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),\n\t\t\t\"storage_createBlob\",\n\t\t);\n\t}\n\n\tprivate checkStorageDisposed(callName: string, error: unknown) {\n\t\tif (this._disposed) {\n\t\t\tthis.logger.sendTelemetryEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: `${callName}_abortedStorageDisposed`,\n\t\t\t\t\tfetchCallName: callName, // fetchCallName matches logs in runWithRetry.ts\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t);\n\t\t\t// pre-0.58 error message: storageServiceDisposedCannotRetry\n\t\t\tthrow new GenericError(\"Storage Service is disposed. Cannot retry\", {\n\t\t\t\tcanRetry: false,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\n\tprivate async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n\t\treturn runWithRetry(api, callName, this.logger, {\n\t\t\tonRetry: (_delayInMs: number, error: unknown) =>\n\t\t\t\tthis.checkStorageDisposed(callName, error),\n\t\t});\n\t}\n}\n"]}
@@ -2,43 +2,114 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
+ import { IGetPendingLocalStateProps, IRuntime } from "@fluidframework/container-definitions/internal";
6
+ import { IDocumentStorageService, IResolvedUrl, ISnapshot } from "@fluidframework/driver-definitions/internal";
5
7
  import { ISequencedDocumentMessage, ISnapshotTree, IVersion } from "@fluidframework/protocol-definitions";
6
- import { IGetPendingLocalStateProps, IRuntime } from "@fluidframework/container-definitions";
7
8
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
8
- import { IDocumentStorageService, IResolvedUrl } from "@fluidframework/driver-definitions";
9
+ import { MonitoringContext } from "@fluidframework/telemetry-utils/internal";
9
10
  import { ISerializableBlobContents } from "./containerStorageAdapter.js";
10
- import { IPendingContainerState } from "./container.js";
11
+ export interface SnapshotWithBlobs {
12
+ /**
13
+ * Snapshot from which container initially loaded.
14
+ */
15
+ baseSnapshot: ISnapshotTree;
16
+ /**
17
+ * Serializable blobs from the base snapshot. Used to load offline since
18
+ * storage is not available.
19
+ */
20
+ snapshotBlobs: ISerializableBlobContents;
21
+ }
22
+ /**
23
+ * State saved by a container at close time, to be used to load a new instance
24
+ * of the container to the same state
25
+ * @internal
26
+ */
27
+ export interface IPendingContainerState extends SnapshotWithBlobs {
28
+ attached: true;
29
+ pendingRuntimeState: unknown;
30
+ /**
31
+ * All ops since base snapshot sequence number up to the latest op
32
+ * seen when the container was closed. Used to apply stashed (saved pending)
33
+ * ops at the same sequence number at which they were made.
34
+ */
35
+ savedOps: ISequencedDocumentMessage[];
36
+ url: string;
37
+ clientId?: string;
38
+ }
39
+ /**
40
+ * State saved by a container in detached state, to be used to load a new instance
41
+ * of the container to the same state (rehydrate)
42
+ * @internal
43
+ */
44
+ export interface IPendingDetachedContainerState extends SnapshotWithBlobs {
45
+ attached: false;
46
+ hasAttachmentBlobs: boolean;
47
+ pendingRuntimeState?: unknown;
48
+ }
49
+ interface SnapshotInfo extends SnapshotWithBlobs {
50
+ snapshotSequenceNumber: number;
51
+ }
11
52
  export declare class SerializedStateManager {
12
53
  private readonly pendingLocalState;
13
54
  private readonly storageAdapter;
14
55
  private readonly _offlineLoadEnabled;
56
+ private readonly newSnapshotFetched?;
15
57
  private readonly processedOps;
16
58
  private snapshot;
17
59
  private readonly mc;
18
- constructor(pendingLocalState: IPendingContainerState | undefined, subLogger: ITelemetryLoggerExt, storageAdapter: Pick<IDocumentStorageService, "readBlob" | "getSnapshotTree" | "getSnapshot" | "getVersions">, _offlineLoadEnabled: boolean);
60
+ private latestSnapshot;
61
+ private refreshSnapshot;
62
+ constructor(pendingLocalState: IPendingContainerState | undefined, subLogger: ITelemetryLoggerExt, storageAdapter: Pick<IDocumentStorageService, "readBlob" | "getSnapshotTree" | "getSnapshot" | "getVersions">, _offlineLoadEnabled: boolean, newSnapshotFetched?: (() => void) | undefined);
19
63
  get offlineLoadEnabled(): boolean;
20
64
  addProcessedOp(message: ISequencedDocumentMessage): void;
21
- private getVersion;
22
- fetchSnapshot(specifiedVersion: string | undefined, supportGetSnapshotApi: boolean | undefined): Promise<{
23
- snapshotTree: ISnapshotTree | undefined;
65
+ fetchSnapshot(specifiedVersion: string | undefined, supportGetSnapshotApi: boolean): Promise<{
66
+ baseSnapshot: ISnapshotTree;
24
67
  version: IVersion | undefined;
25
68
  }>;
26
- private fetchSnapshotCore;
27
69
  /**
28
- * Get the most recent snapshot, or a specific version.
29
- * @param specifiedVersion - The specific version of the snapshot to retrieve
30
- * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
70
+ * Updates class snapshot and processedOps if we have a new snapshot and it's among processedOps range.
31
71
  */
32
- private fetchSnapshotTree;
72
+ private updateSnapshotAndProcessedOpsMaybe;
33
73
  /**
34
74
  * This method is only meant to be used by Container.attach() to set the initial
35
75
  * base snapshot when attaching.
36
76
  * @param snapshot - snapshot and blobs collected while attaching
37
77
  */
38
- setSnapshot(snapshot: {
39
- tree: ISnapshotTree;
40
- blobs: ISerializableBlobContents;
41
- } | undefined): void;
78
+ setSnapshot(snapshot: SnapshotWithBlobs | undefined): void;
42
79
  getPendingLocalStateCore(props: IGetPendingLocalStateProps, clientId: string | undefined, runtime: Pick<IRuntime, "getPendingLocalState">, resolvedUrl: IResolvedUrl): Promise<string>;
43
80
  }
81
+ /**
82
+ * Retrieves the most recent snapshot and returns its info.
83
+ *
84
+ * @param mc - The monitoring context.
85
+ * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.
86
+ * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.
87
+ * @returns a SnapshotInfo object containing the snapshot tree, snapshot blobs and its sequence number.
88
+ */
89
+ export declare function getLatestSnapshotInfo(mc: MonitoringContext, storageAdapter: Pick<IDocumentStorageService, "getSnapshot" | "getSnapshotTree" | "getVersions" | "readBlob">, supportGetSnapshotApi: boolean): Promise<SnapshotInfo | undefined>;
90
+ /**
91
+ * Fetches an ISnapshot from a storage adapter based on the specified version.
92
+ *
93
+ * @param mc - The monitoring context.
94
+ * @param storageAdapter - The storage adapter providing a getSnapshot method to retrieve the ISnapshot and version.
95
+ * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.
96
+ * @returns - The fetched snapshot tree and its version.
97
+ */
98
+ export declare function fetchISnapshot(mc: MonitoringContext, storageAdapter: Pick<IDocumentStorageService, "getSnapshot">, specifiedVersion: string | undefined): Promise<{
99
+ snapshot?: ISnapshot;
100
+ version?: IVersion;
101
+ }>;
102
+ /**
103
+ * Fetches an ISnapshotTree from a storage adapter based on the specified version.
104
+ *
105
+ * @param mc - The monitoring context.
106
+ * @param storageAdapter - The storage adapter providing methods to retrieve the ISnapshotTree and version.
107
+ * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.
108
+ * @returns - The fetched snapshot tree and its version.
109
+ */
110
+ export declare function fetchISnapshotTree(mc: MonitoringContext, storageAdapter: Pick<IDocumentStorageService, "getSnapshotTree" | "getVersions">, specifiedVersion: string | undefined): Promise<{
111
+ snapshot?: ISnapshotTree;
112
+ version?: IVersion | undefined;
113
+ }>;
114
+ export {};
44
115
  //# sourceMappingURL=serializedStateManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serializedStateManager.d.ts","sourceRoot":"","sources":["../src/serializedStateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,yBAAyB,EACzB,aAAa,EACb,QAAQ,EACR,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AAC7F,OAAO,EACN,mBAAmB,EAKnB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACN,uBAAuB,EACvB,YAAY,EAEZ,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,yBAAyB,EAA2B,MAAM,8BAA8B,CAAC;AAClG,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAExD,qBAAa,sBAAsB;IAWjC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAI/B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAhBrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;IAChE,OAAO,CAAC,QAAQ,CAKH;IACb,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAGrB,iBAAiB,EAAE,sBAAsB,GAAG,SAAS,EACtE,SAAS,EAAE,mBAAmB,EACb,cAAc,EAAE,IAAI,CACpC,uBAAuB,EACvB,UAAU,GAAG,iBAAiB,GAAG,aAAa,GAAG,aAAa,CAC9D,EACgB,mBAAmB,EAAE,OAAO;IAQ9C,IAAW,kBAAkB,IAAI,OAAO,CAEvC;IAEM,cAAc,CAAC,OAAO,EAAE,yBAAyB;YAM1C,UAAU;IAKX,aAAa,CACzB,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,qBAAqB,EAAE,OAAO,GAAG,SAAS;;;;YAyB7B,iBAAiB;IAsC/B;;;;OAIG;YACW,iBAAiB;IAyB/B;;;;OAIG;IACI,WAAW,CACjB,QAAQ,EACL;QACA,IAAI,EAAE,aAAa,CAAC;QACpB,KAAK,EAAE,yBAAyB,CAAC;KAChC,GACD,SAAS;IAKA,wBAAwB,CACpC,KAAK,EAAE,0BAA0B,EACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,sBAAsB,CAAC,EAC/C,WAAW,EAAE,YAAY;CAiC1B"}
1
+ {"version":3,"file":"serializedStateManager.d.ts","sourceRoot":"","sources":["../src/serializedStateManager.ts"],"names":[],"mappings":"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"}
@@ -4,18 +4,20 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.SerializedStateManager = void 0;
8
- const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
9
- const core_utils_1 = require("@fluidframework/core-utils");
10
- const driver_utils_1 = require("@fluidframework/driver-utils");
7
+ exports.fetchISnapshotTree = exports.fetchISnapshot = exports.getLatestSnapshotInfo = exports.SerializedStateManager = void 0;
8
+ const internal_1 = require("@fluidframework/core-utils/internal");
9
+ const internal_2 = require("@fluidframework/driver-utils/internal");
10
+ const internal_3 = require("@fluidframework/telemetry-utils/internal");
11
11
  const containerStorageAdapter_js_1 = require("./containerStorageAdapter.js");
12
+ const utils_js_1 = require("./utils.js");
12
13
  class SerializedStateManager {
13
- constructor(pendingLocalState, subLogger, storageAdapter, _offlineLoadEnabled) {
14
+ constructor(pendingLocalState, subLogger, storageAdapter, _offlineLoadEnabled, newSnapshotFetched) {
14
15
  this.pendingLocalState = pendingLocalState;
15
16
  this.storageAdapter = storageAdapter;
16
17
  this._offlineLoadEnabled = _offlineLoadEnabled;
18
+ this.newSnapshotFetched = newSnapshotFetched;
17
19
  this.processedOps = [];
18
- this.mc = (0, telemetry_utils_1.createChildMonitoringContext)({
20
+ this.mc = (0, internal_3.createChildMonitoringContext)({
19
21
  logger: subLogger,
20
22
  namespace: "serializedStateManager",
21
23
  });
@@ -26,90 +28,73 @@ class SerializedStateManager {
26
28
  addProcessedOp(message) {
27
29
  if (this.offlineLoadEnabled) {
28
30
  this.processedOps.push(message);
31
+ this.updateSnapshotAndProcessedOpsMaybe();
29
32
  }
30
33
  }
31
- async getVersion(version) {
32
- const versions = await this.storageAdapter.getVersions(version, 1);
33
- return versions[0];
34
- }
35
34
  async fetchSnapshot(specifiedVersion, supportGetSnapshotApi) {
36
- const { snapshot, version } = this.pendingLocalState === undefined
37
- ? await this.fetchSnapshotCore(specifiedVersion, supportGetSnapshotApi)
38
- : { snapshot: this.pendingLocalState.baseSnapshot, version: undefined };
39
- const snapshotTree = (0, driver_utils_1.isInstanceOfISnapshot)(snapshot)
40
- ? snapshot.snapshotTree
41
- : snapshot;
42
- if (this.pendingLocalState) {
43
- this.snapshot = {
44
- tree: this.pendingLocalState.baseSnapshot,
45
- blobs: this.pendingLocalState.snapshotBlobs,
46
- };
47
- }
48
- else {
49
- (0, core_utils_1.assert)(snapshotTree !== undefined, 0x8e4 /* Snapshot should exist */);
35
+ if (this.pendingLocalState === undefined) {
36
+ const { baseSnapshot, version } = await getSnapshotTree(this.mc, this.storageAdapter, supportGetSnapshotApi, specifiedVersion);
50
37
  // non-interactive clients will not have any pending state we want to save
51
38
  if (this.offlineLoadEnabled) {
52
- const blobs = await (0, containerStorageAdapter_js_1.getBlobContentsFromTree)(snapshotTree, this.storageAdapter);
53
- this.snapshot = { tree: snapshotTree, blobs };
39
+ const snapshotBlobs = await (0, containerStorageAdapter_js_1.getBlobContentsFromTree)(baseSnapshot, this.storageAdapter);
40
+ this.snapshot = { baseSnapshot, snapshotBlobs };
54
41
  }
42
+ return { baseSnapshot, version };
55
43
  }
56
- return { snapshotTree, version };
57
- }
58
- async fetchSnapshotCore(specifiedVersion, supportGetSnapshotApi) {
59
- if (this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch") ===
60
- true &&
61
- supportGetSnapshotApi === true) {
62
- const snapshot = (await this.storageAdapter.getSnapshot?.({
63
- versionId: specifiedVersion,
64
- })) ?? undefined;
65
- const version = snapshot?.snapshotTree.id === undefined
66
- ? undefined
67
- : {
68
- id: snapshot.snapshotTree.id,
69
- treeId: snapshot.snapshotTree.id,
70
- };
71
- if (snapshot === undefined && specifiedVersion !== undefined) {
72
- this.mc.logger.sendErrorEvent({
73
- eventName: "getSnapshotTreeFailed",
74
- id: specifiedVersion,
75
- });
76
- // Not sure if this should be here actually
77
- }
78
- else if (snapshot !== undefined && version?.id === undefined) {
79
- this.mc.logger.sendErrorEvent({
80
- eventName: "getSnapshotFetchedTreeWithoutVersionId",
81
- hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
82
- });
83
- }
84
- return { snapshot, version };
44
+ else {
45
+ const { baseSnapshot, snapshotBlobs } = this.pendingLocalState;
46
+ this.snapshot = { baseSnapshot, snapshotBlobs };
47
+ this.refreshSnapshot ?? (this.refreshSnapshot = (async () => {
48
+ this.latestSnapshot = await getLatestSnapshotInfo(this.mc, this.storageAdapter, supportGetSnapshotApi);
49
+ this.newSnapshotFetched?.();
50
+ this.updateSnapshotAndProcessedOpsMaybe();
51
+ })());
52
+ return { baseSnapshot, version: undefined };
85
53
  }
86
- return this.fetchSnapshotTree(specifiedVersion);
87
54
  }
88
55
  /**
89
- * Get the most recent snapshot, or a specific version.
90
- * @param specifiedVersion - The specific version of the snapshot to retrieve
91
- * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
56
+ * Updates class snapshot and processedOps if we have a new snapshot and it's among processedOps range.
92
57
  */
93
- async fetchSnapshotTree(specifiedVersion) {
94
- const version = await this.getVersion(specifiedVersion ?? null);
95
- if (version === undefined && specifiedVersion !== undefined) {
96
- // We should have a defined version to load from if specified version requested
97
- this.mc.logger.sendErrorEvent({
98
- eventName: "NoVersionFoundWhenSpecified",
99
- id: specifiedVersion,
100
- });
58
+ updateSnapshotAndProcessedOpsMaybe() {
59
+ if (this.latestSnapshot === undefined) {
60
+ return;
101
61
  }
102
- const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
103
- if (snapshot === undefined && version !== undefined) {
104
- this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
62
+ const snapshotSequenceNumber = this.latestSnapshot?.snapshotSequenceNumber;
63
+ if (this.processedOps.length === 0) {
64
+ // can't refresh latest snapshot until we have processed the ops up to it.
65
+ // Pending state would be behind the latest snapshot.
66
+ return;
67
+ }
68
+ const firstProcessedOpSequenceNumber = this.processedOps[0].sequenceNumber;
69
+ const lastProcessedOpSequenceNumber = this.processedOps[this.processedOps.length - 1].sequenceNumber;
70
+ if (snapshotSequenceNumber < firstProcessedOpSequenceNumber) {
71
+ // Snapshot seq number is older than our first processed op, which could mean we're fetching
72
+ // the same snapshot that we already have or snapshot is too old, implicating an unexpected behavior.
73
+ this.mc.logger.sendTelemetryEvent({
74
+ category: snapshotSequenceNumber < firstProcessedOpSequenceNumber - 1
75
+ ? "error"
76
+ : "generic",
77
+ eventName: "OldSnapshotFetchWhileRefreshing",
78
+ snapshotSequenceNumber,
79
+ firstProcessedOpSequenceNumber,
80
+ });
81
+ this.latestSnapshot = undefined;
105
82
  }
106
- else if (snapshot !== undefined && version?.id === undefined) {
107
- this.mc.logger.sendErrorEvent({
108
- eventName: "getSnapshotFetchedTreeWithoutVersionId",
109
- hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
83
+ else if (snapshotSequenceNumber <= lastProcessedOpSequenceNumber) {
84
+ // Snapshot seq num is between the first and last processed op.
85
+ // Remove the ops that are already part of the snapshot
86
+ this.processedOps.splice(0, snapshotSequenceNumber - firstProcessedOpSequenceNumber + 1);
87
+ this.snapshot = this.latestSnapshot;
88
+ this.latestSnapshot = undefined;
89
+ this.mc.logger.sendTelemetryEvent({
90
+ eventName: "SnapshotRefreshed",
91
+ snapshotSequenceNumber,
92
+ firstProcessedOpSequenceNumber,
93
+ newFirstProcessedOpSequenceNumber: this.processedOps.length === 0
94
+ ? undefined
95
+ : this.processedOps[0].sequenceNumber,
110
96
  });
111
97
  }
112
- return { snapshot, version };
113
98
  }
114
99
  /**
115
100
  * This method is only meant to be used by Container.attach() to set the initial
@@ -120,22 +105,22 @@ class SerializedStateManager {
120
105
  this.snapshot = snapshot;
121
106
  }
122
107
  async getPendingLocalStateCore(props, clientId, runtime, resolvedUrl) {
123
- return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
108
+ return internal_3.PerformanceEvent.timedExecAsync(this.mc.logger, {
124
109
  eventName: "getPendingLocalState",
125
110
  notifyImminentClosure: props.notifyImminentClosure,
126
111
  processedOpsSize: this.processedOps.length,
127
112
  clientId,
128
113
  }, async () => {
129
114
  if (!this.offlineLoadEnabled) {
130
- throw new telemetry_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
115
+ throw new internal_3.UsageError("Can't get pending local state unless offline load is enabled");
131
116
  }
132
- (0, core_utils_1.assert)(this.snapshot !== undefined, 0x8e5 /* no base data */);
117
+ (0, internal_1.assert)(this.snapshot !== undefined, 0x8e5 /* no base data */);
133
118
  const pendingRuntimeState = await runtime.getPendingLocalState(props);
134
119
  const pendingState = {
135
120
  attached: true,
136
121
  pendingRuntimeState,
137
- baseSnapshot: this.snapshot.tree,
138
- snapshotBlobs: this.snapshot.blobs,
122
+ baseSnapshot: this.snapshot.baseSnapshot,
123
+ snapshotBlobs: this.snapshot.snapshotBlobs,
139
124
  savedOps: this.processedOps,
140
125
  url: resolvedUrl.url,
141
126
  // no need to save this if there is no pending runtime state
@@ -146,4 +131,103 @@ class SerializedStateManager {
146
131
  }
147
132
  }
148
133
  exports.SerializedStateManager = SerializedStateManager;
134
+ /**
135
+ * Retrieves the most recent snapshot and returns its info.
136
+ *
137
+ * @param mc - The monitoring context.
138
+ * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.
139
+ * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.
140
+ * @returns a SnapshotInfo object containing the snapshot tree, snapshot blobs and its sequence number.
141
+ */
142
+ async function getLatestSnapshotInfo(mc, storageAdapter, supportGetSnapshotApi) {
143
+ return internal_3.PerformanceEvent.timedExecAsync(mc.logger, { eventName: "GetLatestSnapshotInfo" }, async () => {
144
+ const { baseSnapshot } = await getSnapshotTree(mc, storageAdapter, supportGetSnapshotApi, undefined);
145
+ const snapshotBlobs = await (0, containerStorageAdapter_js_1.getBlobContentsFromTree)(baseSnapshot, storageAdapter);
146
+ const attributes = await (0, utils_js_1.getDocumentAttributes)(storageAdapter, baseSnapshot);
147
+ const snapshotSequenceNumber = attributes.sequenceNumber;
148
+ return { baseSnapshot, snapshotBlobs, snapshotSequenceNumber };
149
+ }).catch(() => undefined);
150
+ }
151
+ exports.getLatestSnapshotInfo = getLatestSnapshotInfo;
152
+ /**
153
+ * Retrieves a snapshot from the storage adapter and transforms it into an ISnapshotTree object.
154
+ *
155
+ * @param mc - The monitoring context.
156
+ * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.
157
+ * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.
158
+ * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.
159
+ * @returns - An ISnapshotTree and its version.
160
+ */
161
+ async function getSnapshotTree(mc, storageAdapter, supportGetSnapshotApi, specifiedVersion) {
162
+ const { snapshot, version } = supportGetSnapshotApi
163
+ ? await fetchISnapshot(mc, storageAdapter, specifiedVersion)
164
+ : await fetchISnapshotTree(mc, storageAdapter, specifiedVersion);
165
+ const baseSnapshot = (0, internal_2.isInstanceOfISnapshot)(snapshot)
166
+ ? snapshot.snapshotTree
167
+ : snapshot;
168
+ (0, internal_1.assert)(baseSnapshot !== undefined, 0x8e4 /* Snapshot should exist */);
169
+ return { baseSnapshot, version };
170
+ }
171
+ /**
172
+ * Fetches an ISnapshot from a storage adapter based on the specified version.
173
+ *
174
+ * @param mc - The monitoring context.
175
+ * @param storageAdapter - The storage adapter providing a getSnapshot method to retrieve the ISnapshot and version.
176
+ * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.
177
+ * @returns - The fetched snapshot tree and its version.
178
+ */
179
+ async function fetchISnapshot(mc, storageAdapter, specifiedVersion) {
180
+ const snapshot = await storageAdapter.getSnapshot?.({ versionId: specifiedVersion });
181
+ const version = snapshot?.snapshotTree.id === undefined
182
+ ? undefined
183
+ : {
184
+ id: snapshot.snapshotTree.id,
185
+ treeId: snapshot.snapshotTree.id,
186
+ };
187
+ if (snapshot === undefined && specifiedVersion !== undefined) {
188
+ mc.logger.sendErrorEvent({
189
+ eventName: "getSnapshotTreeFailed",
190
+ id: specifiedVersion,
191
+ });
192
+ }
193
+ else if (snapshot !== undefined && version?.id === undefined) {
194
+ mc.logger.sendErrorEvent({
195
+ eventName: "getSnapshotFetchedTreeWithoutVersionId",
196
+ hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
197
+ });
198
+ }
199
+ return { snapshot, version };
200
+ }
201
+ exports.fetchISnapshot = fetchISnapshot;
202
+ /**
203
+ * Fetches an ISnapshotTree from a storage adapter based on the specified version.
204
+ *
205
+ * @param mc - The monitoring context.
206
+ * @param storageAdapter - The storage adapter providing methods to retrieve the ISnapshotTree and version.
207
+ * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.
208
+ * @returns - The fetched snapshot tree and its version.
209
+ */
210
+ async function fetchISnapshotTree(mc, storageAdapter, specifiedVersion) {
211
+ const versions = await storageAdapter.getVersions(specifiedVersion ?? null, 1);
212
+ const version = versions[0];
213
+ if (version === undefined && specifiedVersion !== undefined) {
214
+ // We should have a defined version to load from if specified version requested
215
+ mc.logger.sendErrorEvent({
216
+ eventName: "NoVersionFoundWhenSpecified",
217
+ id: specifiedVersion,
218
+ });
219
+ }
220
+ const snapshot = (await storageAdapter.getSnapshotTree(version)) ?? undefined;
221
+ if (snapshot === undefined && version !== undefined) {
222
+ mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
223
+ }
224
+ else if (snapshot !== undefined && version?.id === undefined) {
225
+ mc.logger.sendErrorEvent({
226
+ eventName: "getSnapshotFetchedTreeWithoutVersionId",
227
+ hasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.
228
+ });
229
+ }
230
+ return { snapshot, version };
231
+ }
232
+ exports.fetchISnapshotTree = fetchISnapshotTree;
149
233
  //# sourceMappingURL=serializedStateManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serializedStateManager.js","sourceRoot":"","sources":["../src/serializedStateManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tISequencedDocumentMessage,\n\tISnapshotTree,\n\tIVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { IGetPendingLocalStateProps, IRuntime } from \"@fluidframework/container-definitions\";\nimport {\n\tITelemetryLoggerExt,\n\tMonitoringContext,\n\tPerformanceEvent,\n\tUsageError,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\nimport { assert } from \"@fluidframework/core-utils\";\nimport {\n\tIDocumentStorageService,\n\tIResolvedUrl,\n\tISnapshot,\n} from \"@fluidframework/driver-definitions\";\nimport { isInstanceOfISnapshot } from \"@fluidframework/driver-utils\";\nimport { ISerializableBlobContents, getBlobContentsFromTree } from \"./containerStorageAdapter.js\";\nimport { IPendingContainerState } from \"./container.js\";\n\nexport class SerializedStateManager {\n\tprivate readonly processedOps: ISequencedDocumentMessage[] = [];\n\tprivate snapshot:\n\t\t| {\n\t\t\t\ttree: ISnapshotTree;\n\t\t\t\tblobs: ISerializableBlobContents;\n\t\t }\n\t\t| undefined;\n\tprivate readonly mc: MonitoringContext;\n\n\tconstructor(\n\t\tprivate readonly pendingLocalState: IPendingContainerState | undefined,\n\t\tsubLogger: ITelemetryLoggerExt,\n\t\tprivate readonly storageAdapter: Pick<\n\t\t\tIDocumentStorageService,\n\t\t\t\"readBlob\" | \"getSnapshotTree\" | \"getSnapshot\" | \"getVersions\"\n\t\t>,\n\t\tprivate readonly _offlineLoadEnabled: boolean,\n\t) {\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: subLogger,\n\t\t\tnamespace: \"serializedStateManager\",\n\t\t});\n\t}\n\n\tpublic get offlineLoadEnabled(): boolean {\n\t\treturn this._offlineLoadEnabled;\n\t}\n\n\tpublic addProcessedOp(message: ISequencedDocumentMessage) {\n\t\tif (this.offlineLoadEnabled) {\n\t\t\tthis.processedOps.push(message);\n\t\t}\n\t}\n\n\tprivate async getVersion(version: string | null): Promise<IVersion | undefined> {\n\t\tconst versions = await this.storageAdapter.getVersions(version, 1);\n\t\treturn versions[0];\n\t}\n\n\tpublic async fetchSnapshot(\n\t\tspecifiedVersion: string | undefined,\n\t\tsupportGetSnapshotApi: boolean | undefined,\n\t) {\n\t\tconst { snapshot, version } =\n\t\t\tthis.pendingLocalState === undefined\n\t\t\t\t? await this.fetchSnapshotCore(specifiedVersion, supportGetSnapshotApi)\n\t\t\t\t: { snapshot: this.pendingLocalState.baseSnapshot, version: undefined };\n\t\tconst snapshotTree: ISnapshotTree | undefined = isInstanceOfISnapshot(snapshot)\n\t\t\t? snapshot.snapshotTree\n\t\t\t: snapshot;\n\t\tif (this.pendingLocalState) {\n\t\t\tthis.snapshot = {\n\t\t\t\ttree: this.pendingLocalState.baseSnapshot,\n\t\t\t\tblobs: this.pendingLocalState.snapshotBlobs,\n\t\t\t};\n\t\t} else {\n\t\t\tassert(snapshotTree !== undefined, 0x8e4 /* Snapshot should exist */);\n\t\t\t// non-interactive clients will not have any pending state we want to save\n\t\t\tif (this.offlineLoadEnabled) {\n\t\t\t\tconst blobs = await getBlobContentsFromTree(snapshotTree, this.storageAdapter);\n\t\t\t\tthis.snapshot = { tree: snapshotTree, blobs };\n\t\t\t}\n\t\t}\n\t\treturn { snapshotTree, version };\n\t}\n\n\tprivate async fetchSnapshotCore(\n\t\tspecifiedVersion: string | undefined,\n\t\tsupportGetSnapshotApi: boolean | undefined,\n\t): Promise<{ snapshot?: ISnapshot | ISnapshotTree; version?: IVersion }> {\n\t\tif (\n\t\t\tthis.mc.config.getBoolean(\"Fluid.Container.UseLoadingGroupIdForSnapshotFetch\") ===\n\t\t\t\ttrue &&\n\t\t\tsupportGetSnapshotApi === true\n\t\t) {\n\t\t\tconst snapshot =\n\t\t\t\t(await this.storageAdapter.getSnapshot?.({\n\t\t\t\t\tversionId: specifiedVersion,\n\t\t\t\t})) ?? undefined;\n\t\t\tconst version: IVersion | undefined =\n\t\t\t\tsnapshot?.snapshotTree.id === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tid: snapshot.snapshotTree.id,\n\t\t\t\t\t\t\ttreeId: snapshot.snapshotTree.id,\n\t\t\t\t\t };\n\n\t\t\tif (snapshot === undefined && specifiedVersion !== undefined) {\n\t\t\t\tthis.mc.logger.sendErrorEvent({\n\t\t\t\t\teventName: \"getSnapshotTreeFailed\",\n\t\t\t\t\tid: specifiedVersion,\n\t\t\t\t});\n\t\t\t\t// Not sure if this should be here actually\n\t\t\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\t\t\tthis.mc.logger.sendErrorEvent({\n\t\t\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { snapshot, version };\n\t\t}\n\t\treturn this.fetchSnapshotTree(specifiedVersion);\n\t}\n\n\t/**\n\t * Get the most recent snapshot, or a specific version.\n\t * @param specifiedVersion - The specific version of the snapshot to retrieve\n\t * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID\n\t */\n\tprivate async fetchSnapshotTree(\n\t\tspecifiedVersion: string | undefined,\n\t): Promise<{ snapshot?: ISnapshotTree; version?: IVersion | undefined }> {\n\t\tconst version = await this.getVersion(specifiedVersion ?? null);\n\n\t\tif (version === undefined && specifiedVersion !== undefined) {\n\t\t\t// We should have a defined version to load from if specified version requested\n\t\t\tthis.mc.logger.sendErrorEvent({\n\t\t\t\teventName: \"NoVersionFoundWhenSpecified\",\n\t\t\t\tid: specifiedVersion,\n\t\t\t});\n\t\t}\n\t\tconst snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;\n\n\t\tif (snapshot === undefined && version !== undefined) {\n\t\t\tthis.mc.logger.sendErrorEvent({ eventName: \"getSnapshotTreeFailed\", id: version.id });\n\t\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\t\tthis.mc.logger.sendErrorEvent({\n\t\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t\t});\n\t\t}\n\t\treturn { snapshot, version };\n\t}\n\n\t/**\n\t * This method is only meant to be used by Container.attach() to set the initial\n\t * base snapshot when attaching.\n\t * @param snapshot - snapshot and blobs collected while attaching\n\t */\n\tpublic setSnapshot(\n\t\tsnapshot:\n\t\t\t| {\n\t\t\t\t\ttree: ISnapshotTree;\n\t\t\t\t\tblobs: ISerializableBlobContents;\n\t\t\t }\n\t\t\t| undefined,\n\t) {\n\t\tthis.snapshot = snapshot;\n\t}\n\n\tpublic async getPendingLocalStateCore(\n\t\tprops: IGetPendingLocalStateProps,\n\t\tclientId: string | undefined,\n\t\truntime: Pick<IRuntime, \"getPendingLocalState\">,\n\t\tresolvedUrl: IResolvedUrl,\n\t) {\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tthis.mc.logger,\n\t\t\t{\n\t\t\t\teventName: \"getPendingLocalState\",\n\t\t\t\tnotifyImminentClosure: props.notifyImminentClosure,\n\t\t\t\tprocessedOpsSize: this.processedOps.length,\n\t\t\t\tclientId,\n\t\t\t},\n\t\t\tasync () => {\n\t\t\t\tif (!this.offlineLoadEnabled) {\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"Can't get pending local state unless offline load is enabled\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tassert(this.snapshot !== undefined, 0x8e5 /* no base data */);\n\t\t\t\tconst pendingRuntimeState = await runtime.getPendingLocalState(props);\n\t\t\t\tconst pendingState: IPendingContainerState = {\n\t\t\t\t\tattached: true,\n\t\t\t\t\tpendingRuntimeState,\n\t\t\t\t\tbaseSnapshot: this.snapshot.tree,\n\t\t\t\t\tsnapshotBlobs: this.snapshot.blobs,\n\t\t\t\t\tsavedOps: this.processedOps,\n\t\t\t\t\turl: resolvedUrl.url,\n\t\t\t\t\t// no need to save this if there is no pending runtime state\n\t\t\t\t\tclientId: pendingRuntimeState !== undefined ? clientId : undefined,\n\t\t\t\t};\n\n\t\t\t\treturn JSON.stringify(pendingState);\n\t\t\t},\n\t\t);\n\t}\n}\n"]}
1
+ {"version":3,"file":"serializedStateManager.js","sourceRoot":"","sources":["../src/serializedStateManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,kEAA6D;AAM7D,oEAA8E;AAQ9E,uEAKkD;AAElD,6EAAkG;AAClG,yCAAmD;AA8CnD,MAAa,sBAAsB;IAOlC,YACkB,iBAAqD,EACtE,SAA8B,EACb,cAGhB,EACgB,mBAA4B,EAC5B,kBAA+B;QAP/B,sBAAiB,GAAjB,iBAAiB,CAAoC;QAErD,mBAAc,GAAd,cAAc,CAG9B;QACgB,wBAAmB,GAAnB,mBAAmB,CAAS;QAC5B,uBAAkB,GAAlB,kBAAkB,CAAa;QAdhC,iBAAY,GAAgC,EAAE,CAAC;QAgB/D,IAAI,CAAC,EAAE,GAAG,IAAA,uCAA4B,EAAC;YACtC,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,wBAAwB;SACnC,CAAC,CAAC;IACJ,CAAC;IAED,IAAW,kBAAkB;QAC5B,OAAO,IAAI,CAAC,mBAAmB,CAAC;IACjC,CAAC;IAEM,cAAc,CAAC,OAAkC;QACvD,IAAI,IAAI,CAAC,kBAAkB,EAAE;YAC5B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChC,IAAI,CAAC,kCAAkC,EAAE,CAAC;SAC1C;IACF,CAAC;IAEM,KAAK,CAAC,aAAa,CACzB,gBAAoC,EACpC,qBAA8B;QAE9B,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,EAAE;YACzC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,MAAM,eAAe,CACtD,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,cAAc,EACnB,qBAAqB,EACrB,gBAAgB,CAChB,CAAC;YACF,0EAA0E;YAC1E,IAAI,IAAI,CAAC,kBAAkB,EAAE;gBAC5B,MAAM,aAAa,GAAG,MAAM,IAAA,oDAAuB,EAClD,YAAY,EACZ,IAAI,CAAC,cAAc,CACnB,CAAC;gBACF,IAAI,CAAC,QAAQ,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;aAChD;YACD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;SACjC;aAAM;YACN,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC;YAC/D,IAAI,CAAC,QAAQ,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;YAChD,IAAI,CAAC,eAAe,KAApB,IAAI,CAAC,eAAe,GAAK,CAAC,KAAK,IAAI,EAAE;gBACpC,IAAI,CAAC,cAAc,GAAG,MAAM,qBAAqB,CAChD,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,cAAc,EACnB,qBAAqB,CACrB,CAAC;gBACF,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;gBAC5B,IAAI,CAAC,kCAAkC,EAAE,CAAC;YAC3C,CAAC,CAAC,EAAE,EAAC;YAEL,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;SAC5C;IACF,CAAC;IAED;;OAEG;IACK,kCAAkC;QACzC,IAAI,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE;YACtC,OAAO;SACP;QACD,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,EAAE,sBAAsB,CAAC;QAC3E,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;YACnC,0EAA0E;YAC1E,qDAAqD;YACrD,OAAO;SACP;QACD,MAAM,8BAA8B,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;QAC3E,MAAM,6BAA6B,GAClC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QAEhE,IAAI,sBAAsB,GAAG,8BAA8B,EAAE;YAC5D,4FAA4F;YAC5F,qGAAqG;YACrG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBACjC,QAAQ,EACP,sBAAsB,GAAG,8BAA8B,GAAG,CAAC;oBAC1D,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,SAAS;gBACb,SAAS,EAAE,iCAAiC;gBAC5C,sBAAsB;gBACtB,8BAA8B;aAC9B,CAAC,CAAC;YACH,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;SAChC;aAAM,IAAI,sBAAsB,IAAI,6BAA6B,EAAE;YACnE,+DAA+D;YAC/D,uDAAuD;YACvD,IAAI,CAAC,YAAY,CAAC,MAAM,CACvB,CAAC,EACD,sBAAsB,GAAG,8BAA8B,GAAG,CAAC,CAC3D,CAAC;YACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;YACpC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;YAChC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC;gBACjC,SAAS,EAAE,mBAAmB;gBAC9B,sBAAsB;gBACtB,8BAA8B;gBAC9B,iCAAiC,EAChC,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;oBAC7B,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,cAAc;aACvC,CAAC,CAAC;SACH;IACF,CAAC;IAED;;;;OAIG;IACI,WAAW,CAAC,QAAuC;QACzD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAEM,KAAK,CAAC,wBAAwB,CACpC,KAAiC,EACjC,QAA4B,EAC5B,OAA+C,EAC/C,WAAyB;QAEzB,OAAO,2BAAgB,CAAC,cAAc,CACrC,IAAI,CAAC,EAAE,CAAC,MAAM,EACd;YACC,SAAS,EAAE,sBAAsB;YACjC,qBAAqB,EAAE,KAAK,CAAC,qBAAqB;YAClD,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM;YAC1C,QAAQ;SACR,EACD,KAAK,IAAI,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;gBAC7B,MAAM,IAAI,qBAAU,CACnB,8DAA8D,CAC9D,CAAC;aACF;YACD,IAAA,iBAAM,EAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAC9D,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACtE,MAAM,YAAY,GAA2B;gBAC5C,QAAQ,EAAE,IAAI;gBACd,mBAAmB;gBACnB,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY;gBACxC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa;gBAC1C,QAAQ,EAAE,IAAI,CAAC,YAAY;gBAC3B,GAAG,EAAE,WAAW,CAAC,GAAG;gBACpB,4DAA4D;gBAC5D,QAAQ,EAAE,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;aAClE,CAAC;YAEF,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACrC,CAAC,CACD,CAAC;IACH,CAAC;CACD;AAxKD,wDAwKC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,qBAAqB,CAC1C,EAAqB,EACrB,cAGC,EACD,qBAA8B;IAE9B,OAAO,2BAAgB,CAAC,cAAc,CACrC,EAAE,CAAC,MAAM,EACT,EAAE,SAAS,EAAE,uBAAuB,EAAE,EACtC,KAAK,IAAI,EAAE;QACV,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,eAAe,CAC7C,EAAE,EACF,cAAc,EACd,qBAAqB,EACrB,SAAS,CACT,CAAC;QACF,MAAM,aAAa,GAAG,MAAM,IAAA,oDAAuB,EAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QAClF,MAAM,UAAU,GAAwB,MAAM,IAAA,gCAAqB,EAClE,cAAc,EACd,YAAY,CACZ,CAAC;QACF,MAAM,sBAAsB,GAAG,UAAU,CAAC,cAAc,CAAC;QACzD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,CAAC;IAChE,CAAC,CACD,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AAC1B,CAAC;AA3BD,sDA2BC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,eAAe,CAC7B,EAAqB,EACrB,cAGC,EACD,qBAA8B,EAC9B,gBAAoC;IAEpC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,qBAAqB;QAClD,CAAC,CAAC,MAAM,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,gBAAgB,CAAC;QAC5D,CAAC,CAAC,MAAM,kBAAkB,CAAC,EAAE,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAClE,MAAM,YAAY,GAA8B,IAAA,gCAAqB,EAAC,QAAQ,CAAC;QAC9E,CAAC,CAAC,QAAQ,CAAC,YAAY;QACvB,CAAC,CAAC,QAAQ,CAAC;IACZ,IAAA,iBAAM,EAAC,YAAY,KAAK,SAAS,EAAE,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACtE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,cAAc,CACnC,EAAqB,EACrB,cAA4D,EAC5D,gBAAoC;IAEpC,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACrF,MAAM,OAAO,GACZ,QAAQ,EAAE,YAAY,CAAC,EAAE,KAAK,SAAS;QACtC,CAAC,CAAC,SAAS;QACX,CAAC,CAAC;YACA,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE;YAC5B,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE;SAC/B,CAAC;IAEN,IAAI,QAAQ,KAAK,SAAS,IAAI,gBAAgB,KAAK,SAAS,EAAE;QAC7D,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;YACxB,SAAS,EAAE,uBAAuB;YAClC,EAAE,EAAE,gBAAgB;SACpB,CAAC,CAAC;KACH;SAAM,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,EAAE,EAAE,KAAK,SAAS,EAAE;QAC/D,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;YACxB,SAAS,EAAE,wCAAwC;YACnD,UAAU,EAAE,OAAO,KAAK,SAAS,EAAE,mFAAmF;SACtH,CAAC,CAAC;KACH;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AA1BD,wCA0BC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,kBAAkB,CACvC,EAAqB,EACrB,cAAgF,EAChF,gBAAoC;IAEpC,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,gBAAgB,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IAC/E,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE5B,IAAI,OAAO,KAAK,SAAS,IAAI,gBAAgB,KAAK,SAAS,EAAE;QAC5D,+EAA+E;QAC/E,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;YACxB,SAAS,EAAE,6BAA6B;YACxC,EAAE,EAAE,gBAAgB;SACpB,CAAC,CAAC;KACH;IACD,MAAM,QAAQ,GAAG,CAAC,MAAM,cAAc,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,IAAI,SAAS,CAAC;IAE9E,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE;QACpD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,uBAAuB,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;KACjF;SAAM,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,EAAE,EAAE,KAAK,SAAS,EAAE;QAC/D,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;YACxB,SAAS,EAAE,wCAAwC;YACnD,UAAU,EAAE,OAAO,KAAK,SAAS,EAAE,mFAAmF;SACtH,CAAC,CAAC;KACH;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AA1BD,gDA0BC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIGetPendingLocalStateProps,\n\tIRuntime,\n} from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tIDocumentStorageService,\n\tIResolvedUrl,\n\tISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { isInstanceOfISnapshot } from \"@fluidframework/driver-utils/internal\";\nimport {\n\ttype IDocumentAttributes,\n\tISequencedDocumentMessage,\n\tISnapshotTree,\n\tIVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\nimport {\n\tMonitoringContext,\n\tPerformanceEvent,\n\tUsageError,\n\tcreateChildMonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { ISerializableBlobContents, getBlobContentsFromTree } from \"./containerStorageAdapter.js\";\nimport { getDocumentAttributes } from \"./utils.js\";\n\nexport interface SnapshotWithBlobs {\n\t/**\n\t * Snapshot from which container initially loaded.\n\t */\n\tbaseSnapshot: ISnapshotTree;\n\t/**\n\t * Serializable blobs from the base snapshot. Used to load offline since\n\t * storage is not available.\n\t */\n\tsnapshotBlobs: ISerializableBlobContents;\n}\n/**\n * State saved by a container at close time, to be used to load a new instance\n * of the container to the same state\n * @internal\n */\nexport interface IPendingContainerState extends SnapshotWithBlobs {\n\tattached: true;\n\tpendingRuntimeState: unknown;\n\t/**\n\t * All ops since base snapshot sequence number up to the latest op\n\t * seen when the container was closed. Used to apply stashed (saved pending)\n\t * ops at the same sequence number at which they were made.\n\t */\n\tsavedOps: ISequencedDocumentMessage[];\n\turl: string;\n\tclientId?: string;\n}\n\n/**\n * State saved by a container in detached state, to be used to load a new instance\n * of the container to the same state (rehydrate)\n * @internal\n */\nexport interface IPendingDetachedContainerState extends SnapshotWithBlobs {\n\tattached: false;\n\thasAttachmentBlobs: boolean;\n\tpendingRuntimeState?: unknown;\n}\n\ninterface SnapshotInfo extends SnapshotWithBlobs {\n\tsnapshotSequenceNumber: number;\n}\n\nexport class SerializedStateManager {\n\tprivate readonly processedOps: ISequencedDocumentMessage[] = [];\n\tprivate snapshot: SnapshotWithBlobs | undefined;\n\tprivate readonly mc: MonitoringContext;\n\tprivate latestSnapshot: SnapshotInfo | undefined;\n\tprivate refreshSnapshot: Promise<void> | undefined;\n\n\tconstructor(\n\t\tprivate readonly pendingLocalState: IPendingContainerState | undefined,\n\t\tsubLogger: ITelemetryLoggerExt,\n\t\tprivate readonly storageAdapter: Pick<\n\t\t\tIDocumentStorageService,\n\t\t\t\"readBlob\" | \"getSnapshotTree\" | \"getSnapshot\" | \"getVersions\"\n\t\t>,\n\t\tprivate readonly _offlineLoadEnabled: boolean,\n\t\tprivate readonly newSnapshotFetched?: () => void,\n\t) {\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: subLogger,\n\t\t\tnamespace: \"serializedStateManager\",\n\t\t});\n\t}\n\n\tpublic get offlineLoadEnabled(): boolean {\n\t\treturn this._offlineLoadEnabled;\n\t}\n\n\tpublic addProcessedOp(message: ISequencedDocumentMessage) {\n\t\tif (this.offlineLoadEnabled) {\n\t\t\tthis.processedOps.push(message);\n\t\t\tthis.updateSnapshotAndProcessedOpsMaybe();\n\t\t}\n\t}\n\n\tpublic async fetchSnapshot(\n\t\tspecifiedVersion: string | undefined,\n\t\tsupportGetSnapshotApi: boolean,\n\t) {\n\t\tif (this.pendingLocalState === undefined) {\n\t\t\tconst { baseSnapshot, version } = await getSnapshotTree(\n\t\t\t\tthis.mc,\n\t\t\t\tthis.storageAdapter,\n\t\t\t\tsupportGetSnapshotApi,\n\t\t\t\tspecifiedVersion,\n\t\t\t);\n\t\t\t// non-interactive clients will not have any pending state we want to save\n\t\t\tif (this.offlineLoadEnabled) {\n\t\t\t\tconst snapshotBlobs = await getBlobContentsFromTree(\n\t\t\t\t\tbaseSnapshot,\n\t\t\t\t\tthis.storageAdapter,\n\t\t\t\t);\n\t\t\t\tthis.snapshot = { baseSnapshot, snapshotBlobs };\n\t\t\t}\n\t\t\treturn { baseSnapshot, version };\n\t\t} else {\n\t\t\tconst { baseSnapshot, snapshotBlobs } = this.pendingLocalState;\n\t\t\tthis.snapshot = { baseSnapshot, snapshotBlobs };\n\t\t\tthis.refreshSnapshot ??= (async () => {\n\t\t\t\tthis.latestSnapshot = await getLatestSnapshotInfo(\n\t\t\t\t\tthis.mc,\n\t\t\t\t\tthis.storageAdapter,\n\t\t\t\t\tsupportGetSnapshotApi,\n\t\t\t\t);\n\t\t\t\tthis.newSnapshotFetched?.();\n\t\t\t\tthis.updateSnapshotAndProcessedOpsMaybe();\n\t\t\t})();\n\n\t\t\treturn { baseSnapshot, version: undefined };\n\t\t}\n\t}\n\n\t/**\n\t * Updates class snapshot and processedOps if we have a new snapshot and it's among processedOps range.\n\t */\n\tprivate updateSnapshotAndProcessedOpsMaybe() {\n\t\tif (this.latestSnapshot === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst snapshotSequenceNumber = this.latestSnapshot?.snapshotSequenceNumber;\n\t\tif (this.processedOps.length === 0) {\n\t\t\t// can't refresh latest snapshot until we have processed the ops up to it.\n\t\t\t// Pending state would be behind the latest snapshot.\n\t\t\treturn;\n\t\t}\n\t\tconst firstProcessedOpSequenceNumber = this.processedOps[0].sequenceNumber;\n\t\tconst lastProcessedOpSequenceNumber =\n\t\t\tthis.processedOps[this.processedOps.length - 1].sequenceNumber;\n\n\t\tif (snapshotSequenceNumber < firstProcessedOpSequenceNumber) {\n\t\t\t// Snapshot seq number is older than our first processed op, which could mean we're fetching\n\t\t\t// the same snapshot that we already have or snapshot is too old, implicating an unexpected behavior.\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\tcategory:\n\t\t\t\t\tsnapshotSequenceNumber < firstProcessedOpSequenceNumber - 1\n\t\t\t\t\t\t? \"error\"\n\t\t\t\t\t\t: \"generic\",\n\t\t\t\teventName: \"OldSnapshotFetchWhileRefreshing\",\n\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\tfirstProcessedOpSequenceNumber,\n\t\t\t});\n\t\t\tthis.latestSnapshot = undefined;\n\t\t} else if (snapshotSequenceNumber <= lastProcessedOpSequenceNumber) {\n\t\t\t// Snapshot seq num is between the first and last processed op.\n\t\t\t// Remove the ops that are already part of the snapshot\n\t\t\tthis.processedOps.splice(\n\t\t\t\t0,\n\t\t\t\tsnapshotSequenceNumber - firstProcessedOpSequenceNumber + 1,\n\t\t\t);\n\t\t\tthis.snapshot = this.latestSnapshot;\n\t\t\tthis.latestSnapshot = undefined;\n\t\t\tthis.mc.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"SnapshotRefreshed\",\n\t\t\t\tsnapshotSequenceNumber,\n\t\t\t\tfirstProcessedOpSequenceNumber,\n\t\t\t\tnewFirstProcessedOpSequenceNumber:\n\t\t\t\t\tthis.processedOps.length === 0\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: this.processedOps[0].sequenceNumber,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * This method is only meant to be used by Container.attach() to set the initial\n\t * base snapshot when attaching.\n\t * @param snapshot - snapshot and blobs collected while attaching\n\t */\n\tpublic setSnapshot(snapshot: SnapshotWithBlobs | undefined) {\n\t\tthis.snapshot = snapshot;\n\t}\n\n\tpublic async getPendingLocalStateCore(\n\t\tprops: IGetPendingLocalStateProps,\n\t\tclientId: string | undefined,\n\t\truntime: Pick<IRuntime, \"getPendingLocalState\">,\n\t\tresolvedUrl: IResolvedUrl,\n\t) {\n\t\treturn PerformanceEvent.timedExecAsync(\n\t\t\tthis.mc.logger,\n\t\t\t{\n\t\t\t\teventName: \"getPendingLocalState\",\n\t\t\t\tnotifyImminentClosure: props.notifyImminentClosure,\n\t\t\t\tprocessedOpsSize: this.processedOps.length,\n\t\t\t\tclientId,\n\t\t\t},\n\t\t\tasync () => {\n\t\t\t\tif (!this.offlineLoadEnabled) {\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"Can't get pending local state unless offline load is enabled\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tassert(this.snapshot !== undefined, 0x8e5 /* no base data */);\n\t\t\t\tconst pendingRuntimeState = await runtime.getPendingLocalState(props);\n\t\t\t\tconst pendingState: IPendingContainerState = {\n\t\t\t\t\tattached: true,\n\t\t\t\t\tpendingRuntimeState,\n\t\t\t\t\tbaseSnapshot: this.snapshot.baseSnapshot,\n\t\t\t\t\tsnapshotBlobs: this.snapshot.snapshotBlobs,\n\t\t\t\t\tsavedOps: this.processedOps,\n\t\t\t\t\turl: resolvedUrl.url,\n\t\t\t\t\t// no need to save this if there is no pending runtime state\n\t\t\t\t\tclientId: pendingRuntimeState !== undefined ? clientId : undefined,\n\t\t\t\t};\n\n\t\t\t\treturn JSON.stringify(pendingState);\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Retrieves the most recent snapshot and returns its info.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.\n * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.\n * @returns a SnapshotInfo object containing the snapshot tree, snapshot blobs and its sequence number.\n */\nexport async function getLatestSnapshotInfo(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<\n\t\tIDocumentStorageService,\n\t\t\"getSnapshot\" | \"getSnapshotTree\" | \"getVersions\" | \"readBlob\"\n\t>,\n\tsupportGetSnapshotApi: boolean,\n): Promise<SnapshotInfo | undefined> {\n\treturn PerformanceEvent.timedExecAsync(\n\t\tmc.logger,\n\t\t{ eventName: \"GetLatestSnapshotInfo\" },\n\t\tasync () => {\n\t\t\tconst { baseSnapshot } = await getSnapshotTree(\n\t\t\t\tmc,\n\t\t\t\tstorageAdapter,\n\t\t\t\tsupportGetSnapshotApi,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tconst snapshotBlobs = await getBlobContentsFromTree(baseSnapshot, storageAdapter);\n\t\t\tconst attributes: IDocumentAttributes = await getDocumentAttributes(\n\t\t\t\tstorageAdapter,\n\t\t\t\tbaseSnapshot,\n\t\t\t);\n\t\t\tconst snapshotSequenceNumber = attributes.sequenceNumber;\n\t\t\treturn { baseSnapshot, snapshotBlobs, snapshotSequenceNumber };\n\t\t},\n\t).catch(() => undefined);\n}\n\n/**\n * Retrieves a snapshot from the storage adapter and transforms it into an ISnapshotTree object.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the snapshot.\n * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns - An ISnapshotTree and its version.\n */\nasync function getSnapshotTree(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<\n\t\tIDocumentStorageService,\n\t\t\"getSnapshot\" | \"getSnapshotTree\" | \"getVersions\"\n\t>,\n\tsupportGetSnapshotApi: boolean,\n\tspecifiedVersion: string | undefined,\n): Promise<{ baseSnapshot: ISnapshotTree; version?: IVersion }> {\n\tconst { snapshot, version } = supportGetSnapshotApi\n\t\t? await fetchISnapshot(mc, storageAdapter, specifiedVersion)\n\t\t: await fetchISnapshotTree(mc, storageAdapter, specifiedVersion);\n\tconst baseSnapshot: ISnapshotTree | undefined = isInstanceOfISnapshot(snapshot)\n\t\t? snapshot.snapshotTree\n\t\t: snapshot;\n\tassert(baseSnapshot !== undefined, 0x8e4 /* Snapshot should exist */);\n\treturn { baseSnapshot, version };\n}\n\n/**\n * Fetches an ISnapshot from a storage adapter based on the specified version.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing a getSnapshot method to retrieve the ISnapshot and version.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns - The fetched snapshot tree and its version.\n */\nexport async function fetchISnapshot(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<IDocumentStorageService, \"getSnapshot\">,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot?: ISnapshot; version?: IVersion }> {\n\tconst snapshot = await storageAdapter.getSnapshot?.({ versionId: specifiedVersion });\n\tconst version: IVersion | undefined =\n\t\tsnapshot?.snapshotTree.id === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: snapshot.snapshotTree.id,\n\t\t\t\t\ttreeId: snapshot.snapshotTree.id,\n\t\t\t };\n\n\tif (snapshot === undefined && specifiedVersion !== undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotTreeFailed\",\n\t\t\tid: specifiedVersion,\n\t\t});\n\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t});\n\t}\n\treturn { snapshot, version };\n}\n\n/**\n * Fetches an ISnapshotTree from a storage adapter based on the specified version.\n *\n * @param mc - The monitoring context.\n * @param storageAdapter - The storage adapter providing methods to retrieve the ISnapshotTree and version.\n * @param specifiedVersion - An optional version string specifying the version of the snapshot tree to fetch.\n * @returns - The fetched snapshot tree and its version.\n */\nexport async function fetchISnapshotTree(\n\tmc: MonitoringContext,\n\tstorageAdapter: Pick<IDocumentStorageService, \"getSnapshotTree\" | \"getVersions\">,\n\tspecifiedVersion: string | undefined,\n): Promise<{ snapshot?: ISnapshotTree; version?: IVersion | undefined }> {\n\tconst versions = await storageAdapter.getVersions(specifiedVersion ?? null, 1);\n\tconst version = versions[0];\n\n\tif (version === undefined && specifiedVersion !== undefined) {\n\t\t// We should have a defined version to load from if specified version requested\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"NoVersionFoundWhenSpecified\",\n\t\t\tid: specifiedVersion,\n\t\t});\n\t}\n\tconst snapshot = (await storageAdapter.getSnapshotTree(version)) ?? undefined;\n\n\tif (snapshot === undefined && version !== undefined) {\n\t\tmc.logger.sendErrorEvent({ eventName: \"getSnapshotTreeFailed\", id: version.id });\n\t} else if (snapshot !== undefined && version?.id === undefined) {\n\t\tmc.logger.sendErrorEvent({\n\t\t\teventName: \"getSnapshotFetchedTreeWithoutVersionId\",\n\t\t\thasVersion: version !== undefined, // if hasVersion is true, this means that the contract with the service was broken.\n\t\t});\n\t}\n\treturn { snapshot, version };\n}\n"]}