@fluidframework/container-loader 1.4.0-121020 → 2.0.0-dev-rc.1.0.0.225277

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 (335) 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-esm.json +4 -0
  6. package/api-extractor-lint.json +4 -0
  7. package/api-extractor.json +2 -2
  8. package/api-report/container-loader.api.md +143 -0
  9. package/dist/{audience.js → audience.cjs} +15 -13
  10. package/dist/audience.cjs.map +1 -0
  11. package/dist/audience.d.ts +4 -6
  12. package/dist/audience.d.ts.map +1 -1
  13. package/dist/catchUpMonitor.cjs +43 -0
  14. package/dist/catchUpMonitor.cjs.map +1 -0
  15. package/dist/catchUpMonitor.d.ts +29 -0
  16. package/dist/catchUpMonitor.d.ts.map +1 -0
  17. package/dist/{connectionManager.js → connectionManager.cjs} +397 -240
  18. package/dist/connectionManager.cjs.map +1 -0
  19. package/dist/connectionManager.d.ts +23 -33
  20. package/dist/connectionManager.d.ts.map +1 -1
  21. package/dist/{connectionState.js → connectionState.cjs} +5 -7
  22. package/dist/connectionState.cjs.map +1 -0
  23. package/dist/connectionState.d.ts +3 -5
  24. package/dist/connectionState.d.ts.map +1 -1
  25. package/dist/connectionStateHandler.cjs +474 -0
  26. package/dist/connectionStateHandler.cjs.map +1 -0
  27. package/dist/connectionStateHandler.d.ts +127 -29
  28. package/dist/connectionStateHandler.d.ts.map +1 -1
  29. package/dist/container-loader-alpha.d.ts +274 -0
  30. package/dist/container-loader-beta.d.ts +75 -0
  31. package/dist/container-loader-public.d.ts +75 -0
  32. package/dist/container-loader-untrimmed.d.ts +331 -0
  33. package/dist/container.cjs +1585 -0
  34. package/dist/container.cjs.map +1 -0
  35. package/dist/container.d.ts +227 -83
  36. package/dist/container.d.ts.map +1 -1
  37. package/dist/containerContext.cjs +74 -0
  38. package/dist/containerContext.cjs.map +1 -0
  39. package/dist/containerContext.d.ts +33 -59
  40. package/dist/containerContext.d.ts.map +1 -1
  41. package/dist/containerStorageAdapter.cjs +234 -0
  42. package/dist/containerStorageAdapter.cjs.map +1 -0
  43. package/dist/containerStorageAdapter.d.ts +48 -23
  44. package/dist/containerStorageAdapter.d.ts.map +1 -1
  45. package/dist/{contracts.js → contracts.cjs} +5 -5
  46. package/dist/contracts.cjs.map +1 -0
  47. package/dist/contracts.d.ts +45 -17
  48. package/dist/contracts.d.ts.map +1 -1
  49. package/dist/debugLogger.cjs +101 -0
  50. package/dist/debugLogger.cjs.map +1 -0
  51. package/dist/debugLogger.d.ts +30 -0
  52. package/dist/debugLogger.d.ts.map +1 -0
  53. package/dist/{deltaManager.js → deltaManager.cjs} +379 -186
  54. package/dist/deltaManager.cjs.map +1 -0
  55. package/dist/deltaManager.d.ts +54 -18
  56. package/dist/deltaManager.d.ts.map +1 -1
  57. package/dist/{deltaQueue.js → deltaQueue.cjs} +29 -28
  58. package/dist/deltaQueue.cjs.map +1 -0
  59. package/dist/deltaQueue.d.ts +3 -4
  60. package/dist/deltaQueue.d.ts.map +1 -1
  61. package/dist/disposal.cjs +25 -0
  62. package/dist/disposal.cjs.map +1 -0
  63. package/dist/disposal.d.ts +13 -0
  64. package/dist/disposal.d.ts.map +1 -0
  65. package/dist/error.cjs +32 -0
  66. package/dist/error.cjs.map +1 -0
  67. package/dist/error.d.ts +23 -0
  68. package/dist/error.d.ts.map +1 -0
  69. package/dist/index.cjs +19 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.d.ts +5 -2
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/loader.cjs +148 -0
  74. package/dist/loader.cjs.map +1 -0
  75. package/dist/loader.d.ts +38 -19
  76. package/dist/loader.d.ts.map +1 -1
  77. package/dist/location-redirection-utilities/index.cjs +11 -0
  78. package/dist/location-redirection-utilities/index.cjs.map +1 -0
  79. package/dist/location-redirection-utilities/index.d.ts +6 -0
  80. package/dist/location-redirection-utilities/index.d.ts.map +1 -0
  81. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs +53 -0
  82. package/dist/location-redirection-utilities/resolveWithLocationRedirection.cjs.map +1 -0
  83. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +24 -0
  84. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
  85. package/dist/{collabWindowTracker.js → noopHeuristic.cjs} +37 -39
  86. package/dist/noopHeuristic.cjs.map +1 -0
  87. package/dist/noopHeuristic.d.ts +23 -0
  88. package/dist/noopHeuristic.d.ts.map +1 -0
  89. package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
  90. package/dist/packageVersion.cjs.map +1 -0
  91. package/dist/packageVersion.d.ts +1 -1
  92. package/dist/packageVersion.d.ts.map +1 -1
  93. package/dist/protocol.cjs +99 -0
  94. package/dist/protocol.cjs.map +1 -0
  95. package/dist/protocol.d.ts +38 -0
  96. package/dist/protocol.d.ts.map +1 -0
  97. package/dist/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.cjs} +8 -5
  98. package/dist/protocolTreeDocumentStorageService.cjs.map +1 -0
  99. package/dist/protocolTreeDocumentStorageService.d.ts +8 -4
  100. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  101. package/dist/quorum.cjs +16 -0
  102. package/dist/quorum.cjs.map +1 -0
  103. package/dist/quorum.d.ts +1 -14
  104. package/dist/quorum.d.ts.map +1 -1
  105. package/dist/{retriableDocumentStorageService.js → retriableDocumentStorageService.cjs} +36 -21
  106. package/dist/retriableDocumentStorageService.cjs.map +1 -0
  107. package/dist/retriableDocumentStorageService.d.ts +7 -5
  108. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  109. package/dist/tsdoc-metadata.json +11 -0
  110. package/dist/{utils.js → utils.cjs} +52 -14
  111. package/dist/utils.cjs.map +1 -0
  112. package/dist/utils.d.ts +34 -1
  113. package/dist/utils.d.ts.map +1 -1
  114. package/lib/{audience.d.ts → audience.d.mts} +5 -11
  115. package/lib/audience.d.mts.map +1 -0
  116. package/lib/{audience.js → audience.mjs} +15 -17
  117. package/lib/audience.mjs.map +1 -0
  118. package/lib/catchUpMonitor.d.mts +29 -0
  119. package/lib/catchUpMonitor.d.mts.map +1 -0
  120. package/lib/catchUpMonitor.mjs +39 -0
  121. package/lib/catchUpMonitor.mjs.map +1 -0
  122. package/lib/{connectionManager.d.ts → connectionManager.d.mts} +24 -34
  123. package/lib/connectionManager.d.mts.map +1 -0
  124. package/lib/{connectionManager.js → connectionManager.mjs} +378 -218
  125. package/lib/connectionManager.mjs.map +1 -0
  126. package/lib/{connectionState.d.ts → connectionState.d.mts} +4 -6
  127. package/lib/connectionState.d.mts.map +1 -0
  128. package/lib/{connectionState.js → connectionState.mjs} +4 -6
  129. package/lib/connectionState.mjs.map +1 -0
  130. package/lib/connectionStateHandler.d.mts +179 -0
  131. package/lib/connectionStateHandler.d.mts.map +1 -0
  132. package/lib/connectionStateHandler.mjs +469 -0
  133. package/lib/connectionStateHandler.mjs.map +1 -0
  134. package/lib/container-loader-alpha.d.mts +274 -0
  135. package/lib/container-loader-beta.d.mts +75 -0
  136. package/lib/container-loader-public.d.mts +75 -0
  137. package/lib/container-loader-untrimmed.d.mts +331 -0
  138. package/lib/container.d.mts +382 -0
  139. package/lib/container.d.mts.map +1 -0
  140. package/lib/container.mjs +1579 -0
  141. package/lib/container.mjs.map +1 -0
  142. package/lib/containerContext.d.mts +58 -0
  143. package/lib/containerContext.d.mts.map +1 -0
  144. package/lib/containerContext.mjs +70 -0
  145. package/lib/containerContext.mjs.map +1 -0
  146. package/lib/containerStorageAdapter.d.mts +73 -0
  147. package/lib/containerStorageAdapter.d.mts.map +1 -0
  148. package/lib/containerStorageAdapter.mjs +228 -0
  149. package/lib/containerStorageAdapter.mjs.map +1 -0
  150. package/lib/{contracts.d.ts → contracts.d.mts} +46 -18
  151. package/lib/contracts.d.mts.map +1 -0
  152. package/lib/{contracts.js → contracts.mjs} +4 -4
  153. package/lib/contracts.mjs.map +1 -0
  154. package/lib/debugLogger.d.mts +30 -0
  155. package/lib/debugLogger.d.mts.map +1 -0
  156. package/lib/debugLogger.mjs +93 -0
  157. package/lib/debugLogger.mjs.map +1 -0
  158. package/lib/{deltaManager.d.ts → deltaManager.d.mts} +55 -19
  159. package/lib/deltaManager.d.mts.map +1 -0
  160. package/lib/{deltaManager.js → deltaManager.mjs} +361 -165
  161. package/lib/deltaManager.mjs.map +1 -0
  162. package/lib/{deltaQueue.d.ts → deltaQueue.d.mts} +4 -5
  163. package/lib/deltaQueue.d.mts.map +1 -0
  164. package/lib/{deltaQueue.js → deltaQueue.mjs} +25 -24
  165. package/lib/deltaQueue.mjs.map +1 -0
  166. package/lib/disposal.d.mts +13 -0
  167. package/lib/disposal.d.mts.map +1 -0
  168. package/lib/disposal.mjs +21 -0
  169. package/lib/disposal.mjs.map +1 -0
  170. package/lib/error.d.mts +23 -0
  171. package/lib/error.d.mts.map +1 -0
  172. package/lib/error.mjs +28 -0
  173. package/lib/error.mjs.map +1 -0
  174. package/lib/index.d.mts +11 -0
  175. package/lib/index.d.mts.map +1 -0
  176. package/lib/index.mjs +10 -0
  177. package/lib/index.mjs.map +1 -0
  178. package/lib/{loader.d.ts → loader.d.mts} +40 -21
  179. package/lib/loader.d.mts.map +1 -0
  180. package/lib/loader.mjs +143 -0
  181. package/lib/loader.mjs.map +1 -0
  182. package/lib/location-redirection-utilities/index.d.mts +6 -0
  183. package/lib/location-redirection-utilities/index.d.mts.map +1 -0
  184. package/lib/location-redirection-utilities/index.mjs +6 -0
  185. package/lib/location-redirection-utilities/index.mjs.map +1 -0
  186. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts +24 -0
  187. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.mts.map +1 -0
  188. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs +48 -0
  189. package/lib/location-redirection-utilities/resolveWithLocationRedirection.mjs.map +1 -0
  190. package/lib/noopHeuristic.d.mts +23 -0
  191. package/lib/noopHeuristic.d.mts.map +1 -0
  192. package/lib/{collabWindowTracker.js → noopHeuristic.mjs} +33 -35
  193. package/lib/noopHeuristic.mjs.map +1 -0
  194. package/lib/{packageVersion.d.ts → packageVersion.d.mts} +2 -2
  195. package/lib/packageVersion.d.mts.map +1 -0
  196. package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
  197. package/lib/packageVersion.mjs.map +1 -0
  198. package/lib/protocol.d.mts +38 -0
  199. package/lib/protocol.d.mts.map +1 -0
  200. package/lib/protocol.mjs +94 -0
  201. package/lib/protocol.mjs.map +1 -0
  202. package/lib/{protocolTreeDocumentStorageService.d.ts → protocolTreeDocumentStorageService.d.mts} +9 -5
  203. package/lib/protocolTreeDocumentStorageService.d.mts.map +1 -0
  204. package/lib/{protocolTreeDocumentStorageService.js → protocolTreeDocumentStorageService.mjs} +8 -5
  205. package/lib/protocolTreeDocumentStorageService.mjs.map +1 -0
  206. package/lib/quorum.d.mts +4 -0
  207. package/lib/quorum.d.mts.map +1 -0
  208. package/lib/quorum.mjs +12 -0
  209. package/lib/quorum.mjs.map +1 -0
  210. package/lib/{retriableDocumentStorageService.d.ts → retriableDocumentStorageService.d.mts} +8 -6
  211. package/lib/retriableDocumentStorageService.d.mts.map +1 -0
  212. package/lib/{retriableDocumentStorageService.js → retriableDocumentStorageService.mjs} +35 -20
  213. package/lib/retriableDocumentStorageService.mjs.map +1 -0
  214. package/lib/utils.d.mts +67 -0
  215. package/lib/utils.d.mts.map +1 -0
  216. package/lib/{utils.js → utils.mjs} +47 -11
  217. package/lib/utils.mjs.map +1 -0
  218. package/package.json +189 -69
  219. package/prettier.config.cjs +8 -0
  220. package/src/audience.ts +59 -49
  221. package/src/catchUpMonitor.ts +61 -0
  222. package/src/connectionManager.ts +1154 -910
  223. package/src/connectionState.ts +22 -25
  224. package/src/connectionStateHandler.ts +689 -319
  225. package/src/container.ts +2476 -1792
  226. package/src/containerContext.ts +98 -330
  227. package/src/containerStorageAdapter.ts +301 -105
  228. package/src/contracts.ts +184 -146
  229. package/src/debugLogger.ts +123 -0
  230. package/src/deltaManager.ts +1165 -900
  231. package/src/deltaQueue.ts +156 -152
  232. package/src/disposal.ts +25 -0
  233. package/src/error.ts +44 -0
  234. package/src/index.ts +14 -15
  235. package/src/loader.ts +356 -427
  236. package/src/location-redirection-utilities/index.ts +9 -0
  237. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +61 -0
  238. package/src/noopHeuristic.ts +107 -0
  239. package/src/packageVersion.ts +1 -1
  240. package/src/protocol.ts +150 -0
  241. package/src/protocolTreeDocumentStorageService.ts +35 -35
  242. package/src/quorum.ts +11 -50
  243. package/src/retriableDocumentStorageService.ts +135 -95
  244. package/src/utils.ts +159 -86
  245. package/tsc-multi.test.json +4 -0
  246. package/tsconfig.json +10 -12
  247. package/dist/audience.js.map +0 -1
  248. package/dist/collabWindowTracker.d.ts +0 -19
  249. package/dist/collabWindowTracker.d.ts.map +0 -1
  250. package/dist/collabWindowTracker.js.map +0 -1
  251. package/dist/connectionManager.js.map +0 -1
  252. package/dist/connectionState.js.map +0 -1
  253. package/dist/connectionStateHandler.js +0 -280
  254. package/dist/connectionStateHandler.js.map +0 -1
  255. package/dist/container.js +0 -1284
  256. package/dist/container.js.map +0 -1
  257. package/dist/containerContext.js +0 -217
  258. package/dist/containerContext.js.map +0 -1
  259. package/dist/containerStorageAdapter.js +0 -104
  260. package/dist/containerStorageAdapter.js.map +0 -1
  261. package/dist/contracts.js.map +0 -1
  262. package/dist/deltaManager.js.map +0 -1
  263. package/dist/deltaManagerProxy.d.ts +0 -54
  264. package/dist/deltaManagerProxy.d.ts.map +0 -1
  265. package/dist/deltaManagerProxy.js +0 -115
  266. package/dist/deltaManagerProxy.js.map +0 -1
  267. package/dist/deltaQueue.js.map +0 -1
  268. package/dist/index.js +0 -16
  269. package/dist/index.js.map +0 -1
  270. package/dist/loader.js +0 -241
  271. package/dist/loader.js.map +0 -1
  272. package/dist/packageVersion.js.map +0 -1
  273. package/dist/protocolTreeDocumentStorageService.js.map +0 -1
  274. package/dist/quorum.js +0 -44
  275. package/dist/quorum.js.map +0 -1
  276. package/dist/retriableDocumentStorageService.js.map +0 -1
  277. package/dist/utils.js.map +0 -1
  278. package/lib/audience.d.ts.map +0 -1
  279. package/lib/audience.js.map +0 -1
  280. package/lib/collabWindowTracker.d.ts +0 -19
  281. package/lib/collabWindowTracker.d.ts.map +0 -1
  282. package/lib/collabWindowTracker.js.map +0 -1
  283. package/lib/connectionManager.d.ts.map +0 -1
  284. package/lib/connectionManager.js.map +0 -1
  285. package/lib/connectionState.d.ts.map +0 -1
  286. package/lib/connectionState.js.map +0 -1
  287. package/lib/connectionStateHandler.d.ts +0 -81
  288. package/lib/connectionStateHandler.d.ts.map +0 -1
  289. package/lib/connectionStateHandler.js +0 -276
  290. package/lib/connectionStateHandler.js.map +0 -1
  291. package/lib/container.d.ts +0 -238
  292. package/lib/container.d.ts.map +0 -1
  293. package/lib/container.js +0 -1276
  294. package/lib/container.js.map +0 -1
  295. package/lib/containerContext.d.ts +0 -84
  296. package/lib/containerContext.d.ts.map +0 -1
  297. package/lib/containerContext.js +0 -213
  298. package/lib/containerContext.js.map +0 -1
  299. package/lib/containerStorageAdapter.d.ts +0 -48
  300. package/lib/containerStorageAdapter.d.ts.map +0 -1
  301. package/lib/containerStorageAdapter.js +0 -99
  302. package/lib/containerStorageAdapter.js.map +0 -1
  303. package/lib/contracts.d.ts.map +0 -1
  304. package/lib/contracts.js.map +0 -1
  305. package/lib/deltaManager.d.ts.map +0 -1
  306. package/lib/deltaManager.js.map +0 -1
  307. package/lib/deltaManagerProxy.d.ts +0 -54
  308. package/lib/deltaManagerProxy.d.ts.map +0 -1
  309. package/lib/deltaManagerProxy.js +0 -110
  310. package/lib/deltaManagerProxy.js.map +0 -1
  311. package/lib/deltaQueue.d.ts.map +0 -1
  312. package/lib/deltaQueue.js.map +0 -1
  313. package/lib/index.d.ts +0 -8
  314. package/lib/index.d.ts.map +0 -1
  315. package/lib/index.js +0 -8
  316. package/lib/index.js.map +0 -1
  317. package/lib/loader.d.ts.map +0 -1
  318. package/lib/loader.js +0 -236
  319. package/lib/loader.js.map +0 -1
  320. package/lib/packageVersion.d.ts.map +0 -1
  321. package/lib/packageVersion.js.map +0 -1
  322. package/lib/protocolTreeDocumentStorageService.d.ts.map +0 -1
  323. package/lib/protocolTreeDocumentStorageService.js.map +0 -1
  324. package/lib/quorum.d.ts +0 -21
  325. package/lib/quorum.d.ts.map +0 -1
  326. package/lib/quorum.js +0 -38
  327. package/lib/quorum.js.map +0 -1
  328. package/lib/retriableDocumentStorageService.d.ts.map +0 -1
  329. package/lib/retriableDocumentStorageService.js.map +0 -1
  330. package/lib/utils.d.ts +0 -34
  331. package/lib/utils.d.ts.map +0 -1
  332. package/lib/utils.js.map +0 -1
  333. package/src/collabWindowTracker.ts +0 -102
  334. package/src/deltaManagerProxy.ts +0 -158
  335. 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
  }