@fluidframework/container-loader 1.4.0-115997 → 2.0.0-dev-rc.1.0.0.224419

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 (333) hide show
  1. package/.eslintrc.js +18 -21
  2. package/.mocharc.js +12 -0
  3. package/CHANGELOG.md +364 -0
  4. package/README.md +152 -56
  5. package/api-extractor-lint.json +4 -0
  6. package/api-extractor.json +2 -2
  7. package/api-report/container-loader.api.md +143 -0
  8. package/dist/{audience.js → audience.cjs} +15 -13
  9. package/dist/audience.cjs.map +1 -0
  10. package/dist/audience.d.ts +3 -6
  11. package/dist/audience.d.ts.map +1 -1
  12. package/dist/catchUpMonitor.cjs +43 -0
  13. package/dist/catchUpMonitor.cjs.map +1 -0
  14. package/dist/catchUpMonitor.d.ts +29 -0
  15. package/dist/catchUpMonitor.d.ts.map +1 -0
  16. package/dist/{connectionManager.js → connectionManager.cjs} +397 -240
  17. package/dist/connectionManager.cjs.map +1 -0
  18. package/dist/connectionManager.d.ts +23 -33
  19. package/dist/connectionManager.d.ts.map +1 -1
  20. package/dist/{connectionState.js → connectionState.cjs} +5 -7
  21. package/dist/connectionState.cjs.map +1 -0
  22. package/dist/connectionState.d.ts +3 -5
  23. package/dist/connectionState.d.ts.map +1 -1
  24. package/dist/connectionStateHandler.cjs +474 -0
  25. package/dist/connectionStateHandler.cjs.map +1 -0
  26. package/dist/connectionStateHandler.d.ts +127 -29
  27. package/dist/connectionStateHandler.d.ts.map +1 -1
  28. package/dist/container-loader-alpha.d.ts +274 -0
  29. package/dist/container-loader-beta.d.ts +75 -0
  30. package/dist/container-loader-public.d.ts +75 -0
  31. package/dist/container-loader-untrimmed.d.ts +331 -0
  32. package/dist/container.cjs +1585 -0
  33. package/dist/container.cjs.map +1 -0
  34. package/dist/container.d.ts +227 -83
  35. package/dist/container.d.ts.map +1 -1
  36. package/dist/containerContext.cjs +74 -0
  37. package/dist/containerContext.cjs.map +1 -0
  38. package/dist/containerContext.d.ts +33 -59
  39. package/dist/containerContext.d.ts.map +1 -1
  40. package/dist/containerStorageAdapter.cjs +234 -0
  41. package/dist/containerStorageAdapter.cjs.map +1 -0
  42. package/dist/containerStorageAdapter.d.ts +48 -23
  43. package/dist/containerStorageAdapter.d.ts.map +1 -1
  44. package/dist/{contracts.js → contracts.cjs} +5 -5
  45. package/dist/contracts.cjs.map +1 -0
  46. package/dist/contracts.d.ts +45 -17
  47. package/dist/contracts.d.ts.map +1 -1
  48. package/dist/debugLogger.cjs +101 -0
  49. package/dist/debugLogger.cjs.map +1 -0
  50. package/dist/debugLogger.d.ts +30 -0
  51. package/dist/debugLogger.d.ts.map +1 -0
  52. package/dist/{deltaManager.js → deltaManager.cjs} +379 -186
  53. package/dist/deltaManager.cjs.map +1 -0
  54. package/dist/deltaManager.d.ts +54 -18
  55. package/dist/deltaManager.d.ts.map +1 -1
  56. package/dist/{deltaQueue.js → deltaQueue.cjs} +29 -28
  57. package/dist/deltaQueue.cjs.map +1 -0
  58. package/dist/deltaQueue.d.ts +3 -4
  59. package/dist/deltaQueue.d.ts.map +1 -1
  60. package/dist/disposal.cjs +25 -0
  61. package/dist/disposal.cjs.map +1 -0
  62. package/dist/disposal.d.ts +13 -0
  63. package/dist/disposal.d.ts.map +1 -0
  64. package/dist/error.cjs +32 -0
  65. package/dist/error.cjs.map +1 -0
  66. package/dist/error.d.ts +23 -0
  67. package/dist/error.d.ts.map +1 -0
  68. package/dist/index.cjs +19 -0
  69. package/dist/index.cjs.map +1 -0
  70. package/dist/index.d.ts +5 -2
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/loader.cjs +148 -0
  73. package/dist/loader.cjs.map +1 -0
  74. package/dist/loader.d.ts +38 -19
  75. package/dist/loader.d.ts.map +1 -1
  76. package/dist/location-redirection-utilities/index.cjs +11 -0
  77. package/dist/location-redirection-utilities/index.cjs.map +1 -0
  78. package/dist/location-redirection-utilities/index.d.ts +6 -0
  79. package/dist/location-redirection-utilities/index.d.ts.map +1 -0
  80. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs +53 -0
  81. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs.map +1 -0
  82. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +24 -0
  83. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
  84. package/dist/{collabWindowTracker.js → noopHeuristic.cjs} +37 -39
  85. package/dist/noopHeuristic.cjs.map +1 -0
  86. package/dist/noopHeuristic.d.ts +23 -0
  87. package/dist/noopHeuristic.d.ts.map +1 -0
  88. package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
  89. package/dist/packageVersion.cjs.map +1 -0
  90. package/dist/packageVersion.d.ts +1 -1
  91. package/dist/packageVersion.d.ts.map +1 -1
  92. package/dist/protocol.cjs +99 -0
  93. package/dist/protocol.cjs.map +1 -0
  94. package/dist/protocol.d.ts +38 -0
  95. package/dist/protocol.d.ts.map +1 -0
  96. package/dist/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.cjs} +8 -5
  97. package/dist/protocolTreeDocumentStorageService.cjs.map +1 -0
  98. package/dist/protocolTreeDocumentStorageService.d.ts +8 -4
  99. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  100. package/dist/quorum.cjs +16 -0
  101. package/dist/quorum.cjs.map +1 -0
  102. package/dist/quorum.d.ts +1 -14
  103. package/dist/quorum.d.ts.map +1 -1
  104. package/dist/{retriableDocumentStorageService.js → retriableDocumentStorageService.cjs} +36 -21
  105. package/dist/retriableDocumentStorageService.cjs.map +1 -0
  106. package/dist/retriableDocumentStorageService.d.ts +7 -5
  107. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  108. package/dist/tsdoc-metadata.json +11 -0
  109. package/dist/{utils.js → utils.cjs} +52 -14
  110. package/dist/utils.cjs.map +1 -0
  111. package/dist/utils.d.ts +34 -1
  112. package/dist/utils.d.ts.map +1 -1
  113. package/lib/{audience.d.ts → audience.d.mts} +3 -10
  114. package/lib/audience.d.mts.map +1 -0
  115. package/lib/{audience.js → audience.mjs} +15 -17
  116. package/lib/audience.mjs.map +1 -0
  117. package/lib/catchUpMonitor.d.mts +29 -0
  118. package/lib/catchUpMonitor.d.mts.map +1 -0
  119. package/lib/catchUpMonitor.mjs +39 -0
  120. package/lib/catchUpMonitor.mjs.map +1 -0
  121. package/lib/{connectionManager.d.ts → connectionManager.d.mts} +23 -33
  122. package/lib/connectionManager.d.mts.map +1 -0
  123. package/lib/{connectionManager.js → connectionManager.mjs} +378 -218
  124. package/lib/connectionManager.mjs.map +1 -0
  125. package/lib/{connectionState.d.ts → connectionState.d.mts} +3 -5
  126. package/lib/connectionState.d.mts.map +1 -0
  127. package/lib/{connectionState.js → connectionState.mjs} +4 -6
  128. package/lib/connectionState.mjs.map +1 -0
  129. package/lib/connectionStateHandler.d.mts +179 -0
  130. package/lib/connectionStateHandler.d.mts.map +1 -0
  131. package/lib/connectionStateHandler.mjs +469 -0
  132. package/lib/connectionStateHandler.mjs.map +1 -0
  133. package/lib/container-loader-alpha.d.mts +274 -0
  134. package/lib/container-loader-beta.d.mts +75 -0
  135. package/lib/container-loader-public.d.mts +75 -0
  136. package/lib/container-loader-untrimmed.d.mts +331 -0
  137. package/lib/container.d.mts +382 -0
  138. package/lib/container.d.mts.map +1 -0
  139. package/lib/container.mjs +1579 -0
  140. package/lib/container.mjs.map +1 -0
  141. package/lib/containerContext.d.mts +58 -0
  142. package/lib/containerContext.d.mts.map +1 -0
  143. package/lib/containerContext.mjs +70 -0
  144. package/lib/containerContext.mjs.map +1 -0
  145. package/lib/containerStorageAdapter.d.mts +73 -0
  146. package/lib/containerStorageAdapter.d.mts.map +1 -0
  147. package/lib/containerStorageAdapter.mjs +228 -0
  148. package/lib/containerStorageAdapter.mjs.map +1 -0
  149. package/lib/{contracts.d.ts → contracts.d.mts} +45 -17
  150. package/lib/contracts.d.mts.map +1 -0
  151. package/lib/{contracts.js → contracts.mjs} +4 -4
  152. package/lib/contracts.mjs.map +1 -0
  153. package/lib/debugLogger.d.mts +30 -0
  154. package/lib/debugLogger.d.mts.map +1 -0
  155. package/lib/debugLogger.mjs +93 -0
  156. package/lib/debugLogger.mjs.map +1 -0
  157. package/lib/{deltaManager.d.ts → deltaManager.d.mts} +54 -18
  158. package/lib/deltaManager.d.mts.map +1 -0
  159. package/lib/{deltaManager.js → deltaManager.mjs} +361 -165
  160. package/lib/deltaManager.mjs.map +1 -0
  161. package/lib/{deltaQueue.d.ts → deltaQueue.d.mts} +3 -4
  162. package/lib/deltaQueue.d.mts.map +1 -0
  163. package/lib/{deltaQueue.js → deltaQueue.mjs} +25 -24
  164. package/lib/deltaQueue.mjs.map +1 -0
  165. package/lib/disposal.d.mts +13 -0
  166. package/lib/disposal.d.mts.map +1 -0
  167. package/lib/disposal.mjs +21 -0
  168. package/lib/disposal.mjs.map +1 -0
  169. package/lib/error.d.mts +23 -0
  170. package/lib/error.d.mts.map +1 -0
  171. package/lib/error.mjs +28 -0
  172. package/lib/error.mjs.map +1 -0
  173. package/lib/index.d.mts +11 -0
  174. package/lib/index.d.mts.map +1 -0
  175. package/lib/index.mjs +10 -0
  176. package/lib/index.mjs.map +1 -0
  177. package/lib/{loader.d.ts → loader.d.mts} +39 -20
  178. package/lib/loader.d.mts.map +1 -0
  179. package/lib/loader.mjs +143 -0
  180. package/lib/loader.mjs.map +1 -0
  181. package/lib/location-redirection-utilities/index.d.mts +6 -0
  182. package/lib/location-redirection-utilities/index.d.mts.map +1 -0
  183. package/lib/location-redirection-utilities/index.mjs +6 -0
  184. package/lib/location-redirection-utilities/index.mjs.map +1 -0
  185. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts +24 -0
  186. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +1 -0
  187. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs +48 -0
  188. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +1 -0
  189. package/lib/noopHeuristic.d.mts +23 -0
  190. package/lib/noopHeuristic.d.mts.map +1 -0
  191. package/lib/{collabWindowTracker.js → noopHeuristic.mjs} +33 -35
  192. package/lib/noopHeuristic.mjs.map +1 -0
  193. package/lib/{packageVersion.d.ts → packageVersion.d.mts} +1 -1
  194. package/lib/{packageVersion.d.ts.map → packageVersion.d.mts.map} +1 -1
  195. package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
  196. package/lib/packageVersion.mjs.map +1 -0
  197. package/lib/protocol.d.mts +38 -0
  198. package/lib/protocol.d.mts.map +1 -0
  199. package/lib/protocol.mjs +94 -0
  200. package/lib/protocol.mjs.map +1 -0
  201. package/lib/{protocolTreeDocumentStorageService.d.ts → protocolTreeDocumentStorageService.d.mts} +8 -4
  202. package/lib/protocolTreeDocumentStorageService.d.mts.map +1 -0
  203. package/lib/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.mjs} +8 -5
  204. package/lib/protocolTreeDocumentStorageService.mjs.map +1 -0
  205. package/lib/quorum.d.mts +4 -0
  206. package/lib/quorum.d.mts.map +1 -0
  207. package/lib/quorum.mjs +12 -0
  208. package/lib/quorum.mjs.map +1 -0
  209. package/lib/{retriableDocumentStorageService.d.ts → retriableDocumentStorageService.d.mts} +7 -5
  210. package/lib/retriableDocumentStorageService.d.mts.map +1 -0
  211. package/lib/{retriableDocumentStorageService.js → retriableDocumentStorageService.mjs} +35 -20
  212. package/lib/retriableDocumentStorageService.mjs.map +1 -0
  213. package/lib/utils.d.mts +67 -0
  214. package/lib/utils.d.mts.map +1 -0
  215. package/lib/{utils.js → utils.mjs} +47 -11
  216. package/lib/utils.mjs.map +1 -0
  217. package/package.json +163 -70
  218. package/prettier.config.cjs +8 -0
  219. package/src/audience.ts +59 -49
  220. package/src/catchUpMonitor.ts +61 -0
  221. package/src/connectionManager.ts +1154 -910
  222. package/src/connectionState.ts +22 -25
  223. package/src/connectionStateHandler.ts +689 -319
  224. package/src/container.ts +2476 -1792
  225. package/src/containerContext.ts +98 -330
  226. package/src/containerStorageAdapter.ts +301 -105
  227. package/src/contracts.ts +184 -146
  228. package/src/debugLogger.ts +123 -0
  229. package/src/deltaManager.ts +1165 -900
  230. package/src/deltaQueue.ts +156 -152
  231. package/src/disposal.ts +25 -0
  232. package/src/error.ts +44 -0
  233. package/src/index.ts +14 -15
  234. package/src/loader.ts +356 -427
  235. package/src/location-redirection-utilities/index.ts +9 -0
  236. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +61 -0
  237. package/src/noopHeuristic.ts +107 -0
  238. package/src/packageVersion.ts +1 -1
  239. package/src/protocol.ts +150 -0
  240. package/src/protocolTreeDocumentStorageService.ts +35 -35
  241. package/src/quorum.ts +11 -50
  242. package/src/retriableDocumentStorageService.ts +135 -95
  243. package/src/utils.ts +159 -86
  244. package/tsc-multi.test.json +4 -0
  245. package/tsconfig.json +10 -12
  246. package/dist/audience.js.map +0 -1
  247. package/dist/collabWindowTracker.d.ts +0 -19
  248. package/dist/collabWindowTracker.d.ts.map +0 -1
  249. package/dist/collabWindowTracker.js.map +0 -1
  250. package/dist/connectionManager.js.map +0 -1
  251. package/dist/connectionState.js.map +0 -1
  252. package/dist/connectionStateHandler.js +0 -280
  253. package/dist/connectionStateHandler.js.map +0 -1
  254. package/dist/container.js +0 -1284
  255. package/dist/container.js.map +0 -1
  256. package/dist/containerContext.js +0 -217
  257. package/dist/containerContext.js.map +0 -1
  258. package/dist/containerStorageAdapter.js +0 -104
  259. package/dist/containerStorageAdapter.js.map +0 -1
  260. package/dist/contracts.js.map +0 -1
  261. package/dist/deltaManager.js.map +0 -1
  262. package/dist/deltaManagerProxy.d.ts +0 -54
  263. package/dist/deltaManagerProxy.d.ts.map +0 -1
  264. package/dist/deltaManagerProxy.js +0 -115
  265. package/dist/deltaManagerProxy.js.map +0 -1
  266. package/dist/deltaQueue.js.map +0 -1
  267. package/dist/index.js +0 -16
  268. package/dist/index.js.map +0 -1
  269. package/dist/loader.js +0 -241
  270. package/dist/loader.js.map +0 -1
  271. package/dist/packageVersion.js.map +0 -1
  272. package/dist/protocolTreeDocumentStorageService.js.map +0 -1
  273. package/dist/quorum.js +0 -44
  274. package/dist/quorum.js.map +0 -1
  275. package/dist/retriableDocumentStorageService.js.map +0 -1
  276. package/dist/utils.js.map +0 -1
  277. package/lib/audience.d.ts.map +0 -1
  278. package/lib/audience.js.map +0 -1
  279. package/lib/collabWindowTracker.d.ts +0 -19
  280. package/lib/collabWindowTracker.d.ts.map +0 -1
  281. package/lib/collabWindowTracker.js.map +0 -1
  282. package/lib/connectionManager.d.ts.map +0 -1
  283. package/lib/connectionManager.js.map +0 -1
  284. package/lib/connectionState.d.ts.map +0 -1
  285. package/lib/connectionState.js.map +0 -1
  286. package/lib/connectionStateHandler.d.ts +0 -81
  287. package/lib/connectionStateHandler.d.ts.map +0 -1
  288. package/lib/connectionStateHandler.js +0 -276
  289. package/lib/connectionStateHandler.js.map +0 -1
  290. package/lib/container.d.ts +0 -238
  291. package/lib/container.d.ts.map +0 -1
  292. package/lib/container.js +0 -1276
  293. package/lib/container.js.map +0 -1
  294. package/lib/containerContext.d.ts +0 -84
  295. package/lib/containerContext.d.ts.map +0 -1
  296. package/lib/containerContext.js +0 -213
  297. package/lib/containerContext.js.map +0 -1
  298. package/lib/containerStorageAdapter.d.ts +0 -48
  299. package/lib/containerStorageAdapter.d.ts.map +0 -1
  300. package/lib/containerStorageAdapter.js +0 -99
  301. package/lib/containerStorageAdapter.js.map +0 -1
  302. package/lib/contracts.d.ts.map +0 -1
  303. package/lib/contracts.js.map +0 -1
  304. package/lib/deltaManager.d.ts.map +0 -1
  305. package/lib/deltaManager.js.map +0 -1
  306. package/lib/deltaManagerProxy.d.ts +0 -54
  307. package/lib/deltaManagerProxy.d.ts.map +0 -1
  308. package/lib/deltaManagerProxy.js +0 -110
  309. package/lib/deltaManagerProxy.js.map +0 -1
  310. package/lib/deltaQueue.d.ts.map +0 -1
  311. package/lib/deltaQueue.js.map +0 -1
  312. package/lib/index.d.ts +0 -8
  313. package/lib/index.d.ts.map +0 -1
  314. package/lib/index.js +0 -8
  315. package/lib/index.js.map +0 -1
  316. package/lib/loader.d.ts.map +0 -1
  317. package/lib/loader.js +0 -236
  318. package/lib/loader.js.map +0 -1
  319. package/lib/packageVersion.js.map +0 -1
  320. package/lib/protocolTreeDocumentStorageService.d.ts.map +0 -1
  321. package/lib/protocolTreeDocumentStorageService.js.map +0 -1
  322. package/lib/quorum.d.ts +0 -21
  323. package/lib/quorum.d.ts.map +0 -1
  324. package/lib/quorum.js +0 -38
  325. package/lib/quorum.js.map +0 -1
  326. package/lib/retriableDocumentStorageService.d.ts.map +0 -1
  327. package/lib/retriableDocumentStorageService.js.map +0 -1
  328. package/lib/utils.d.ts +0 -34
  329. package/lib/utils.d.ts.map +0 -1
  330. package/lib/utils.js.map +0 -1
  331. package/src/collabWindowTracker.ts +0 -102
  332. package/src/deltaManagerProxy.ts +0 -158
  333. package/tsconfig.esnext.json +0 -7
@@ -3,126 +3,322 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryLogger } from "@fluidframework/common-definitions";
6
+ import { IDisposable } from "@fluidframework/core-interfaces";
7
+ import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
8
+ import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
9
+ import { assert } from "@fluidframework/core-utils";
7
10
  import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
8
11
  import {
9
- IDocumentStorageService,
10
- IDocumentStorageServicePolicies,
11
- ISummaryContext,
12
+ FetchSource,
13
+ IDocumentService,
14
+ IDocumentStorageService,
15
+ IDocumentStorageServicePolicies,
16
+ ISummaryContext,
12
17
  } from "@fluidframework/driver-definitions";
18
+ import { UsageError } from "@fluidframework/driver-utils";
13
19
  import {
14
- ICreateBlobResponse,
15
- ISnapshotTree,
16
- ISummaryHandle,
17
- ISummaryTree,
18
- IVersion,
20
+ ICreateBlobResponse,
21
+ ISnapshotTree,
22
+ ISummaryHandle,
23
+ ISummaryTree,
24
+ IVersion,
19
25
  } from "@fluidframework/protocol-definitions";
20
26
  import { IDetachedBlobStorage } from "./loader";
27
+ import { ProtocolTreeStorageService } from "./protocolTreeDocumentStorageService";
28
+ import { RetriableDocumentStorageService } from "./retriableDocumentStorageService";
29
+
30
+ /**
31
+ * Stringified blobs from a summary/snapshot tree.
32
+ * @internal
33
+ */
34
+ export interface ISerializableBlobContents {
35
+ [id: string]: string;
36
+ }
21
37
 
22
38
  /**
23
39
  * This class wraps the actual storage and make sure no wrong apis are called according to
24
40
  * container attach state.
25
41
  */
26
- export class ContainerStorageAdapter implements IDocumentStorageService {
27
- private readonly blobContents: { [id: string]: ArrayBufferLike; } = {};
28
- constructor(private readonly storageGetter: () => IDocumentStorageService) {}
29
-
30
- public loadSnapshotForRehydratingContainer(snapshotTree: ISnapshotTreeWithBlobContents) {
31
- this.getBlobContents(snapshotTree);
32
- }
33
-
34
- private getBlobContents(snapshotTree: ISnapshotTreeWithBlobContents) {
35
- for (const [id, value] of Object.entries(snapshotTree.blobsContents)) {
36
- this.blobContents[id] = value;
37
- }
38
- for (const [_, tree] of Object.entries(snapshotTree.trees)) {
39
- this.getBlobContents(tree);
40
- }
41
- }
42
-
43
- public get policies(): IDocumentStorageServicePolicies | undefined {
44
- // back-compat 0.40 containerRuntime requests policies even in detached container if storage is present
45
- // and storage is always present in >=0.41.
46
- try {
47
- return this.storageGetter().policies;
48
- } catch (e) {}
49
- return undefined;
50
- }
51
-
52
- public get repositoryUrl(): string {
53
- return this.storageGetter().repositoryUrl;
54
- }
55
-
56
- public async getSnapshotTree(version?: IVersion, scenarioName?: string): Promise<ISnapshotTree | null> {
57
- return this.storageGetter().getSnapshotTree(version, scenarioName);
58
- }
59
-
60
- public async readBlob(id: string): Promise<ArrayBufferLike> {
61
- const blob = this.blobContents[id];
62
- if (blob !== undefined) {
63
- return blob;
64
- }
65
- return this.storageGetter().readBlob(id);
66
- }
67
-
68
- public async getVersions(versionId: string | null, count: number, scenarioName?: string): Promise<IVersion[]> {
69
- return this.storageGetter().getVersions(versionId, count, scenarioName);
70
- }
71
-
72
- public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
73
- return this.storageGetter().uploadSummaryWithContext(summary, context);
74
- }
75
-
76
- public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
77
- return this.storageGetter().downloadSummary(handle);
78
- }
79
-
80
- public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
81
- return this.storageGetter().createBlob(file);
82
- }
42
+ export class ContainerStorageAdapter implements IDocumentStorageService, IDisposable {
43
+ private _storageService: IDocumentStorageService & Partial<IDisposable>;
44
+
45
+ private _summarizeProtocolTree: boolean | undefined;
46
+ /**
47
+ * Whether the adapter will enforce sending combined summary trees.
48
+ */
49
+ public get summarizeProtocolTree() {
50
+ return this._summarizeProtocolTree === true;
51
+ }
52
+
53
+ /**
54
+ * An adapter that ensures we're using detachedBlobStorage up until we connect to a real service, and then
55
+ * after connecting to a real service augments it with retry and combined summary tree enforcement.
56
+ * @param detachedBlobStorage - The detached blob storage to use up until we connect to a real service
57
+ * @param logger - Telemetry logger
58
+ * @param addProtocolSummaryIfMissing - a callback to permit the container to inspect the summary we're about to
59
+ * upload, and fix it up with a protocol tree if needed
60
+ * @param forceEnableSummarizeProtocolTree - Enforce uploading a protocol summary regardless of the service's policy
61
+ */
62
+ public constructor(
63
+ detachedBlobStorage: IDetachedBlobStorage | undefined,
64
+ private readonly logger: ITelemetryLoggerExt,
65
+ /**
66
+ * ArrayBufferLikes or utf8 encoded strings, containing blobs from a snapshot
67
+ */
68
+ private readonly blobContents: { [id: string]: ArrayBufferLike | string } = {},
69
+ private readonly addProtocolSummaryIfMissing: (summaryTree: ISummaryTree) => ISummaryTree,
70
+ forceEnableSummarizeProtocolTree: boolean | undefined,
71
+ ) {
72
+ this._storageService = new BlobOnlyStorage(detachedBlobStorage, logger);
73
+ this._summarizeProtocolTree = forceEnableSummarizeProtocolTree;
74
+ }
75
+
76
+ disposed: boolean = false;
77
+ dispose(error?: Error): void {
78
+ this._storageService?.dispose?.(error);
79
+ this.disposed = true;
80
+ }
81
+
82
+ public connectToService(service: IDocumentService): void {
83
+ if (!(this._storageService instanceof BlobOnlyStorage)) {
84
+ return;
85
+ }
86
+
87
+ const storageServiceP = service.connectToStorage();
88
+ const retriableStorage = (this._storageService = new RetriableDocumentStorageService(
89
+ storageServiceP,
90
+ this.logger,
91
+ ));
92
+
93
+ this._summarizeProtocolTree =
94
+ this._summarizeProtocolTree ?? service.policies?.summarizeProtocolTree;
95
+ if (this.summarizeProtocolTree) {
96
+ this.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
97
+ this._storageService = new ProtocolTreeStorageService(
98
+ retriableStorage,
99
+ this.addProtocolSummaryIfMissing,
100
+ );
101
+ }
102
+ }
103
+
104
+ public loadSnapshotForRehydratingContainer(snapshotTree: ISnapshotTreeWithBlobContents) {
105
+ this.getBlobContents(snapshotTree);
106
+ }
107
+
108
+ private getBlobContents(snapshotTree: ISnapshotTreeWithBlobContents) {
109
+ if (snapshotTree.blobsContents !== undefined) {
110
+ for (const [id, value] of Object.entries(snapshotTree.blobsContents ?? {})) {
111
+ this.blobContents[id] = value;
112
+ }
113
+ }
114
+ for (const [_, tree] of Object.entries(snapshotTree.trees)) {
115
+ this.getBlobContents(tree);
116
+ }
117
+ }
118
+
119
+ public get policies(): IDocumentStorageServicePolicies | undefined {
120
+ // back-compat 0.40 containerRuntime requests policies even in detached container if storage is present
121
+ // and storage is always present in >=0.41.
122
+ try {
123
+ return this._storageService.policies;
124
+ } catch (e) {}
125
+ return undefined;
126
+ }
127
+
128
+ public get repositoryUrl(): string {
129
+ return this._storageService.repositoryUrl;
130
+ }
131
+
132
+ public async getSnapshotTree(
133
+ version?: IVersion,
134
+ scenarioName?: string,
135
+ ): Promise<ISnapshotTree | null> {
136
+ return this._storageService.getSnapshotTree(version, scenarioName);
137
+ }
138
+
139
+ public async readBlob(id: string): Promise<ArrayBufferLike> {
140
+ const maybeBlob = this.blobContents[id];
141
+ if (maybeBlob !== undefined) {
142
+ if (typeof maybeBlob === "string") {
143
+ const blob = stringToBuffer(maybeBlob, "utf8");
144
+ return blob;
145
+ }
146
+ return maybeBlob;
147
+ }
148
+ return this._storageService.readBlob(id);
149
+ }
150
+
151
+ public async getVersions(
152
+ versionId: string | null,
153
+ count: number,
154
+ scenarioName?: string,
155
+ fetchSource?: FetchSource,
156
+ ): Promise<IVersion[]> {
157
+ return this._storageService.getVersions(versionId, count, scenarioName, fetchSource);
158
+ }
159
+
160
+ public async uploadSummaryWithContext(
161
+ summary: ISummaryTree,
162
+ context: ISummaryContext,
163
+ ): Promise<string> {
164
+ return this._storageService.uploadSummaryWithContext(summary, context);
165
+ }
166
+
167
+ public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
168
+ return this._storageService.downloadSummary(handle);
169
+ }
170
+
171
+ public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
172
+ return this._storageService.createBlob(file);
173
+ }
83
174
  }
84
175
 
85
176
  /**
86
177
  * Storage which only supports createBlob() and readBlob(). This is used with IDetachedBlobStorage to support
87
178
  * blobs in detached containers.
88
179
  */
89
- export class BlobOnlyStorage implements IDocumentStorageService {
90
- constructor(
91
- private readonly blobStorage: IDetachedBlobStorage,
92
- private readonly logger: ITelemetryLogger,
93
- ) { }
94
-
95
- public async createBlob(content: ArrayBufferLike): Promise<ICreateBlobResponse> {
96
- return this.blobStorage.createBlob(content);
97
- }
98
-
99
- public async readBlob(blobId: string): Promise<ArrayBufferLike> {
100
- return this.blobStorage.readBlob(blobId);
101
- }
102
-
103
- public get policies(): IDocumentStorageServicePolicies | undefined {
104
- return this.notCalled();
105
- }
106
-
107
- public get repositoryUrl(): string {
108
- return this.notCalled();
109
- }
110
-
111
- /* eslint-disable @typescript-eslint/unbound-method */
112
- public getSnapshotTree: () => Promise<ISnapshotTree | null> = this.notCalled;
113
- public getVersions: () => Promise<IVersion[]> = this.notCalled;
114
- public write: () => Promise<IVersion> = this.notCalled;
115
- public uploadSummaryWithContext: () => Promise<string> = this.notCalled;
116
- public downloadSummary: () => Promise<ISummaryTree> = this.notCalled;
117
- /* eslint-enable @typescript-eslint/unbound-method */
118
-
119
- private notCalled(): never {
120
- try {
121
- // some browsers may not populate stack unless exception is thrown
122
- throw new Error("BlobOnlyStorage not implemented method used");
123
- } catch (err) {
124
- this.logger.sendErrorEvent({ eventName: "BlobOnlyStorageWrongCall" }, err);
125
- throw err;
126
- }
127
- }
180
+ class BlobOnlyStorage implements IDocumentStorageService {
181
+ constructor(
182
+ private readonly detachedStorage: IDetachedBlobStorage | undefined,
183
+ private readonly logger: ITelemetryLoggerExt,
184
+ ) {}
185
+
186
+ public async createBlob(content: ArrayBufferLike): Promise<ICreateBlobResponse> {
187
+ return this.verifyStorage().createBlob(content);
188
+ }
189
+
190
+ public async readBlob(blobId: string): Promise<ArrayBufferLike> {
191
+ return this.verifyStorage().readBlob(blobId);
192
+ }
193
+
194
+ private verifyStorage(): IDetachedBlobStorage {
195
+ if (this.detachedStorage === undefined) {
196
+ throw new UsageError("Real storage calls not allowed in Unattached container");
197
+ }
198
+ return this.detachedStorage;
199
+ }
200
+
201
+ public get policies(): IDocumentStorageServicePolicies | undefined {
202
+ return this.notCalled();
203
+ }
204
+
205
+ public get repositoryUrl(): string {
206
+ return this.notCalled();
207
+ }
208
+
209
+ /* eslint-disable @typescript-eslint/unbound-method */
210
+ public getSnapshotTree: () => Promise<ISnapshotTree | null> = this.notCalled;
211
+ public getVersions: () => Promise<IVersion[]> = this.notCalled;
212
+ public write: () => Promise<IVersion> = this.notCalled;
213
+ public uploadSummaryWithContext: () => Promise<string> = this.notCalled;
214
+ public downloadSummary: () => Promise<ISummaryTree> = this.notCalled;
215
+ /* eslint-enable @typescript-eslint/unbound-method */
216
+
217
+ private notCalled(): never {
218
+ this.verifyStorage();
219
+ try {
220
+ // some browsers may not populate stack unless exception is thrown
221
+ throw new Error("BlobOnlyStorage not implemented method used");
222
+ } catch (err) {
223
+ this.logger.sendTelemetryEvent({ eventName: "BlobOnlyStorageWrongCall" }, err);
224
+ throw err;
225
+ }
226
+ }
227
+ }
228
+
229
+ // runtime will write a tree to the summary containing "attachment" type entries
230
+ // which reference attachment blobs by ID, along with a blob containing the blob redirect table.
231
+ // However, some drivers do not support the "attachment" type and will convert them to "blob" type
232
+ // entries. We want to avoid saving these to reduce the size of stashed change blobs, but we
233
+ // need to make sure the blob redirect table is saved.
234
+ const blobsTreeName = ".blobs";
235
+ const redirectTableBlobName = ".redirectTable";
236
+
237
+ /**
238
+ * Get blob contents of a snapshot tree from storage (or, ideally, cache)
239
+ */
240
+ export async function getBlobContentsFromTree(
241
+ snapshot: ISnapshotTree,
242
+ storage: IDocumentStorageService,
243
+ ): Promise<ISerializableBlobContents> {
244
+ const blobs = {};
245
+ await getBlobContentsFromTreeCore(snapshot, blobs, storage);
246
+ return blobs;
247
+ }
248
+
249
+ async function getBlobContentsFromTreeCore(
250
+ tree: ISnapshotTree,
251
+ blobs: ISerializableBlobContents,
252
+ storage: IDocumentStorageService,
253
+ root = true,
254
+ ) {
255
+ const treePs: Promise<any>[] = [];
256
+ for (const [key, subTree] of Object.entries(tree.trees)) {
257
+ if (root && key === blobsTreeName) {
258
+ treePs.push(getBlobManagerTreeFromTree(subTree, blobs, storage));
259
+ } else {
260
+ treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage, false));
261
+ }
262
+ }
263
+ for (const id of Object.values(tree.blobs)) {
264
+ const blob = await storage.readBlob(id);
265
+ // ArrayBufferLike will not survive JSON.stringify()
266
+ blobs[id] = bufferToString(blob, "utf8");
267
+ }
268
+ return Promise.all(treePs);
269
+ }
270
+
271
+ // save redirect table from .blobs tree but nothing else
272
+ async function getBlobManagerTreeFromTree(
273
+ tree: ISnapshotTree,
274
+ blobs: ISerializableBlobContents,
275
+ storage: IDocumentStorageService,
276
+ ) {
277
+ const id = tree.blobs[redirectTableBlobName];
278
+ const blob = await storage.readBlob(id);
279
+ // ArrayBufferLike will not survive JSON.stringify()
280
+ blobs[id] = bufferToString(blob, "utf8");
281
+ }
282
+
283
+ /**
284
+ * Extract blob contents from a snapshot tree with blob contents
285
+ */
286
+ export function getBlobContentsFromTreeWithBlobContents(
287
+ snapshot: ISnapshotTreeWithBlobContents,
288
+ ): ISerializableBlobContents {
289
+ const blobs = {};
290
+ getBlobContentsFromTreeWithBlobContentsCore(snapshot, blobs);
291
+ return blobs;
292
+ }
293
+
294
+ function getBlobContentsFromTreeWithBlobContentsCore(
295
+ tree: ISnapshotTreeWithBlobContents,
296
+ blobs: ISerializableBlobContents,
297
+ root = true,
298
+ ) {
299
+ for (const [key, subTree] of Object.entries(tree.trees)) {
300
+ if (root && key === blobsTreeName) {
301
+ getBlobManagerTreeFromTreeWithBlobContents(subTree, blobs);
302
+ } else {
303
+ getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs, false);
304
+ }
305
+ }
306
+ for (const id of Object.values(tree.blobs)) {
307
+ const blob = tree.blobsContents?.[id];
308
+ assert(blob !== undefined, 0x2ec /* "Blob must be present in blobsContents" */);
309
+ // ArrayBufferLike will not survive JSON.stringify()
310
+ blobs[id] = bufferToString(blob, "utf8");
311
+ }
312
+ }
313
+
314
+ // save redirect table from .blobs tree but nothing else
315
+ function getBlobManagerTreeFromTreeWithBlobContents(
316
+ tree: ISnapshotTreeWithBlobContents,
317
+ blobs: ISerializableBlobContents,
318
+ ) {
319
+ const id = tree.blobs[redirectTableBlobName];
320
+ const blob = tree.blobsContents?.[id];
321
+ assert(blob !== undefined, 0x70f /* Blob must be present in blobsContents */);
322
+ // ArrayBufferLike will not survive JSON.stringify()
323
+ blobs[id] = bufferToString(blob, "utf8");
128
324
  }