@fluidframework/container-loader 2.118.0 → 3.0.0

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 (213) hide show
  1. package/CHANGELOG.md +74 -4
  2. package/README.md +53 -50
  3. package/{api-extractor.json → api-extractor/api-extractor-model.json} +1 -1
  4. package/api-report/container-loader.legacy.alpha.api.md +4 -3
  5. package/dist/attachment.d.ts.map +1 -1
  6. package/dist/audience.js +3 -2
  7. package/dist/audience.js.map +1 -1
  8. package/dist/captureReferencedContents.js +9 -9
  9. package/dist/captureReferencedContents.js.map +1 -1
  10. package/dist/catchUpMonitor.js +11 -8
  11. package/dist/catchUpMonitor.js.map +1 -1
  12. package/dist/connectionManager.d.ts.map +1 -1
  13. package/dist/connectionManager.js +86 -51
  14. package/dist/connectionManager.js.map +1 -1
  15. package/dist/connectionStateHandler.js +40 -14
  16. package/dist/connectionStateHandler.js.map +1 -1
  17. package/dist/container.d.ts +1 -1
  18. package/dist/container.d.ts.map +1 -1
  19. package/dist/container.js +193 -143
  20. package/dist/container.js.map +1 -1
  21. package/dist/containerContext.js +48 -11
  22. package/dist/containerContext.js.map +1 -1
  23. package/dist/containerStorageAdapter.js +25 -17
  24. package/dist/containerStorageAdapter.js.map +1 -1
  25. package/dist/contracts.d.ts.map +1 -1
  26. package/dist/createAndLoadContainerUtils.d.ts +34 -13
  27. package/dist/createAndLoadContainerUtils.d.ts.map +1 -1
  28. package/dist/createAndLoadContainerUtils.js +97 -37
  29. package/dist/createAndLoadContainerUtils.js.map +1 -1
  30. package/dist/debugLogger.d.ts +7 -22
  31. package/dist/debugLogger.d.ts.map +1 -1
  32. package/dist/debugLogger.js +34 -34
  33. package/dist/debugLogger.js.map +1 -1
  34. package/dist/deltaManager.d.ts +16 -4
  35. package/dist/deltaManager.d.ts.map +1 -1
  36. package/dist/deltaManager.js +73 -48
  37. package/dist/deltaManager.js.map +1 -1
  38. package/dist/deltaManagerFactory.d.ts +23 -0
  39. package/dist/deltaManagerFactory.d.ts.map +1 -0
  40. package/dist/deltaManagerFactory.js +17 -0
  41. package/dist/deltaManagerFactory.js.map +1 -0
  42. package/dist/deltaQueue.js +14 -7
  43. package/dist/deltaQueue.js.map +1 -1
  44. package/dist/disposal.js +1 -2
  45. package/dist/disposal.js.map +1 -1
  46. package/dist/error.js +5 -4
  47. package/dist/error.js.map +1 -1
  48. package/dist/frozenServices.d.ts +2 -2
  49. package/dist/frozenServices.d.ts.map +1 -1
  50. package/dist/frozenServices.js +52 -34
  51. package/dist/frozenServices.js.map +1 -1
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +2 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/loadContainerToSequenceNumber.js +1 -2
  57. package/dist/loadContainerToSequenceNumber.js.map +1 -1
  58. package/dist/loadPaused.js +1 -2
  59. package/dist/loadPaused.js.map +1 -1
  60. package/dist/loader.js +5 -1
  61. package/dist/loader.js.map +1 -1
  62. package/dist/loaderLayerCompatState.d.ts +25 -1
  63. package/dist/loaderLayerCompatState.d.ts.map +1 -1
  64. package/dist/loaderLayerCompatState.js +79 -11
  65. package/dist/loaderLayerCompatState.js.map +1 -1
  66. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +2 -3
  67. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  68. package/dist/memoryBlobStorage.js +2 -3
  69. package/dist/memoryBlobStorage.js.map +1 -1
  70. package/dist/noopHeuristic.js +3 -1
  71. package/dist/noopHeuristic.js.map +1 -1
  72. package/dist/packageVersion.d.ts +1 -1
  73. package/dist/packageVersion.d.ts.map +1 -1
  74. package/dist/packageVersion.js +1 -1
  75. package/dist/packageVersion.js.map +1 -1
  76. package/dist/pendingLocalStateStore.d.ts +4 -3
  77. package/dist/pendingLocalStateStore.d.ts.map +1 -1
  78. package/dist/pendingLocalStateStore.js +26 -37
  79. package/dist/pendingLocalStateStore.js.map +1 -1
  80. package/dist/pointInTimeServices.js +4 -2
  81. package/dist/pointInTimeServices.js.map +1 -1
  82. package/dist/protocol/protocol.js +3 -0
  83. package/dist/protocol/protocol.js.map +1 -1
  84. package/dist/protocol/quorum.js +26 -5
  85. package/dist/protocol/quorum.js.map +1 -1
  86. package/dist/protocol.js +5 -3
  87. package/dist/protocol.js.map +1 -1
  88. package/dist/protocolTreeDocumentStorageService.js +10 -0
  89. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  90. package/dist/quorum.js +1 -2
  91. package/dist/quorum.js.map +1 -1
  92. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  93. package/dist/retriableDocumentStorageService.js +5 -1
  94. package/dist/retriableDocumentStorageService.js.map +1 -1
  95. package/dist/serializedStateManager.d.ts +6 -0
  96. package/dist/serializedStateManager.d.ts.map +1 -1
  97. package/dist/serializedStateManager.js +19 -24
  98. package/dist/serializedStateManager.js.map +1 -1
  99. package/dist/snapshotRefresher.js +31 -36
  100. package/dist/snapshotRefresher.js.map +1 -1
  101. package/dist/utils.d.ts +1 -1
  102. package/dist/utils.d.ts.map +1 -1
  103. package/dist/utils.js +13 -13
  104. package/dist/utils.js.map +1 -1
  105. package/lib/attachment.d.ts.map +1 -1
  106. package/lib/audience.js +3 -2
  107. package/lib/audience.js.map +1 -1
  108. package/lib/catchUpMonitor.js +11 -8
  109. package/lib/catchUpMonitor.js.map +1 -1
  110. package/lib/connectionManager.d.ts.map +1 -1
  111. package/lib/connectionManager.js +86 -51
  112. package/lib/connectionManager.js.map +1 -1
  113. package/lib/connectionStateHandler.js +37 -11
  114. package/lib/connectionStateHandler.js.map +1 -1
  115. package/lib/container.d.ts +1 -1
  116. package/lib/container.d.ts.map +1 -1
  117. package/lib/container.js +191 -141
  118. package/lib/container.js.map +1 -1
  119. package/lib/containerContext.js +48 -11
  120. package/lib/containerContext.js.map +1 -1
  121. package/lib/containerStorageAdapter.js +22 -14
  122. package/lib/containerStorageAdapter.js.map +1 -1
  123. package/lib/contracts.d.ts.map +1 -1
  124. package/lib/createAndLoadContainerUtils.d.ts +34 -13
  125. package/lib/createAndLoadContainerUtils.d.ts.map +1 -1
  126. package/lib/createAndLoadContainerUtils.js +93 -32
  127. package/lib/createAndLoadContainerUtils.js.map +1 -1
  128. package/lib/debugLogger.d.ts +7 -22
  129. package/lib/debugLogger.d.ts.map +1 -1
  130. package/lib/debugLogger.js +34 -33
  131. package/lib/debugLogger.js.map +1 -1
  132. package/lib/deltaManager.d.ts +16 -4
  133. package/lib/deltaManager.d.ts.map +1 -1
  134. package/lib/deltaManager.js +73 -48
  135. package/lib/deltaManager.js.map +1 -1
  136. package/lib/deltaManagerFactory.d.ts +23 -0
  137. package/lib/deltaManagerFactory.d.ts.map +1 -0
  138. package/lib/deltaManagerFactory.js +14 -0
  139. package/lib/deltaManagerFactory.js.map +1 -0
  140. package/lib/deltaQueue.js +14 -7
  141. package/lib/deltaQueue.js.map +1 -1
  142. package/lib/error.js +5 -4
  143. package/lib/error.js.map +1 -1
  144. package/lib/frozenServices.d.ts +2 -2
  145. package/lib/frozenServices.d.ts.map +1 -1
  146. package/lib/frozenServices.js +48 -30
  147. package/lib/frozenServices.js.map +1 -1
  148. package/lib/index.d.ts +1 -1
  149. package/lib/index.d.ts.map +1 -1
  150. package/lib/index.js +1 -1
  151. package/lib/index.js.map +1 -1
  152. package/lib/legacy.d.ts +1 -1
  153. package/lib/legacyAlpha.d.ts +1 -1
  154. package/lib/loader.js +6 -2
  155. package/lib/loader.js.map +1 -1
  156. package/lib/loaderLayerCompatState.d.ts +25 -1
  157. package/lib/loaderLayerCompatState.d.ts.map +1 -1
  158. package/lib/loaderLayerCompatState.js +76 -9
  159. package/lib/loaderLayerCompatState.js.map +1 -1
  160. package/lib/noopHeuristic.js +3 -1
  161. package/lib/noopHeuristic.js.map +1 -1
  162. package/lib/packageVersion.d.ts +1 -1
  163. package/lib/packageVersion.d.ts.map +1 -1
  164. package/lib/packageVersion.js +1 -1
  165. package/lib/packageVersion.js.map +1 -1
  166. package/lib/pendingLocalStateStore.d.ts +4 -3
  167. package/lib/pendingLocalStateStore.d.ts.map +1 -1
  168. package/lib/pendingLocalStateStore.js +26 -37
  169. package/lib/pendingLocalStateStore.js.map +1 -1
  170. package/lib/pointInTimeServices.js +2 -0
  171. package/lib/pointInTimeServices.js.map +1 -1
  172. package/lib/protocol/protocol.js +3 -0
  173. package/lib/protocol/protocol.js.map +1 -1
  174. package/lib/protocol/quorum.js +26 -5
  175. package/lib/protocol/quorum.js.map +1 -1
  176. package/lib/protocol.js +2 -0
  177. package/lib/protocol.js.map +1 -1
  178. package/lib/protocolTreeDocumentStorageService.js +10 -0
  179. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  180. package/lib/public.d.ts +1 -1
  181. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  182. package/lib/retriableDocumentStorageService.js +5 -1
  183. package/lib/retriableDocumentStorageService.js.map +1 -1
  184. package/lib/serializedStateManager.d.ts +6 -0
  185. package/lib/serializedStateManager.d.ts.map +1 -1
  186. package/lib/serializedStateManager.js +15 -20
  187. package/lib/serializedStateManager.js.map +1 -1
  188. package/lib/snapshotRefresher.js +31 -36
  189. package/lib/snapshotRefresher.js.map +1 -1
  190. package/lib/utils.d.ts +1 -1
  191. package/lib/utils.d.ts.map +1 -1
  192. package/lib/utils.js +3 -3
  193. package/lib/utils.js.map +1 -1
  194. package/package.json +44 -106
  195. package/src/container.ts +35 -22
  196. package/src/createAndLoadContainerUtils.ts +131 -46
  197. package/src/debugLogger.ts +39 -40
  198. package/src/deltaManager.ts +16 -4
  199. package/src/deltaManagerFactory.ts +53 -0
  200. package/src/frozenServices.ts +6 -7
  201. package/src/index.ts +1 -0
  202. package/src/loader.ts +2 -2
  203. package/src/loaderLayerCompatState.ts +85 -20
  204. package/src/packageVersion.ts +1 -1
  205. package/src/pendingLocalStateStore.ts +7 -3
  206. package/src/serializedStateManager.ts +6 -0
  207. package/src/utils.ts +3 -3
  208. package/tsconfig.json +1 -1
  209. package/internal.d.ts +0 -11
  210. package/legacy/alpha.d.ts +0 -11
  211. package/legacy.d.ts +0 -11
  212. /package/api-extractor/{api-extractor.current.json → api-extractor-report.current.json} +0 -0
  213. /package/api-extractor/{api-extractor.legacy.json → api-extractor-report.legacy.json} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,12 +1,82 @@
1
1
  # @fluidframework/container-loader
2
2
 
3
- ## 2.118.0
3
+ ## 3.0.0
4
4
 
5
- Dependency updates only.
5
+ ### Minor Changes
6
6
 
7
- ## 2.117.0
7
+ - Removal of direct CommonJS support ([#28124](https://github.com/microsoft/FluidFramework/pull/28124)) [0f84e3b8878](https://github.com/microsoft/FluidFramework/commit/0f84e3b8878a5e75b2253976d98fd963bbd9db88)
8
8
 
9
- Dependency updates only.
9
+ Direct `require()` import is no longer directly supported.
10
+ Package is transpiled as ECMAScript Module.
11
+
12
+ See [Removal of direct CommonJS support in v3.0](https://github.com/microsoft/FluidFramework/issues/27444) for more information.
13
+
14
+ - Full container state capture now includes recently sequenced operations ([#28009](https://github.com/microsoft/FluidFramework/pull/28009)) [6a2354f2146](https://github.com/microsoft/FluidFramework/commit/6a2354f2146440e6cbb8121957c4558cb47f6d5b)
15
+
16
+ `captureFullContainerState` now connects to the delta stream and catches up through the latest operation known when the connection is established.
17
+ This prevents captured state from omitting operations that have been broadcast over the websocket but have not yet reached delta storage.
18
+
19
+ - Require modern TypeScript module resolution ([#27970](https://github.com/microsoft/FluidFramework/pull/27970)) [325e2016ca9](https://github.com/microsoft/FluidFramework/commit/325e2016ca9978d4a1f7552c97ba34feac9df41f)
20
+
21
+ Fluid Framework Client packages no longer include type declaration compatibility entrypoints for TypeScript's legacy Node10 resolution mode (`"moduleResolution": "node"` or `"node10"`).
22
+ Applications upgrading to Fluid Framework 3.0 must use one of the following supported configurations:
23
+ - `"module": "Node16"` with `"moduleResolution": "Node16"`
24
+ - `"module": "NodeNext"` with `"moduleResolution": "NodeNext"`
25
+ - `"module": "ESNext"` with `"moduleResolution": "Bundler"`
26
+
27
+ Existing public package entrypoints exposed through `package.json` exports, including `/alpha`, `/beta`, and `/legacy`, remain available under supported module resolution modes.
28
+
29
+ See [Removal of Node10 resolutions in v3.0](https://github.com/microsoft/FluidFramework/issues/27457) for more information.
30
+
31
+ - Add reference-only capture for reusable container baselines ([#28006](https://github.com/microsoft/FluidFramework/pull/28006)) [4374770404e](https://github.com/microsoft/FluidFramework/commit/4374770404ee485456abc128c3266f24f25251c3)
32
+
33
+ [`captureFullContainerState`](https://fluidframework.com/docs/api/container-loader/#capturefullcontainerstate-function) now accepts a `blobCaptureMode` option. The default `"inline"` mode remains self-contained, while `"reference"` omits structural and attachment blob payloads so repeated online loads can fetch them from live storage.
34
+
35
+ ```typescript
36
+ const baseline = await captureFullContainerState({
37
+ urlResolver,
38
+ documentServiceFactory,
39
+ request,
40
+ blobCaptureMode: "reference",
41
+ });
42
+
43
+ const container = await loadExistingContainer({
44
+ ...loaderProps,
45
+ request,
46
+ pendingLocalState: baseline,
47
+ });
48
+ ```
49
+
50
+ - Client packages now target ES2022 ([#27846](https://github.com/microsoft/FluidFramework/pull/27846)) [91c78541bdd](https://github.com/microsoft/FluidFramework/commit/91c78541bddcbca5d6c5f357b023eeaee617d885)
51
+
52
+ The TypeScript compilation `target` and `lib` for the Fluid Framework client packages have been raised from ES2021/ES2020 to **ES2022**.
53
+ The published JavaScript now uses ES2022 language features (with correspondingly less down-leveling), so consuming these packages requires a runtime that supports ES2022.
54
+ All actively supported Node.js versions and evergreen browsers already meet this requirement.
55
+
56
+ Note that Fluid Framework has not officially supported targets older than ES2022 since before 2.0: this is documented in [ClientRequirements.md](https://github.com/microsoft/FluidFramework/blob/main/ClientRequirements.md) as well as the README for every client package.
57
+
58
+ It is possible this change could impact users of less up to date JavaScript runtimes.
59
+ Impacted users can use a tool like [babel](https://babeljs.io/) to transpile out unsupported language features.
60
+
61
+ - Pending local state uses Fluid-owned iterator types ([#27908](https://github.com/microsoft/FluidFramework/pull/27908)) [5035f7cfed4](https://github.com/microsoft/FluidFramework/commit/5035f7cfed4dedec8ded17b29be97f91f2a4b675)
62
+
63
+ [`PendingLocalStateStore`](https://fluidframework.com/docs/api/container-loader/pendinglocalstatestore-class) iteration methods now return [`FluidIterableIterator`](https://fluidframework.com/docs/api/core-interfaces/fluiditerableiterator-interface) instead of TypeScript's built-in iterator types.
64
+ This prevents changes to TypeScript's standard iterator interfaces from affecting the container loader API.
65
+
66
+ #### Migration
67
+
68
+ The returned iterators continue to support `next()`, spreading, and `for...of`.
69
+ Methods available only on newer built-in iterator types are not available.
70
+
71
+ ```typescript
72
+ for (const [key, pendingState] of pendingLocalStateStore.entries()) {
73
+ // ...
74
+ }
75
+ ```
76
+
77
+ - Build with TypeScript 6 ([#28052](https://github.com/microsoft/FluidFramework/pull/28052)) [7ab015c49de](https://github.com/microsoft/FluidFramework/commit/7ab015c49deec84833cdfe1fb5e1606b901f6e81)
78
+
79
+ FluidFramework Client SDK is now built using TypeScript 6. Consumers should build with TypeScript v6 or v7 or compatible tooling.
10
80
 
11
81
  ## 2.116.0
12
82
 
package/README.md CHANGED
@@ -47,15 +47,15 @@
47
47
 
48
48
  ## Using Fluid Framework libraries
49
49
 
50
- When taking a dependency on a Fluid Framework library's public APIs, we recommend using a `^` (caret) version range, such as `^1.3.4`.
51
- While Fluid Framework libraries may use different ranges with interdependencies between other Fluid Framework libraries,
52
- library consumers should always prefer `^`.
50
+ For a dependency on a Fluid Framework library's public APIs, we recommend a `^` (caret) version range.
51
+ For example, use `^1.3.4`.
53
52
 
54
- If using any of Fluid Framework's unstable APIs (for example, its `beta` APIs), we recommend using a more constrained version range, such as `~`.
53
+ For a dependency on an unstable API, such as a `beta` API, we recommend a more restrictive version range.
54
+ For example, use a `~` version range.
55
55
 
56
56
  ## Installation
57
57
 
58
- To get started, install the package by running the following command:
58
+ Run this command to install the package:
59
59
 
60
60
  ```bash
61
61
  npm i @fluidframework/container-loader
@@ -63,16 +63,16 @@ npm i @fluidframework/container-loader
63
63
 
64
64
  ## Importing from this package
65
65
 
66
- This package leverages [package.json exports](https://nodejs.org/api/packages.html#exports) to separate its APIs by support level.
67
- For more information on the related support guarantees, see [API Support Levels](https://fluidframework.com/docs/build/releases-and-apitags/#api-support-levels).
66
+ This package uses [package.json exports](https://nodejs.org/api/packages.html#exports) to separate APIs by support level.
67
+ For information about the support guarantees, read [API Support Levels](https://fluidframework.com/docs/build/releases-and-apitags/#api-support-levels).
68
68
 
69
- To access the `public` ([SemVer](https://semver.org/)) APIs, import via `@fluidframework/container-loader` like normal.
69
+ Import the `public` APIs from `@fluidframework/container-loader`.
70
70
 
71
- To access the `legacy` APIs, import via `@fluidframework/container-loader/legacy`.
71
+ Import the `legacy` APIs from `@fluidframework/container-loader/legacy`.
72
72
 
73
73
  ## API Documentation
74
74
 
75
- API documentation for **@fluidframework/container-loader** is available at <https://fluidframework.com/docs/apis/container-loader>.
75
+ Read the **@fluidframework/container-loader** API documentation at <https://fluidframework.com/docs/apis/container-loader>.
76
76
 
77
77
  <!-- prettier-ignore-end -->
78
78
 
@@ -302,62 +302,69 @@ Note that when an active connection is in place, it's just a matter of time befo
302
302
 
303
303
  ## Minimum Client Requirements
304
304
 
305
- These are the platform requirements for the current version of Fluid Framework Client Packages.
306
- These requirements err on the side of being too strict since within a major version they can be relaxed over time, but not made stricter.
307
- For Long Term Support (LTS) versions this can require supporting these platforms for several years.
305
+ Fluid Framework client libraries support the platforms in this document.
306
+ These requirements are intentionally restrictive.
307
+ Within a major version series, we can relax these requirements, but we cannot make them stricter.
308
+ For a Long Term Support (LTS) version, we might need to support these platforms for several years.
308
309
 
309
- It is likely that other configurations will work, but they are not supported: if they stop working, we do not consider that a bug.
310
- If you would benefit from support for something not listed here, file an issue and the product team will evaluate your request.
311
- When making such a request please include if the configuration already works (and thus the request is just that it becomes officially supported), or if changes are required to get it working.
310
+ Other configurations can work, but Fluid Framework does not support them.
311
+ If an unsupported configuration stops working, we do not classify this as a bug.
312
+ To request support for a configuration that is not listed, file an issue.
313
+ The product team will evaluate your request.
314
+ In the issue, specify the current status of the configuration:
315
+
316
+ - The configuration works but needs official support.
317
+ - The configuration does not work and requires changes.
312
318
 
313
319
  ### Supported Runtimes
314
320
 
315
- - NodeJs ^22.22.2 except that we will drop support for it [when NodeJs 22 loses its upstream support on 2027-04-30](https://github.com/nodejs/release#release-schedule), and will support a newer LTS version of NodeJS at least 1 year before 22 is end-of-life.
316
- - Running Fluid in a Node.js environment with the `--no-experimental-fetch` flag is not supported.
317
- - Modern browsers supporting the es2022 standard library: in response to asks we can add explicit support for using babel to polyfill to target specific standards or runtimes (meaning we can avoid/remove use of things that don't polyfill robustly, but otherwise target modern standards).
321
+ - Fluid Framework supports Node.js versions 22 and 24 while they receive [upstream support](https://nodejs.org/en/about/previous-releases).
322
+ - Fluid Framework will stop support for version 22 [when upstream support ends on 2027-04-30](https://github.com/nodejs/release#release-schedule).
323
+ - Fluid Framework does not support Node.js with the `--no-experimental-fetch` flag.
324
+ - Fluid Framework supports modern browsers that support the ES2022 standard library.
318
325
 
319
326
  ### Supported Tools
320
327
 
321
- - TypeScript 5.4:
322
- - All [`strict`](https://www.typescriptlang.org/tsconfig) options are supported.
323
- - [`strictNullChecks`](https://www.typescriptlang.org/tsconfig) is required.
324
- - [Configuration options deprecated in 5.0](https://github.com/microsoft/TypeScript/issues/51909) are not supported.
325
- - `exactOptionalPropertyTypes` is currently not fully supported.
326
- If used, narrowing members of Fluid Framework types types using `in`, `Reflect.has`, `Object.hasOwn` or `Object.prototype.hasOwnProperty` should be avoided as they may incorrectly exclude `undefined` from the possible values in some cases.
328
+ - [TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0):
329
+ - Fluid Framework supports all [`strict`](https://www.typescriptlang.org/tsconfig) options.
330
+ - Set the build targets (`lib`, `target`) to `ES2022` or later.
331
+ - Enable [`strictNullChecks`](https://www.typescriptlang.org/tsconfig).
332
+ - Fluid Framework does not support [configuration options deprecated in TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0#breaking-changes-and-deprecations-in-typescript-6-0).
333
+ - Fluid Framework does not fully support `exactOptionalPropertyTypes`.
334
+ If you enable this option, do not use `in`, `Reflect.has`, `Object.hasOwn`, or `Object.prototype.hasOwnProperty` to narrow members of Fluid Framework types.
335
+ These methods can incorrectly exclude `undefined` from the possible values.
327
336
  - [webpack](https://webpack.js.org/) 5
328
- - We are not intending to be prescriptive about what bundler to use.
329
- Other bundlers which can handle ES Modules should work, but webpack is the only one we actively test.
337
+ - We do not require a specific bundler.
338
+ Other bundlers that handle ES Modules can work, but we actively test only webpack.
330
339
 
331
340
  ### Module Resolution
332
341
 
333
- [`Node16`, `NodeNext`, or `Bundler`](https://www.typescriptlang.org/tsconfig#moduleResolution) resolution should be used with TypeScript compilerOptions to follow the [Node.js v12+ ESM Resolution and Loading algorithm](https://nodejs.github.io/nodejs.dev/en/api/v20/esm/#resolution-and-loading-algorithm).
334
- Node10 resolution is not supported as it does not support Fluid Framework's API structuring pattern that is used to distinguish stable APIs from those that are in development.
342
+ In TypeScript `compilerOptions`, use [`Node16`, `Node20`, `NodeNext`, or `Bundler`](https://www.typescriptlang.org/tsconfig#moduleResolution) module resolution.
343
+ These settings follow the [Node.js v12+ ESM Resolution and Loading algorithm](https://nodejs.github.io/nodejs.dev/en/api/v20/esm/#resolution-and-loading-algorithm).
344
+
345
+ Do not use `Node10` module resolution.
335
346
 
336
347
  ### Module Formats
337
348
 
338
349
  - ES Modules:
339
- ES Modules are the preferred way to consume our client packages (including in NodeJs) and consuming our client packages from ES Modules is fully supported.
340
- - CommonJs:
341
- Consuming our client packages as CommonJs is supported only in NodeJS and only for the cases listed below.
342
- This is done to accommodate some workflows without good ES Module support.
343
- If you have a workflow you would like included in this list, file an issue.
344
- Once this list of workflows motivating CommonJS support is empty, we may drop support for CommonJS one year after notice of the change is posted here.
345
-
346
- - Testing with Jest (which lacks [stable ESM support](https://jestjs.io/docs/ecmascript-modules) due to [unstable APIs in NodeJs](https://github.com/nodejs/node/issues/37648))
350
+ Use ES Modules to consume Fluid Framework client packages, including in Node.js.
351
+ - CommonJS:
352
+ Fluid Framework does not officially support CommonJS in version 3.0 or later.
347
353
 
348
354
  ## Contribution Guidelines
349
355
 
350
- There are many ways to [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid.
356
+ You can [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid Framework in these ways:
351
357
 
352
- - Participate in Q&A in our [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
353
- - [Submit bugs](https://github.com/microsoft/FluidFramework/issues) and help us verify fixes as they are checked in.
354
- - Review the [source code changes](https://github.com/microsoft/FluidFramework/pulls).
358
+ - Answer questions in [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
359
+ - [Submit bug reports](https://github.com/microsoft/FluidFramework/issues) and help verify fixes.
360
+ - Review [source code changes](https://github.com/microsoft/FluidFramework/pulls).
355
361
  - [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).
356
362
 
357
- Detailed instructions for working in the repo can be found in the [Wiki](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
363
+ For detailed instructions, read the [repo documentation](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
358
364
 
359
- This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
360
- For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
365
+ This project follows the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
366
+ For more information, read the [Code of Conduct frequently asked questions](https://opensource.microsoft.com/codeofconduct/faq/).
367
+ For questions or comments, contact [opencode@microsoft.com](mailto:opencode@microsoft.com).
361
368
 
362
369
  This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
363
370
  Use of these trademarks or logos must follow Microsoft’s [Trademark & Brand Guidelines](https://www.microsoft.com/trademarks).
@@ -365,13 +372,9 @@ Use of Microsoft trademarks or logos in modified versions of this project must n
365
372
 
366
373
  ## Help
367
374
 
368
- Not finding what you're looking for in this README?
369
- Check out [fluidframework.com](https://fluidframework.com/docs/).
370
-
371
- Still not finding what you're looking for?
372
- Please [file an issue](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Contributing/Submitting-Bugs-and-Feature-Requests.md).
375
+ Read the [Fluid Framework documentation](https://fluidframework.com/docs/) for information about Fluid Framework concepts and APIs.
373
376
 
374
- Thank you!
377
+ To request information that the documentation does not contain, [create an issue](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Contributing/Submitting-Bugs-and-Feature-Requests.md).
375
378
 
376
379
  ## Trademark
377
380
 
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
- "extends": "../../../common/build/build-common/api-extractor-model.esm.json"
3
+ "extends": "<projectFolder>/../../../common/build/build-common/api-extractor-model.esm.json"
4
4
  }
@@ -49,6 +49,7 @@ export interface IBaseProtocolHandler {
49
49
 
50
50
  // @alpha @legacy
51
51
  export interface ICaptureFullContainerStateProps {
52
+ readonly blobCaptureMode?: "inline" | "reference" | undefined;
52
53
  readonly documentServiceFactory: IDocumentServiceFactory;
53
54
  readonly logger?: ITelemetryBaseLogger | undefined;
54
55
  readonly request: IRequest;
@@ -240,13 +241,13 @@ export interface OnDemandSummaryResults {
240
241
 
241
242
  // @alpha @legacy
242
243
  export class PendingLocalStateStore<TKey> {
243
- [Symbol.iterator](): Iterator<[TKey, string]>;
244
+ [Symbol.iterator](): FluidIterableIterator<[TKey, string]>;
244
245
  clear(): void;
245
246
  delete(key: TKey): boolean;
246
- entries(): Iterator<[TKey, string]>;
247
+ entries(): FluidIterableIterator<[TKey, string]>;
247
248
  get(key: TKey): string | undefined;
248
249
  has(key: TKey): boolean;
249
- keys(): IterableIterator<TKey>;
250
+ keys(): FluidIterableIterator<TKey>;
250
251
  set(key: TKey, pendingLocalState: string): this;
251
252
  get size(): number;
252
253
  }
@@ -1 +1 @@
1
- {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../src/attachment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAEpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EACX,uBAAuB,EACvB,SAAS,EACT,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AAE3F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAGxE;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,gCAAgC;IAChD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,6BAA6B,CAAC;CAChD;AAED;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,6BAA6B,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACvB,mBAAmB,GACnB,gCAAgC,GAChC,yBAAyB,GACzB,sBAAsB,GACtB,YAAY,CAAC;AAEhB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAEtE;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,IAAI,CAAC;IAErE;;;;;OAKG;IACH,QAAQ,CAAC,yBAAyB,EAAE,CACnC,IAAI,EAAE,YAAY,GAAG,SAAS,KAC1B,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,YAAY,GAAG,0BAA0B,CAAC,CAAC,CAAC;IAEvF;;OAEG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAClC,yBAAyB,EACzB,YAAY,GAAG,UAAU,GAAG,MAAM,CAClC,CAAC;IAEF;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE,CACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B,6BAA6B,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,2HAMnC,kBAAkB,KAAG,QAAQ,SAAS,CA4ExC,CAAC"}
1
+ {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../src/attachment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAEpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EACX,uBAAuB,EACvB,SAAS,EACT,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AAE3F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAGxE;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,gCAAgC;IAChD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,6BAA6B,CAAC;CAChD;AAED;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,6BAA6B,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACvB,mBAAmB,GACnB,gCAAgC,GAChC,yBAAyB,GACzB,sBAAsB,GACtB,YAAY,CAAC;AAEhB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAEtE;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,IAAI,CAAC;IAErE;;;;;OAKG;IACH,QAAQ,CAAC,yBAAyB,EAAE,CACnC,IAAI,EAAE,YAAY,GAAG,SAAS,KAC1B,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,YAAY,GAAG,0BAA0B,CAAC,CAAC,CAAC;IAEvF;;OAEG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAClC,yBAAyB,EACzB,YAAY,GAAG,UAAU,GAAG,MAAM,CAClC,CAAC;IAEF;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE,CACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B,6BAA6B,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GAAU,wHAM7C,kBAAkB,KAAG,OAAO,CAAC,SAAS,CA4ExC,CAAC"}
package/dist/audience.js CHANGED
@@ -11,9 +11,10 @@ const internal_1 = require("@fluidframework/core-utils/internal");
11
11
  * Audience represents all clients connected to the op stream.
12
12
  */
13
13
  class Audience extends client_utils_1.TypedEventEmitter {
14
+ members = new Map();
15
+ _currentClientId;
14
16
  constructor() {
15
17
  super();
16
- this.members = new Map();
17
18
  // We are expecting this class to have many listeners, so we suppress noisy "MaxListenersExceededWarning" logging.
18
19
  super.setMaxListeners(0);
19
20
  }
@@ -32,7 +33,7 @@ class Audience extends client_utils_1.TypedEventEmitter {
32
33
  // this.getMember(clientId) could resolve to undefined in these two cases:
33
34
  // 1) Feature gates controlling ConnectionStateHandler() behavior are off
34
35
  // 2) we are loading from stashed state and audience is empty, but we remember and set prior clientId
35
- this.emit("selfChanged", oldId === undefined ? undefined : ({ clientId: oldId }), { clientId, client: this.getMember(clientId) });
36
+ this.emit("selfChanged", oldId === undefined ? undefined : { clientId: oldId }, { clientId, client: this.getMember(clientId) });
36
37
  }
37
38
  }
38
39
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"audience.js","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AAGjE,kEAA6D;AAG7D;;GAEG;AACH,MAAa,QAAS,SAAQ,gCAAkC;IAI/D;QACC,KAAK,EAAE,CAAC;QAJQ,YAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;QAKrD,kHAAkH;QAClH,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAEM,OAAO;QACb,OAAO,IAAI,CAAC,gBAAgB,KAAK,SAAS;YACzC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC;gBACA,QAAQ,EAAE,IAAI,CAAC,gBAAgB;gBAC/B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC;aAC7C,CAAC;IACL,CAAC;IAEM,kBAAkB,CAAC,QAAgB;QACzC,IAAI,IAAI,CAAC,gBAAgB,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC;YACpC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;YACjC,0EAA0E;YAC1E,yEAAyE;YACzE,qGAAqG;YACrG,IAAI,CAAC,IAAI,CACR,aAAa,EACb,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAkB,CAAC,EACvE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAkB,CAC9D,CAAC;QACH,CAAC;IACF,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,OAAgB;QAClD,mGAAmG;QACnG,+FAA+F;QAC/F,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAA,iBAAM,EACL,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAClD,KAAK,CAAC,wDAAwD,CAC9D,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,YAAY,CAAC,QAAgB;QACnC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACd,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,UAAU;QAChB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;OAKG;IACI,SAAS,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;CACD;AAtFD,4BAsFC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IAudienceEvents, ISelf } from \"@fluidframework/container-definitions\";\nimport type { IAudienceOwner } from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\n\n/**\n * Audience represents all clients connected to the op stream.\n */\nexport class Audience extends TypedEventEmitter<IAudienceEvents> implements IAudienceOwner {\n\tprivate readonly members = new Map<string, IClient>();\n\tprivate _currentClientId: string | undefined;\n\n\tconstructor() {\n\t\tsuper();\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t}\n\n\tpublic getSelf(): ISelf | undefined {\n\t\treturn this._currentClientId === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tclientId: this._currentClientId,\n\t\t\t\t\tclient: this.getMember(this._currentClientId),\n\t\t\t\t};\n\t}\n\n\tpublic setCurrentClientId(clientId: string): void {\n\t\tif (this._currentClientId !== clientId) {\n\t\t\tconst oldId = this._currentClientId;\n\t\t\tthis._currentClientId = clientId;\n\t\t\t// this.getMember(clientId) could resolve to undefined in these two cases:\n\t\t\t// 1) Feature gates controlling ConnectionStateHandler() behavior are off\n\t\t\t// 2) we are loading from stashed state and audience is empty, but we remember and set prior clientId\n\t\t\tthis.emit(\n\t\t\t\t\"selfChanged\",\n\t\t\t\toldId === undefined ? undefined : ({ clientId: oldId } satisfies ISelf),\n\t\t\t\t{ clientId, client: this.getMember(clientId) } satisfies ISelf,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a new client to the audience\n\t */\n\tpublic addMember(clientId: string, details: IClient): void {\n\t\t// Given that signal delivery is unreliable process, we might observe same client being added twice\n\t\t// In such case we should see exactly same payload (IClient), and should not raise event twice!\n\t\tif (this.members.has(clientId)) {\n\t\t\tconst client = this.members.get(clientId);\n\t\t\tassert(\n\t\t\t\tJSON.stringify(client) === JSON.stringify(details),\n\t\t\t\t0x4b2 /* new client has different payload from existing one */,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.members.set(clientId, details);\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a client from the audience. Only emits an event if a client is actually removed\n\t * @returns if a client was removed from the audience\n\t */\n\tpublic removeMember(clientId: string): boolean {\n\t\tconst removedClient = this.members.get(clientId);\n\t\tif (removedClient === undefined) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\tthis.members.delete(clientId);\n\t\t\tthis.emit(\"removeMember\", clientId, removedClient);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all the members in the audience.\n\t *\n\t * @remarks When the container is disconnected, this will keep returning the audience as it was last seen before the\n\t * container disconnected.\n\t */\n\tpublic getMembers(): Map<string, IClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the audience.\n\t *\n\t * @remarks When the container is disconnected, this will keep returning members from the audience as it was last seen\n\t * before the container disconnected.\n\t */\n\tpublic getMember(clientId: string): IClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n}\n"]}
1
+ {"version":3,"file":"audience.js","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AAGjE,kEAA6D;AAG7D;;GAEG;AACH,MAAa,QAAS,SAAQ,gCAAkC;IAC9C,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC9C,gBAAgB,CAAqB;IAE7C;QACC,KAAK,EAAE,CAAC;QACR,kHAAkH;QAClH,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAEM,OAAO;QACb,OAAO,IAAI,CAAC,gBAAgB,KAAK,SAAS;YACzC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC;gBACA,QAAQ,EAAE,IAAI,CAAC,gBAAgB;gBAC/B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC;aAC7C,CAAC;IACL,CAAC;IAEM,kBAAkB,CAAC,QAAgB;QACzC,IAAI,IAAI,CAAC,gBAAgB,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC;YACpC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;YACjC,0EAA0E;YAC1E,yEAAyE;YACzE,qGAAqG;YACrG,IAAI,CAAC,IAAI,CACR,aAAa,EACb,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,EAAE,QAAQ,EAAE,KAAK,EAAmB,EACvE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAkB,CAC9D,CAAC;QACH,CAAC;IACF,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,QAAgB,EAAE,OAAgB;QAClD,mGAAmG;QACnG,+FAA+F;QAC/F,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAA,iBAAM,EACL,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAClD,KAAK,CAAC,wDAAwD,CAC9D,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;IACF,CAAC;IAED;;;OAGG;IACI,YAAY,CAAC,QAAgB;QACnC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACd,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACI,UAAU;QAChB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;OAKG;IACI,SAAS,CAAC,QAAgB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;CACD;AAtFD,4BAsFC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport type { IAudienceEvents, ISelf } from \"@fluidframework/container-definitions\";\nimport type { IAudienceOwner } from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\n\n/**\n * Audience represents all clients connected to the op stream.\n */\nexport class Audience extends TypedEventEmitter<IAudienceEvents> implements IAudienceOwner {\n\tprivate readonly members = new Map<string, IClient>();\n\tprivate _currentClientId: string | undefined;\n\n\tconstructor() {\n\t\tsuper();\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t}\n\n\tpublic getSelf(): ISelf | undefined {\n\t\treturn this._currentClientId === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tclientId: this._currentClientId,\n\t\t\t\t\tclient: this.getMember(this._currentClientId),\n\t\t\t\t};\n\t}\n\n\tpublic setCurrentClientId(clientId: string): void {\n\t\tif (this._currentClientId !== clientId) {\n\t\t\tconst oldId = this._currentClientId;\n\t\t\tthis._currentClientId = clientId;\n\t\t\t// this.getMember(clientId) could resolve to undefined in these two cases:\n\t\t\t// 1) Feature gates controlling ConnectionStateHandler() behavior are off\n\t\t\t// 2) we are loading from stashed state and audience is empty, but we remember and set prior clientId\n\t\t\tthis.emit(\n\t\t\t\t\"selfChanged\",\n\t\t\t\toldId === undefined ? undefined : ({ clientId: oldId } satisfies ISelf),\n\t\t\t\t{ clientId, client: this.getMember(clientId) } satisfies ISelf,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a new client to the audience\n\t */\n\tpublic addMember(clientId: string, details: IClient): void {\n\t\t// Given that signal delivery is unreliable process, we might observe same client being added twice\n\t\t// In such case we should see exactly same payload (IClient), and should not raise event twice!\n\t\tif (this.members.has(clientId)) {\n\t\t\tconst client = this.members.get(clientId);\n\t\t\tassert(\n\t\t\t\tJSON.stringify(client) === JSON.stringify(details),\n\t\t\t\t0x4b2 /* new client has different payload from existing one */,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.members.set(clientId, details);\n\t\t\tthis.emit(\"addMember\", clientId, details);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a client from the audience. Only emits an event if a client is actually removed\n\t * @returns if a client was removed from the audience\n\t */\n\tpublic removeMember(clientId: string): boolean {\n\t\tconst removedClient = this.members.get(clientId);\n\t\tif (removedClient === undefined) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\tthis.members.delete(clientId);\n\t\t\tthis.emit(\"removeMember\", clientId, removedClient);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all the members in the audience.\n\t *\n\t * @remarks When the container is disconnected, this will keep returning the audience as it was last seen before the\n\t * container disconnected.\n\t */\n\tpublic getMembers(): Map<string, IClient> {\n\t\treturn new Map(this.members);\n\t}\n\n\t/**\n\t * Retrieves a specific member of the audience.\n\t *\n\t * @remarks When the container is disconnected, this will keep returning members from the audience as it was last seen\n\t * before the container disconnected.\n\t */\n\tpublic getMember(clientId: string): IClient | undefined {\n\t\treturn this.members.get(clientId);\n\t}\n}\n"]}
@@ -4,7 +4,15 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.snapshotHasLoadingGroups = exports.inlineAttachmentBlobsByReference = exports.unreferencedAttachmentBlobLocalIds = exports.extractBlobAttachReferences = exports.captureReferencedAttachmentBlobs = exports.readReferencedSnapshotBlobs = exports.parseGcSnapshotData = exports.mapWithConcurrency = exports.wireFormatConstants = void 0;
7
+ exports.wireFormatConstants = void 0;
8
+ exports.mapWithConcurrency = mapWithConcurrency;
9
+ exports.parseGcSnapshotData = parseGcSnapshotData;
10
+ exports.readReferencedSnapshotBlobs = readReferencedSnapshotBlobs;
11
+ exports.captureReferencedAttachmentBlobs = captureReferencedAttachmentBlobs;
12
+ exports.extractBlobAttachReferences = extractBlobAttachReferences;
13
+ exports.unreferencedAttachmentBlobLocalIds = unreferencedAttachmentBlobLocalIds;
14
+ exports.inlineAttachmentBlobsByReference = inlineAttachmentBlobsByReference;
15
+ exports.snapshotHasLoadingGroups = snapshotHasLoadingGroups;
8
16
  const client_utils_1 = require("@fluid-internal/client-utils");
9
17
  const internal_1 = require("@fluidframework/driver-utils/internal");
10
18
  /**
@@ -63,7 +71,6 @@ async function mapWithConcurrency(items, limit, fn) {
63
71
  await Promise.all(workers);
64
72
  return results;
65
73
  }
66
- exports.mapWithConcurrency = mapWithConcurrency;
67
74
  /**
68
75
  * Parses the `gc` subtree of a base snapshot. Returns `undefined` if the
69
76
  * snapshot has no GC tree (GC disabled or pre-GC document).
@@ -97,7 +104,6 @@ async function parseGcSnapshotData(baseSnapshot, storage) {
97
104
  }
98
105
  return { gcState, tombstones, deletedNodes };
99
106
  }
100
- exports.parseGcSnapshotData = parseGcSnapshotData;
101
107
  /**
102
108
  * Walks a snapshot and inlines the contents of every blob reachable without
103
109
  * crossing an `unreferenced` subtree boundary. Subtrees flagged
@@ -120,7 +126,6 @@ async function readReferencedSnapshotBlobs(snapshot, storage) {
120
126
  });
121
127
  return blobs;
122
128
  }
123
- exports.readReferencedSnapshotBlobs = readReferencedSnapshotBlobs;
124
129
  /**
125
130
  * Synchronously walks the snapshot tree and gathers the set of blob ids that
126
131
  * should be inlined. Subtrees flagged `unreferenced: true` are skipped
@@ -198,7 +203,6 @@ async function captureReferencedAttachmentBlobs(baseSnapshot, storage, gcData) {
198
203
  });
199
204
  return contents;
200
205
  }
201
- exports.captureReferencedAttachmentBlobs = captureReferencedAttachmentBlobs;
202
206
  /**
203
207
  * Reconstructs the BlobManager's redirect table from a `.blobs` subtree.
204
208
  * Mirrors `toRedirectTable` in blobManagerSnapSum.ts.
@@ -277,7 +281,6 @@ function extractBlobAttachReferences(op) {
277
281
  }
278
282
  return [{ localId: op.metadata.localId, storageId: op.metadata.blobId }];
279
283
  }
280
- exports.extractBlobAttachReferences = extractBlobAttachReferences;
281
284
  /**
282
285
  * Set of attachment-blob localIds that GC has marked unreferenced,
283
286
  * tombstoned, or deleted in the base snapshot. `undefined` if `gcData`
@@ -288,7 +291,6 @@ exports.extractBlobAttachReferences = extractBlobAttachReferences;
288
291
  function unreferencedAttachmentBlobLocalIds(gcData) {
289
292
  return gcData === undefined ? undefined : collectUnreferencedBlobLocalIds(gcData);
290
293
  }
291
- exports.unreferencedAttachmentBlobLocalIds = unreferencedAttachmentBlobLocalIds;
292
294
  /**
293
295
  * Inline attachment blob contents for the given `(localId, storageId)`
294
296
  * references. Skips entries already present in `existing` (de-dupe with
@@ -319,7 +321,6 @@ async function inlineAttachmentBlobsByReference(references, storage, unreference
319
321
  });
320
322
  return added;
321
323
  }
322
- exports.inlineAttachmentBlobsByReference = inlineAttachmentBlobsByReference;
323
324
  /**
324
325
  * Returns true if any referenced subtree of `baseSnapshot` declares a
325
326
  * `groupId` — the snapshot-tree wire field that carries the runtime's
@@ -345,5 +346,4 @@ function snapshotHasLoadingGroups(baseSnapshot) {
345
346
  }
346
347
  return false;
347
348
  }
348
- exports.snapshotHasLoadingGroups = snapshotHasLoadingGroups;
349
349
  //# sourceMappingURL=captureReferencedContents.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureReferencedContents.js","sourceRoot":"","sources":["../src/captureReferencedContents.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAA8D;AAO9D,oEAAqE;AAOrE;;;;;;;;;;;;;;GAcG;AACU,QAAA,mBAAmB,GAAG;IAClC,aAAa,EAAE,QAAQ;IACvB,qBAAqB,EAAE,gBAAgB;IACvC,mBAAmB,EAAE,QAAQ;IAC7B,SAAS,EAAE,IAAI;IACf,YAAY,EAAE,MAAM;IACpB,kBAAkB,EAAE,cAAc;IAClC,gBAAgB,EAAE,gBAAgB;CACzB,CAAC;AAEX,MAAM,EACL,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,SAAS,EACT,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,GAChB,GAAG,2BAAmB,CAAC;AAuBxB;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B;;;;;;;GAOG;AACI,KAAK,UAAU,kBAAkB,CACvC,KAAmB,EACnB,KAAa,EACb,EAA2B;IAE3B,MAAM,OAAO,GAAQ,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,IAAI,EAAE;QAC9D,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AAChB,CAAC;AAnBD,gDAmBC;AAED;;;GAGG;AACI,KAAK,UAAU,mBAAmB,CACxC,YAA2B,EAC3B,OAAkD;IAElD,MAAM,cAAc,GAA8B,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAChF,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,OAA6B,CAAC;IAClC,IAAI,UAAgC,CAAC;IACrC,IAAI,YAAkC,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAClE,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;YAC9B,YAAY,GAAG,MAAM,IAAA,uBAAY,EAAW,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC;aAAM,IAAI,GAAG,KAAK,kBAAkB,EAAE,CAAC;YACvC,UAAU,GAAG,MAAM,IAAA,uBAAY,EAAW,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,MAAM,IAAA,uBAAY,EAAW,OAAO,EAAE,MAAM,CAAC,CAAC;YAC9D,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACP,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBAClE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC;gBACtC,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAC9C,CAAC;AA5BD,kDA4BC;AAED;;;;;;;;;;GAUG;AACI,KAAK,UAAU,2BAA2B,CAChD,QAAmC,EACnC,OAAkD;IAElD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QACnE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5B,KAAK,CAAC,EAAE,CAAC,GAAG,IAAA,6BAAc,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACd,CAAC;AAbD,kEAaC;AAED;;;;;;GAMG;AACH,SAAS,wBAAwB,CAChC,IAAmB,EACnB,MAAe,EACf,GAAgB;IAEhB,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QAChC,OAAO;IACR,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,IAAI,MAAM,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YACrC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACzD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC/B,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACtB,CAAC;QACF,CAAC;aAAM,CAAC;YACP,wBAAwB,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/C,CAAC;IACF,CAAC;AACF,CAAC;AAED,SAAS,eAAe,CACvB,QAAmC,EACnC,OAAkD;IAElD,IAAI,cAAc,IAAI,QAAQ,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;QAC3C,OAAO;YACN,IAAI,EAAE,QAAQ,CAAC,YAAY;YAC3B,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;SAChE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACI,KAAK,UAAU,gCAAgC,CACrD,YAA2B,EAC3B,OAAkD,EAClD,MAAmC;IAEnC,MAAM,SAAS,GAA8B,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC/E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,kBAAkB,GAAG,MAAM,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACvE,IAAI,kBAAkB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,oBAAoB,GACzB,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,+BAA+B,CAAC,MAAM,CAAC,CAAC;IAE5E,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,KAAK,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,kBAAkB,EAAE,CAAC;QACvD,IAAI,oBAAoB,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;YACjD,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;IACF,CAAC;IAED,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,MAAM,kBAAkB,CAAC,CAAC,GAAG,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;QACxF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjD,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAA,6BAAc,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AACjB,CAAC;AA9BD,4EA8BC;AAED;;;GAGG;AACH,KAAK,UAAU,iBAAiB,CAC/B,SAAwB,EACxB,OAAkD;IAElD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,MAAM,WAAW,GAAuB,SAAS,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC/E,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAA,uBAAY,EAAqB,OAAO,EAAE,WAAW,CAAC,CAAC;QAC7E,KAAK,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,OAAO,EAAE,CAAC;YAC5C,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;IACF,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,IAAI,GAAG,KAAK,qBAAqB,EAAE,CAAC;YACnC,yEAAyE;YACzE,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;IACD,OAAO,aAAa,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,+BAA+B,CAAC,MAAuB;IAC/D,MAAM,cAAc,GAAG,IAAI,mBAAmB,GAAG,CAAC;IAClD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3E,IACC,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC;gBACnC,QAAQ,CAAC,uBAAuB,KAAK,SAAS,EAC7C,CAAC;gBACF,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;YACzD,CAAC;QACF,CAAC;IACF,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACvF,IAAI,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QACzD,CAAC;IACF,CAAC;IACD,OAAO,YAAY,CAAC;AACrB,CAAC;AAmBD,SAAS,wBAAwB,CAAC,QAAiB;IAClD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,QAAmD,CAAC;IACtE,OAAO,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,CAAC;AACtF,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,2BAA2B,CAC1C,EAA+C;IAE/C,IAAI,CAAC,wBAAwB,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5C,OAAO,EAAE,CAAC;IACX,CAAC;IACD,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AAC1E,CAAC;AAPD,kEAOC;AAED;;;;;;GAMG;AACH,SAAgB,kCAAkC,CACjD,MAAmC;IAEnC,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,+BAA+B,CAAC,MAAM,CAAC,CAAC;AACnF,CAAC;AAJD,gFAIC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,gCAAgC,CACrD,UAA2C,EAC3C,OAAkD,EAClD,oBAAqD,EACrD,QAAuC;IAEvC,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,KAAK,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,UAAU,EAAE,CAAC;QACjD,IAAI,oBAAoB,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;YACjD,SAAS;QACV,CAAC;QACD,IAAI,QAAQ,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;YACvC,SAAS;QACV,CAAC;QACD,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,IAAI,iBAAiB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,kBAAkB,CAAC,CAAC,GAAG,iBAAiB,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;QACxF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjD,KAAK,CAAC,SAAS,CAAC,GAAG,IAAA,6BAAc,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACd,CAAC;AAzBD,4EAyBC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,wBAAwB,CAAC,YAA2B;IACnE,IAAI,YAAY,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,YAAY,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,IAAI,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAbD,4DAaC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { bufferToString } from \"@fluid-internal/client-utils\";\nimport type {\n\tIDocumentStorageService,\n\tISequencedDocumentMessage,\n\tISnapshot,\n\tISnapshotTree,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\n\nimport type {\n\tIBase64BlobContents,\n\tISerializableBlobContents,\n} from \"./containerStorageAdapter.js\";\n\n/**\n * Wire-format constants this module needs to walk and filter snapshots.\n * Authoritative definitions live in `container-runtime` and\n * `runtime-definitions`; the values are duplicated here to avoid a\n * loader → runtime layering dependency. A contract test in\n * `packages/test/local-server-tests` asserts these match the authoritative\n * values; do not change them in isolation.\n *\n * Authoritative sources:\n * - `blobsTreeName`, `redirectTableBlobName`: `packages/runtime/container-runtime/src/blobManager/blobManagerSnapSum.ts`\n * - `blobManagerBasePath`: `packages/runtime/container-runtime/src/blobManager/blobManager.ts`\n * - `gcTreeKey`, `gcBlobPrefix`, `gcTombstoneBlobKey`, `gcDeletedBlobKey`: `packages/runtime/runtime-definitions/src/garbageCollectionDefinitions.ts`\n *\n * @internal\n */\nexport const wireFormatConstants = {\n\tblobsTreeName: \".blobs\",\n\tredirectTableBlobName: \".redirectTable\",\n\tblobManagerBasePath: \"_blobs\",\n\tgcTreeKey: \"gc\",\n\tgcBlobPrefix: \"__gc\",\n\tgcTombstoneBlobKey: \"__tombstones\",\n\tgcDeletedBlobKey: \"__deletedNodes\",\n} as const;\n\nconst {\n\tblobsTreeName,\n\tredirectTableBlobName,\n\tblobManagerBasePath,\n\tgcTreeKey,\n\tgcBlobPrefix,\n\tgcTombstoneBlobKey,\n\tgcDeletedBlobKey,\n} = wireFormatConstants;\n\ninterface IGcNodeData {\n\toutboundRoutes: string[];\n\tunreferencedTimestampMs?: number;\n}\n\ninterface IGcState {\n\tgcNodes: { [id: string]: IGcNodeData };\n}\n\n/**\n * The parsed subset of the `gc` subtree that drives reachability decisions.\n */\nexport interface IGcSnapshotData {\n\tgcState: IGcState | undefined;\n\ttombstones: string[] | undefined;\n\tdeletedNodes: string[] | undefined;\n}\n\n/** Reader that returns a blob's contents for a given storage id. */\ntype BlobReader = (id: string) => Promise<ArrayBufferLike>;\n\n/**\n * Upper bound on concurrent `readBlob` calls. Driver/service back-pressure is\n * real for large documents, and unbounded `Promise.all` can trigger throttling\n * or spike memory. The value is a pragmatic middle ground — high enough to\n * keep a typical driver's request pipeline full, low enough to avoid storms.\n */\nconst maxReadConcurrency = 32;\n\n/**\n * Runs `fn` over `items` with at most `limit` promises in flight. Preserves\n * input order on output (not that any caller depends on it today).\n *\n * Exported for unit tests; not part of the package public API.\n *\n * @internal\n */\nexport async function mapWithConcurrency<T, R>(\n\titems: readonly T[],\n\tlimit: number,\n\tfn: (item: T) => Promise<R>,\n): Promise<R[]> {\n\tconst results: R[] = Array.from({ length: items.length });\n\tlet cursor = 0;\n\tconst workerCount = Math.min(limit, items.length);\n\tconst workers = Array.from({ length: workerCount }, async () => {\n\t\twhile (cursor < items.length) {\n\t\t\tconst index = cursor++;\n\t\t\tconst item = items[index];\n\t\t\tif (item !== undefined) {\n\t\t\t\tresults[index] = await fn(item);\n\t\t\t}\n\t\t}\n\t});\n\tawait Promise.all(workers);\n\treturn results;\n}\n\n/**\n * Parses the `gc` subtree of a base snapshot. Returns `undefined` if the\n * snapshot has no GC tree (GC disabled or pre-GC document).\n */\nexport async function parseGcSnapshotData(\n\tbaseSnapshot: ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): Promise<IGcSnapshotData | undefined> {\n\tconst gcSnapshotTree: ISnapshotTree | undefined = baseSnapshot.trees[gcTreeKey];\n\tif (gcSnapshotTree === undefined) {\n\t\treturn undefined;\n\t}\n\tlet gcState: IGcState | undefined;\n\tlet tombstones: string[] | undefined;\n\tlet deletedNodes: string[] | undefined;\n\tfor (const [key, blobId] of Object.entries(gcSnapshotTree.blobs)) {\n\t\tif (key === gcDeletedBlobKey) {\n\t\t\tdeletedNodes = await readAndParse<string[]>(storage, blobId);\n\t\t} else if (key === gcTombstoneBlobKey) {\n\t\t\ttombstones = await readAndParse<string[]>(storage, blobId);\n\t\t} else if (key.startsWith(gcBlobPrefix)) {\n\t\t\tconst partial = await readAndParse<IGcState>(storage, blobId);\n\t\t\tif (gcState === undefined) {\n\t\t\t\tgcState = { gcNodes: { ...partial.gcNodes } };\n\t\t\t} else {\n\t\t\t\tfor (const [nodeId, nodeData] of Object.entries(partial.gcNodes)) {\n\t\t\t\t\tgcState.gcNodes[nodeId] ??= nodeData;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn { gcState, tombstones, deletedNodes };\n}\n\n/**\n * Walks a snapshot and inlines the contents of every blob reachable without\n * crossing an `unreferenced` subtree boundary. Subtrees flagged\n * `unreferenced: true` are skipped entirely — the summarizer sets that flag\n * from GC state, so honouring it filters out dead subtrees without a\n * separate GC-path traversal.\n *\n * The root-level `.blobs` subtree is special-cased: only its `.redirectTable`\n * blob is read, because attachment blob contents are captured separately via\n * {@link captureReferencedAttachmentBlobs}.\n */\nexport async function readReferencedSnapshotBlobs(\n\tsnapshot: ISnapshot | ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): Promise<ISerializableBlobContents> {\n\tconst { tree, read } = toTreeAndReader(snapshot, storage);\n\tconst ids = new Set<string>();\n\tcollectReferencedBlobIds(tree, true, ids);\n\tconst blobs: ISerializableBlobContents = {};\n\tawait mapWithConcurrency([...ids], maxReadConcurrency, async (id) => {\n\t\tconst data = await read(id);\n\t\tblobs[id] = bufferToString(data, \"utf8\");\n\t});\n\treturn blobs;\n}\n\n/**\n * Synchronously walks the snapshot tree and gathers the set of blob ids that\n * should be inlined. Subtrees flagged `unreferenced: true` are skipped\n * entirely. The root-level `.blobs` subtree is special-cased: only its\n * `.redirectTable` id is collected, because attachment blob contents are\n * captured separately via {@link captureReferencedAttachmentBlobs}.\n */\nfunction collectReferencedBlobIds(\n\ttree: ISnapshotTree,\n\tisRoot: boolean,\n\tids: Set<string>,\n): void {\n\tif (tree.unreferenced === true) {\n\t\treturn;\n\t}\n\tfor (const blobId of Object.values(tree.blobs)) {\n\t\tids.add(blobId);\n\t}\n\tfor (const [key, subTree] of Object.entries(tree.trees)) {\n\t\tif (isRoot && key === blobsTreeName) {\n\t\t\tconst tableBlobId = subTree.blobs[redirectTableBlobName];\n\t\t\tif (tableBlobId !== undefined) {\n\t\t\t\tids.add(tableBlobId);\n\t\t\t}\n\t\t} else {\n\t\t\tcollectReferencedBlobIds(subTree, false, ids);\n\t\t}\n\t}\n}\n\nfunction toTreeAndReader(\n\tsnapshot: ISnapshot | ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): { tree: ISnapshotTree; read: BlobReader } {\n\tif (\"snapshotTree\" in snapshot) {\n\t\tconst blobContents = snapshot.blobContents;\n\t\treturn {\n\t\t\ttree: snapshot.snapshotTree,\n\t\t\tread: async (id) => blobContents.get(id) ?? storage.readBlob(id),\n\t\t};\n\t}\n\treturn { tree: snapshot, read: async (id) => storage.readBlob(id) };\n}\n\n/**\n * Fetches attachment blob contents from a snapshot, filtered by GC\n * reachability. Blobs GC has explicitly marked unreferenced, tombstoned, or\n * deleted are skipped. Blobs absent from the GC graph are kept — GC state\n * lags behind recent attachments and dropping them would lose live data.\n * If `gcData` is `undefined`, every attachment blob is returned.\n *\n * The returned map is keyed by attachment blob storage id. Values are the\n * raw bytes encoded as **base64** strings — attachment blobs may carry\n * arbitrary binary payloads (images, encrypted data, etc.) and a\n * UTF-8 round-trip would silently corrupt non-UTF-8 byte sequences with\n * replacement characters. The runtime's own pending-blob serializer uses\n * base64 for the same reason. This diverges from the structural-blob path\n * in {@link readReferencedSnapshotBlobs}, which encodes UTF-8 because those\n * blobs are JSON or other text the runtime authored. Callers must keep the\n * two encodings on separate fields of the pending state so the load side\n * can decode each correctly.\n */\nexport async function captureReferencedAttachmentBlobs(\n\tbaseSnapshot: ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\tgcData: IGcSnapshotData | undefined,\n): Promise<IBase64BlobContents> {\n\tconst blobsTree: ISnapshotTree | undefined = baseSnapshot.trees[blobsTreeName];\n\tif (blobsTree === undefined) {\n\t\treturn {};\n\t}\n\tconst localIdToStorageId = await readRedirectTable(blobsTree, storage);\n\tif (localIdToStorageId.size === 0) {\n\t\treturn {};\n\t}\n\n\tconst unreferencedLocalIds =\n\t\tgcData === undefined ? undefined : collectUnreferencedBlobLocalIds(gcData);\n\n\tconst storageIdsToFetch = new Set<string>();\n\tfor (const [localId, storageId] of localIdToStorageId) {\n\t\tif (unreferencedLocalIds?.has(localId) !== true) {\n\t\t\tstorageIdsToFetch.add(storageId);\n\t\t}\n\t}\n\n\tconst contents: IBase64BlobContents = {};\n\tawait mapWithConcurrency([...storageIdsToFetch], maxReadConcurrency, async (storageId) => {\n\t\tconst buffer = await storage.readBlob(storageId);\n\t\tcontents[storageId] = bufferToString(buffer, \"base64\");\n\t});\n\treturn contents;\n}\n\n/**\n * Reconstructs the BlobManager's redirect table from a `.blobs` subtree.\n * Mirrors `toRedirectTable` in blobManagerSnapSum.ts.\n */\nasync function readRedirectTable(\n\tblobsTree: ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): Promise<Map<string, string>> {\n\tconst redirectTable = new Map<string, string>();\n\tconst tableBlobId: string | undefined = blobsTree.blobs[redirectTableBlobName];\n\tif (tableBlobId !== undefined) {\n\t\tconst entries = await readAndParse<[string, string][]>(storage, tableBlobId);\n\t\tfor (const [localId, storageId] of entries) {\n\t\t\tredirectTable.set(localId, storageId);\n\t\t}\n\t}\n\tfor (const [key, storageId] of Object.entries(blobsTree.blobs)) {\n\t\tif (key !== redirectTableBlobName) {\n\t\t\t// Identity mapping: storage ids referenced directly in handles (legacy).\n\t\t\tredirectTable.set(storageId, storageId);\n\t\t}\n\t}\n\treturn redirectTable;\n}\n\n/**\n * Collects the set of blob localIds that GC has explicitly marked as\n * unreferenced (via `unreferencedTimestampMs` on a gc node), tombstoned, or\n * deleted. Tombstones and deletedNodes are applied regardless of whether\n * `gcState` is present — they are authoritative on their own and must not\n * be silently dropped when gc state is absent but tombstone/deleted lists\n * exist.\n */\nfunction collectUnreferencedBlobLocalIds(gcData: IGcSnapshotData): Set<string> {\n\tconst blobPathPrefix = `/${blobManagerBasePath}/`;\n\tconst unreferenced = new Set<string>();\n\tif (gcData.gcState !== undefined) {\n\t\tfor (const [nodePath, nodeData] of Object.entries(gcData.gcState.gcNodes)) {\n\t\t\tif (\n\t\t\t\tnodePath.startsWith(blobPathPrefix) &&\n\t\t\t\tnodeData.unreferencedTimestampMs !== undefined\n\t\t\t) {\n\t\t\t\tunreferenced.add(nodePath.slice(blobPathPrefix.length));\n\t\t\t}\n\t\t}\n\t}\n\tfor (const nodePath of [...(gcData.tombstones ?? []), ...(gcData.deletedNodes ?? [])]) {\n\t\tif (nodePath.startsWith(blobPathPrefix)) {\n\t\t\tunreferenced.add(nodePath.slice(blobPathPrefix.length));\n\t\t}\n\t}\n\treturn unreferenced;\n}\n\n/**\n * A blob reference extracted from a `BlobAttach` op. `localId` is the\n * `BlobManager` GC identity for the blob; `storageId` is the id used for\n * `IDocumentStorageService.readBlob`.\n *\n * @internal\n */\nexport interface IBlobAttachReference {\n\treadonly localId: string;\n\treadonly storageId: string;\n}\n\ninterface IBlobAttachLikeMetadata {\n\treadonly localId: string;\n\treadonly blobId: string;\n}\n\nfunction isBlobAttachLikeMetadata(metadata: unknown): metadata is IBlobAttachLikeMetadata {\n\tif (typeof metadata !== \"object\" || metadata === null) {\n\t\treturn false;\n\t}\n\tconst candidate = metadata as { localId?: unknown; blobId?: unknown };\n\treturn typeof candidate.localId === \"string\" && typeof candidate.blobId === \"string\";\n}\n\n/**\n * Extracts every `BlobAttach` reference an op carries. Returns an empty array\n * for non-blobAttach ops.\n *\n * This is the single place in the loader that interprets the BlobAttach\n * wire format. Capture and load-side reasoning about ops should call into\n * this function rather than reading `op.metadata` directly, so a future\n * protocol change touches one site.\n *\n * BlobAttach ops carry `(localId, storageId)` directly on\n * `ISequencedDocumentMessage.metadata` and are not grouped — the container\n * runtime routes them through a separate `outbox.submitBlobAttach` lane,\n * and `OpGroupingManager.groupBatch` asserts (0x5dd) that no op carrying\n * non-batch metadata enters a grouped batch. If either guarantee changes,\n * extend this function rather than each call site.\n *\n * @internal\n */\nexport function extractBlobAttachReferences(\n\top: Pick<ISequencedDocumentMessage, \"metadata\">,\n): IBlobAttachReference[] {\n\tif (!isBlobAttachLikeMetadata(op.metadata)) {\n\t\treturn [];\n\t}\n\treturn [{ localId: op.metadata.localId, storageId: op.metadata.blobId }];\n}\n\n/**\n * Set of attachment-blob localIds that GC has marked unreferenced,\n * tombstoned, or deleted in the base snapshot. `undefined` if `gcData`\n * is `undefined` (GC disabled / pre-GC document).\n *\n * @internal\n */\nexport function unreferencedAttachmentBlobLocalIds(\n\tgcData: IGcSnapshotData | undefined,\n): Set<string> | undefined {\n\treturn gcData === undefined ? undefined : collectUnreferencedBlobLocalIds(gcData);\n}\n\n/**\n * Inline attachment blob contents for the given `(localId, storageId)`\n * references. Skips entries already present in `existing` (de-dupe with\n * the snapshot path) and entries whose `localId` is in\n * `unreferencedLocalIds`. Returns only the freshly-read entries; the\n * caller merges them into the existing map.\n *\n * @internal\n */\nexport async function inlineAttachmentBlobsByReference(\n\treferences: readonly IBlobAttachReference[],\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\tunreferencedLocalIds: ReadonlySet<string> | undefined,\n\texisting: Readonly<IBase64BlobContents>,\n): Promise<IBase64BlobContents> {\n\tconst storageIdsToFetch = new Set<string>();\n\tfor (const { localId, storageId } of references) {\n\t\tif (unreferencedLocalIds?.has(localId) === true) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (existing[storageId] !== undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tstorageIdsToFetch.add(storageId);\n\t}\n\tconst added: IBase64BlobContents = {};\n\tif (storageIdsToFetch.size === 0) {\n\t\treturn added;\n\t}\n\tawait mapWithConcurrency([...storageIdsToFetch], maxReadConcurrency, async (storageId) => {\n\t\tconst buffer = await storage.readBlob(storageId);\n\t\tadded[storageId] = bufferToString(buffer, \"base64\");\n\t});\n\treturn added;\n}\n\n/**\n * Returns true if any referenced subtree of `baseSnapshot` declares a\n * `groupId` — the snapshot-tree wire field that carries the runtime's\n * loading-group identifier. Subtrees flagged `unreferenced` are skipped —\n * a dead subtree's `groupId` would not be loaded by the runtime either.\n *\n * `captureFullContainerState` does not yet support loading groups: prefetching\n * per-group snapshots adds a code path that has no end-to-end coverage and no\n * known production consumer. Callers use this to fail fast with a `UsageError`\n * rather than silently producing a pending state that omits group data.\n */\nexport function snapshotHasLoadingGroups(baseSnapshot: ISnapshotTree): boolean {\n\tif (baseSnapshot.unreferenced === true) {\n\t\treturn false;\n\t}\n\tif (baseSnapshot.groupId !== undefined) {\n\t\treturn true;\n\t}\n\tfor (const child of Object.values(baseSnapshot.trees)) {\n\t\tif (snapshotHasLoadingGroups(child)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n"]}
1
+ {"version":3,"file":"captureReferencedContents.js","sourceRoot":"","sources":["../src/captureReferencedContents.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 { bufferToString } from \"@fluid-internal/client-utils\";\nimport type {\n\tIDocumentStorageService,\n\tISequencedDocumentMessage,\n\tISnapshot,\n\tISnapshotTree,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\n\nimport type {\n\tIBase64BlobContents,\n\tISerializableBlobContents,\n} from \"./containerStorageAdapter.js\";\n\n/**\n * Wire-format constants this module needs to walk and filter snapshots.\n * Authoritative definitions live in `container-runtime` and\n * `runtime-definitions`; the values are duplicated here to avoid a\n * loader → runtime layering dependency. A contract test in\n * `packages/test/local-server-tests` asserts these match the authoritative\n * values; do not change them in isolation.\n *\n * Authoritative sources:\n * - `blobsTreeName`, `redirectTableBlobName`: `packages/runtime/container-runtime/src/blobManager/blobManagerSnapSum.ts`\n * - `blobManagerBasePath`: `packages/runtime/container-runtime/src/blobManager/blobManager.ts`\n * - `gcTreeKey`, `gcBlobPrefix`, `gcTombstoneBlobKey`, `gcDeletedBlobKey`: `packages/runtime/runtime-definitions/src/garbageCollectionDefinitions.ts`\n *\n * @internal\n */\nexport const wireFormatConstants = {\n\tblobsTreeName: \".blobs\",\n\tredirectTableBlobName: \".redirectTable\",\n\tblobManagerBasePath: \"_blobs\",\n\tgcTreeKey: \"gc\",\n\tgcBlobPrefix: \"__gc\",\n\tgcTombstoneBlobKey: \"__tombstones\",\n\tgcDeletedBlobKey: \"__deletedNodes\",\n} as const;\n\nconst {\n\tblobsTreeName,\n\tredirectTableBlobName,\n\tblobManagerBasePath,\n\tgcTreeKey,\n\tgcBlobPrefix,\n\tgcTombstoneBlobKey,\n\tgcDeletedBlobKey,\n} = wireFormatConstants;\n\ninterface IGcNodeData {\n\toutboundRoutes: string[];\n\tunreferencedTimestampMs?: number;\n}\n\ninterface IGcState {\n\tgcNodes: { [id: string]: IGcNodeData };\n}\n\n/**\n * The parsed subset of the `gc` subtree that drives reachability decisions.\n */\nexport interface IGcSnapshotData {\n\tgcState: IGcState | undefined;\n\ttombstones: string[] | undefined;\n\tdeletedNodes: string[] | undefined;\n}\n\n/** Reader that returns a blob's contents for a given storage id. */\ntype BlobReader = (id: string) => Promise<ArrayBufferLike>;\n\n/**\n * Upper bound on concurrent `readBlob` calls. Driver/service back-pressure is\n * real for large documents, and unbounded `Promise.all` can trigger throttling\n * or spike memory. The value is a pragmatic middle ground — high enough to\n * keep a typical driver's request pipeline full, low enough to avoid storms.\n */\nconst maxReadConcurrency = 32;\n\n/**\n * Runs `fn` over `items` with at most `limit` promises in flight. Preserves\n * input order on output (not that any caller depends on it today).\n *\n * Exported for unit tests; not part of the package public API.\n *\n * @internal\n */\nexport async function mapWithConcurrency<T, R>(\n\titems: readonly T[],\n\tlimit: number,\n\tfn: (item: T) => Promise<R>,\n): Promise<R[]> {\n\tconst results: R[] = Array.from({ length: items.length });\n\tlet cursor = 0;\n\tconst workerCount = Math.min(limit, items.length);\n\tconst workers = Array.from({ length: workerCount }, async () => {\n\t\twhile (cursor < items.length) {\n\t\t\tconst index = cursor++;\n\t\t\tconst item = items[index];\n\t\t\tif (item !== undefined) {\n\t\t\t\tresults[index] = await fn(item);\n\t\t\t}\n\t\t}\n\t});\n\tawait Promise.all(workers);\n\treturn results;\n}\n\n/**\n * Parses the `gc` subtree of a base snapshot. Returns `undefined` if the\n * snapshot has no GC tree (GC disabled or pre-GC document).\n */\nexport async function parseGcSnapshotData(\n\tbaseSnapshot: ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): Promise<IGcSnapshotData | undefined> {\n\tconst gcSnapshotTree: ISnapshotTree | undefined = baseSnapshot.trees[gcTreeKey];\n\tif (gcSnapshotTree === undefined) {\n\t\treturn undefined;\n\t}\n\tlet gcState: IGcState | undefined;\n\tlet tombstones: string[] | undefined;\n\tlet deletedNodes: string[] | undefined;\n\tfor (const [key, blobId] of Object.entries(gcSnapshotTree.blobs)) {\n\t\tif (key === gcDeletedBlobKey) {\n\t\t\tdeletedNodes = await readAndParse<string[]>(storage, blobId);\n\t\t} else if (key === gcTombstoneBlobKey) {\n\t\t\ttombstones = await readAndParse<string[]>(storage, blobId);\n\t\t} else if (key.startsWith(gcBlobPrefix)) {\n\t\t\tconst partial = await readAndParse<IGcState>(storage, blobId);\n\t\t\tif (gcState === undefined) {\n\t\t\t\tgcState = { gcNodes: { ...partial.gcNodes } };\n\t\t\t} else {\n\t\t\t\tfor (const [nodeId, nodeData] of Object.entries(partial.gcNodes)) {\n\t\t\t\t\tgcState.gcNodes[nodeId] ??= nodeData;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn { gcState, tombstones, deletedNodes };\n}\n\n/**\n * Walks a snapshot and inlines the contents of every blob reachable without\n * crossing an `unreferenced` subtree boundary. Subtrees flagged\n * `unreferenced: true` are skipped entirely — the summarizer sets that flag\n * from GC state, so honouring it filters out dead subtrees without a\n * separate GC-path traversal.\n *\n * The root-level `.blobs` subtree is special-cased: only its `.redirectTable`\n * blob is read, because attachment blob contents are captured separately via\n * {@link captureReferencedAttachmentBlobs}.\n */\nexport async function readReferencedSnapshotBlobs(\n\tsnapshot: ISnapshot | ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): Promise<ISerializableBlobContents> {\n\tconst { tree, read } = toTreeAndReader(snapshot, storage);\n\tconst ids = new Set<string>();\n\tcollectReferencedBlobIds(tree, true, ids);\n\tconst blobs: ISerializableBlobContents = {};\n\tawait mapWithConcurrency([...ids], maxReadConcurrency, async (id) => {\n\t\tconst data = await read(id);\n\t\tblobs[id] = bufferToString(data, \"utf8\");\n\t});\n\treturn blobs;\n}\n\n/**\n * Synchronously walks the snapshot tree and gathers the set of blob ids that\n * should be inlined. Subtrees flagged `unreferenced: true` are skipped\n * entirely. The root-level `.blobs` subtree is special-cased: only its\n * `.redirectTable` id is collected, because attachment blob contents are\n * captured separately via {@link captureReferencedAttachmentBlobs}.\n */\nfunction collectReferencedBlobIds(\n\ttree: ISnapshotTree,\n\tisRoot: boolean,\n\tids: Set<string>,\n): void {\n\tif (tree.unreferenced === true) {\n\t\treturn;\n\t}\n\tfor (const blobId of Object.values(tree.blobs)) {\n\t\tids.add(blobId);\n\t}\n\tfor (const [key, subTree] of Object.entries(tree.trees)) {\n\t\tif (isRoot && key === blobsTreeName) {\n\t\t\tconst tableBlobId = subTree.blobs[redirectTableBlobName];\n\t\t\tif (tableBlobId !== undefined) {\n\t\t\t\tids.add(tableBlobId);\n\t\t\t}\n\t\t} else {\n\t\t\tcollectReferencedBlobIds(subTree, false, ids);\n\t\t}\n\t}\n}\n\nfunction toTreeAndReader(\n\tsnapshot: ISnapshot | ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): { tree: ISnapshotTree; read: BlobReader } {\n\tif (\"snapshotTree\" in snapshot) {\n\t\tconst blobContents = snapshot.blobContents;\n\t\treturn {\n\t\t\ttree: snapshot.snapshotTree,\n\t\t\tread: async (id) => blobContents.get(id) ?? storage.readBlob(id),\n\t\t};\n\t}\n\treturn { tree: snapshot, read: async (id) => storage.readBlob(id) };\n}\n\n/**\n * Fetches attachment blob contents from a snapshot, filtered by GC\n * reachability. Blobs GC has explicitly marked unreferenced, tombstoned, or\n * deleted are skipped. Blobs absent from the GC graph are kept — GC state\n * lags behind recent attachments and dropping them would lose live data.\n * If `gcData` is `undefined`, every attachment blob is returned.\n *\n * The returned map is keyed by attachment blob storage id. Values are the\n * raw bytes encoded as **base64** strings — attachment blobs may carry\n * arbitrary binary payloads (images, encrypted data, etc.) and a\n * UTF-8 round-trip would silently corrupt non-UTF-8 byte sequences with\n * replacement characters. The runtime's own pending-blob serializer uses\n * base64 for the same reason. This diverges from the structural-blob path\n * in {@link readReferencedSnapshotBlobs}, which encodes UTF-8 because those\n * blobs are JSON or other text the runtime authored. Callers must keep the\n * two encodings on separate fields of the pending state so the load side\n * can decode each correctly.\n */\nexport async function captureReferencedAttachmentBlobs(\n\tbaseSnapshot: ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\tgcData: IGcSnapshotData | undefined,\n): Promise<IBase64BlobContents> {\n\tconst blobsTree: ISnapshotTree | undefined = baseSnapshot.trees[blobsTreeName];\n\tif (blobsTree === undefined) {\n\t\treturn {};\n\t}\n\tconst localIdToStorageId = await readRedirectTable(blobsTree, storage);\n\tif (localIdToStorageId.size === 0) {\n\t\treturn {};\n\t}\n\n\tconst unreferencedLocalIds =\n\t\tgcData === undefined ? undefined : collectUnreferencedBlobLocalIds(gcData);\n\n\tconst storageIdsToFetch = new Set<string>();\n\tfor (const [localId, storageId] of localIdToStorageId) {\n\t\tif (unreferencedLocalIds?.has(localId) !== true) {\n\t\t\tstorageIdsToFetch.add(storageId);\n\t\t}\n\t}\n\n\tconst contents: IBase64BlobContents = {};\n\tawait mapWithConcurrency([...storageIdsToFetch], maxReadConcurrency, async (storageId) => {\n\t\tconst buffer = await storage.readBlob(storageId);\n\t\tcontents[storageId] = bufferToString(buffer, \"base64\");\n\t});\n\treturn contents;\n}\n\n/**\n * Reconstructs the BlobManager's redirect table from a `.blobs` subtree.\n * Mirrors `toRedirectTable` in blobManagerSnapSum.ts.\n */\nasync function readRedirectTable(\n\tblobsTree: ISnapshotTree,\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n): Promise<Map<string, string>> {\n\tconst redirectTable = new Map<string, string>();\n\tconst tableBlobId: string | undefined = blobsTree.blobs[redirectTableBlobName];\n\tif (tableBlobId !== undefined) {\n\t\tconst entries = await readAndParse<[string, string][]>(storage, tableBlobId);\n\t\tfor (const [localId, storageId] of entries) {\n\t\t\tredirectTable.set(localId, storageId);\n\t\t}\n\t}\n\tfor (const [key, storageId] of Object.entries(blobsTree.blobs)) {\n\t\tif (key !== redirectTableBlobName) {\n\t\t\t// Identity mapping: storage ids referenced directly in handles (legacy).\n\t\t\tredirectTable.set(storageId, storageId);\n\t\t}\n\t}\n\treturn redirectTable;\n}\n\n/**\n * Collects the set of blob localIds that GC has explicitly marked as\n * unreferenced (via `unreferencedTimestampMs` on a gc node), tombstoned, or\n * deleted. Tombstones and deletedNodes are applied regardless of whether\n * `gcState` is present — they are authoritative on their own and must not\n * be silently dropped when gc state is absent but tombstone/deleted lists\n * exist.\n */\nfunction collectUnreferencedBlobLocalIds(gcData: IGcSnapshotData): Set<string> {\n\tconst blobPathPrefix = `/${blobManagerBasePath}/`;\n\tconst unreferenced = new Set<string>();\n\tif (gcData.gcState !== undefined) {\n\t\tfor (const [nodePath, nodeData] of Object.entries(gcData.gcState.gcNodes)) {\n\t\t\tif (\n\t\t\t\tnodePath.startsWith(blobPathPrefix) &&\n\t\t\t\tnodeData.unreferencedTimestampMs !== undefined\n\t\t\t) {\n\t\t\t\tunreferenced.add(nodePath.slice(blobPathPrefix.length));\n\t\t\t}\n\t\t}\n\t}\n\tfor (const nodePath of [...(gcData.tombstones ?? []), ...(gcData.deletedNodes ?? [])]) {\n\t\tif (nodePath.startsWith(blobPathPrefix)) {\n\t\t\tunreferenced.add(nodePath.slice(blobPathPrefix.length));\n\t\t}\n\t}\n\treturn unreferenced;\n}\n\n/**\n * A blob reference extracted from a `BlobAttach` op. `localId` is the\n * `BlobManager` GC identity for the blob; `storageId` is the id used for\n * `IDocumentStorageService.readBlob`.\n *\n * @internal\n */\nexport interface IBlobAttachReference {\n\treadonly localId: string;\n\treadonly storageId: string;\n}\n\ninterface IBlobAttachLikeMetadata {\n\treadonly localId: string;\n\treadonly blobId: string;\n}\n\nfunction isBlobAttachLikeMetadata(metadata: unknown): metadata is IBlobAttachLikeMetadata {\n\tif (typeof metadata !== \"object\" || metadata === null) {\n\t\treturn false;\n\t}\n\tconst candidate = metadata as { localId?: unknown; blobId?: unknown };\n\treturn typeof candidate.localId === \"string\" && typeof candidate.blobId === \"string\";\n}\n\n/**\n * Extracts every `BlobAttach` reference an op carries. Returns an empty array\n * for non-blobAttach ops.\n *\n * This is the single place in the loader that interprets the BlobAttach\n * wire format. Capture and load-side reasoning about ops should call into\n * this function rather than reading `op.metadata` directly, so a future\n * protocol change touches one site.\n *\n * BlobAttach ops carry `(localId, storageId)` directly on\n * `ISequencedDocumentMessage.metadata` and are not grouped — the container\n * runtime routes them through a separate `outbox.submitBlobAttach` lane,\n * and `OpGroupingManager.groupBatch` asserts (0x5dd) that no op carrying\n * non-batch metadata enters a grouped batch. If either guarantee changes,\n * extend this function rather than each call site.\n *\n * @internal\n */\nexport function extractBlobAttachReferences(\n\top: Pick<ISequencedDocumentMessage, \"metadata\">,\n): IBlobAttachReference[] {\n\tif (!isBlobAttachLikeMetadata(op.metadata)) {\n\t\treturn [];\n\t}\n\treturn [{ localId: op.metadata.localId, storageId: op.metadata.blobId }];\n}\n\n/**\n * Set of attachment-blob localIds that GC has marked unreferenced,\n * tombstoned, or deleted in the base snapshot. `undefined` if `gcData`\n * is `undefined` (GC disabled / pre-GC document).\n *\n * @internal\n */\nexport function unreferencedAttachmentBlobLocalIds(\n\tgcData: IGcSnapshotData | undefined,\n): Set<string> | undefined {\n\treturn gcData === undefined ? undefined : collectUnreferencedBlobLocalIds(gcData);\n}\n\n/**\n * Inline attachment blob contents for the given `(localId, storageId)`\n * references. Skips entries already present in `existing` (de-dupe with\n * the snapshot path) and entries whose `localId` is in\n * `unreferencedLocalIds`. Returns only the freshly-read entries; the\n * caller merges them into the existing map.\n *\n * @internal\n */\nexport async function inlineAttachmentBlobsByReference(\n\treferences: readonly IBlobAttachReference[],\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\tunreferencedLocalIds: ReadonlySet<string> | undefined,\n\texisting: Readonly<IBase64BlobContents>,\n): Promise<IBase64BlobContents> {\n\tconst storageIdsToFetch = new Set<string>();\n\tfor (const { localId, storageId } of references) {\n\t\tif (unreferencedLocalIds?.has(localId) === true) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (existing[storageId] !== undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tstorageIdsToFetch.add(storageId);\n\t}\n\tconst added: IBase64BlobContents = {};\n\tif (storageIdsToFetch.size === 0) {\n\t\treturn added;\n\t}\n\tawait mapWithConcurrency([...storageIdsToFetch], maxReadConcurrency, async (storageId) => {\n\t\tconst buffer = await storage.readBlob(storageId);\n\t\tadded[storageId] = bufferToString(buffer, \"base64\");\n\t});\n\treturn added;\n}\n\n/**\n * Returns true if any referenced subtree of `baseSnapshot` declares a\n * `groupId` — the snapshot-tree wire field that carries the runtime's\n * loading-group identifier. Subtrees flagged `unreferenced` are skipped —\n * a dead subtree's `groupId` would not be loaded by the runtime either.\n *\n * `captureFullContainerState` does not yet support loading groups: prefetching\n * per-group snapshots adds a code path that has no end-to-end coverage and no\n * known production consumer. Callers use this to fail fast with a `UsageError`\n * rather than silently producing a pending state that omits group data.\n */\nexport function snapshotHasLoadingGroups(baseSnapshot: ISnapshotTree): boolean {\n\tif (baseSnapshot.unreferenced === true) {\n\t\treturn false;\n\t}\n\tif (baseSnapshot.groupId !== undefined) {\n\t\treturn true;\n\t}\n\tfor (const child of Object.values(baseSnapshot.trees)) {\n\t\tif (snapshotHasLoadingGroups(child)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n"]}
@@ -11,6 +11,16 @@ const internal_1 = require("@fluidframework/core-utils/internal");
11
11
  * that were known at the time the monitor was created.
12
12
  */
13
13
  class CatchUpMonitor {
14
+ deltaManager;
15
+ listener;
16
+ targetSeqNumber;
17
+ caughtUp = false;
18
+ opHandler = (message) => {
19
+ if (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {
20
+ this.caughtUp = true;
21
+ this.listener();
22
+ }
23
+ };
14
24
  /**
15
25
  * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.
16
26
  *
@@ -25,14 +35,6 @@ class CatchUpMonitor {
25
35
  constructor(deltaManager, listener) {
26
36
  this.deltaManager = deltaManager;
27
37
  this.listener = listener;
28
- this.caughtUp = false;
29
- this.opHandler = (message) => {
30
- if (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {
31
- this.caughtUp = true;
32
- this.listener();
33
- }
34
- };
35
- this._disposed = false;
36
38
  this.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;
37
39
  (0, internal_1.assert)(this.targetSeqNumber >= this.deltaManager.lastSequenceNumber, 0x37c /* Cannot wait for seqNumber below last processed sequence number */);
38
40
  this.deltaManager.on("op", this.opHandler);
@@ -47,6 +49,7 @@ class CatchUpMonitor {
47
49
  // Simulate the last processed op to set caughtUp in case we already are
48
50
  this.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });
49
51
  }
52
+ _disposed = false;
50
53
  /**
51
54
  * {@inheritDoc @fluidframework/core-interfaces#IDisposable.disposed}
52
55
  */