@fluidframework/container-loader 2.0.0-dev-rc.3.0.0.254866 → 2.0.0-dev-rc.5.0.0.263932

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 (190) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/api-report/container-loader.api.md +7 -3
  3. package/dist/attachment.d.ts +3 -2
  4. package/dist/attachment.d.ts.map +1 -1
  5. package/dist/attachment.js +5 -5
  6. package/dist/attachment.js.map +1 -1
  7. package/dist/audience.d.ts +6 -4
  8. package/dist/audience.d.ts.map +1 -1
  9. package/dist/audience.js +18 -3
  10. package/dist/audience.js.map +1 -1
  11. package/dist/catchUpMonitor.d.ts +1 -1
  12. package/dist/catchUpMonitor.d.ts.map +1 -1
  13. package/dist/catchUpMonitor.js.map +1 -1
  14. package/dist/connectionManager.d.ts +7 -3
  15. package/dist/connectionManager.d.ts.map +1 -1
  16. package/dist/connectionManager.js +63 -39
  17. package/dist/connectionManager.js.map +1 -1
  18. package/dist/connectionStateHandler.d.ts +31 -10
  19. package/dist/connectionStateHandler.d.ts.map +1 -1
  20. package/dist/connectionStateHandler.js +49 -36
  21. package/dist/connectionStateHandler.js.map +1 -1
  22. package/dist/container.d.ts +22 -13
  23. package/dist/container.d.ts.map +1 -1
  24. package/dist/container.js +145 -117
  25. package/dist/container.js.map +1 -1
  26. package/dist/containerContext.d.ts +3 -3
  27. package/dist/containerContext.d.ts.map +1 -1
  28. package/dist/containerContext.js.map +1 -1
  29. package/dist/containerStorageAdapter.d.ts +12 -3
  30. package/dist/containerStorageAdapter.d.ts.map +1 -1
  31. package/dist/containerStorageAdapter.js +42 -4
  32. package/dist/containerStorageAdapter.js.map +1 -1
  33. package/dist/contracts.d.ts +2 -2
  34. package/dist/contracts.d.ts.map +1 -1
  35. package/dist/contracts.js.map +1 -1
  36. package/dist/debugLogger.d.ts +1 -2
  37. package/dist/debugLogger.d.ts.map +1 -1
  38. package/dist/debugLogger.js.map +1 -1
  39. package/dist/deltaManager.d.ts +5 -6
  40. package/dist/deltaManager.d.ts.map +1 -1
  41. package/dist/deltaManager.js +29 -24
  42. package/dist/deltaManager.js.map +1 -1
  43. package/dist/deltaQueue.d.ts +1 -1
  44. package/dist/deltaQueue.d.ts.map +1 -1
  45. package/dist/deltaQueue.js.map +1 -1
  46. package/dist/error.d.ts +1 -2
  47. package/dist/error.d.ts.map +1 -1
  48. package/dist/error.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +3 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/{alpha.d.ts → legacy.d.ts} +5 -2
  54. package/dist/loadPaused.d.ts +35 -0
  55. package/dist/loadPaused.d.ts.map +1 -0
  56. package/dist/loadPaused.js +115 -0
  57. package/dist/loadPaused.js.map +1 -0
  58. package/dist/loader.d.ts +1 -1
  59. package/dist/loader.d.ts.map +1 -1
  60. package/dist/loader.js +1 -14
  61. package/dist/loader.js.map +1 -1
  62. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  63. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +4 -4
  64. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  65. package/dist/packageVersion.d.ts +1 -1
  66. package/dist/packageVersion.js +1 -1
  67. package/dist/packageVersion.js.map +1 -1
  68. package/dist/protocol.d.ts.map +1 -1
  69. package/dist/protocol.js +3 -0
  70. package/dist/protocol.js.map +1 -1
  71. package/dist/public.d.ts +2 -1
  72. package/dist/retriableDocumentStorageService.d.ts +1 -1
  73. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  74. package/dist/retriableDocumentStorageService.js.map +1 -1
  75. package/dist/serializedStateManager.d.ts +89 -9
  76. package/dist/serializedStateManager.d.ts.map +1 -1
  77. package/dist/serializedStateManager.js +153 -37
  78. package/dist/serializedStateManager.js.map +1 -1
  79. package/dist/utils.d.ts +13 -3
  80. package/dist/utils.d.ts.map +1 -1
  81. package/dist/utils.js +31 -17
  82. package/dist/utils.js.map +1 -1
  83. package/{dist/beta.d.ts → internal.d.ts} +2 -4
  84. package/{lib/beta.d.ts → legacy.d.ts} +2 -4
  85. package/lib/attachment.d.ts +3 -2
  86. package/lib/attachment.d.ts.map +1 -1
  87. package/lib/attachment.js +5 -5
  88. package/lib/attachment.js.map +1 -1
  89. package/lib/audience.d.ts +6 -4
  90. package/lib/audience.d.ts.map +1 -1
  91. package/lib/audience.js +19 -4
  92. package/lib/audience.js.map +1 -1
  93. package/lib/catchUpMonitor.d.ts +1 -1
  94. package/lib/catchUpMonitor.d.ts.map +1 -1
  95. package/lib/catchUpMonitor.js.map +1 -1
  96. package/lib/connectionManager.d.ts +7 -3
  97. package/lib/connectionManager.d.ts.map +1 -1
  98. package/lib/connectionManager.js +42 -18
  99. package/lib/connectionManager.js.map +1 -1
  100. package/lib/connectionStateHandler.d.ts +31 -10
  101. package/lib/connectionStateHandler.d.ts.map +1 -1
  102. package/lib/connectionStateHandler.js +49 -36
  103. package/lib/connectionStateHandler.js.map +1 -1
  104. package/lib/container.d.ts +22 -13
  105. package/lib/container.d.ts.map +1 -1
  106. package/lib/container.js +146 -118
  107. package/lib/container.js.map +1 -1
  108. package/lib/containerContext.d.ts +3 -3
  109. package/lib/containerContext.d.ts.map +1 -1
  110. package/lib/containerContext.js.map +1 -1
  111. package/lib/containerStorageAdapter.d.ts +12 -3
  112. package/lib/containerStorageAdapter.d.ts.map +1 -1
  113. package/lib/containerStorageAdapter.js +42 -4
  114. package/lib/containerStorageAdapter.js.map +1 -1
  115. package/lib/contracts.d.ts +2 -2
  116. package/lib/contracts.d.ts.map +1 -1
  117. package/lib/contracts.js +1 -1
  118. package/lib/contracts.js.map +1 -1
  119. package/lib/debugLogger.d.ts +1 -2
  120. package/lib/debugLogger.d.ts.map +1 -1
  121. package/lib/debugLogger.js.map +1 -1
  122. package/lib/deltaManager.d.ts +5 -6
  123. package/lib/deltaManager.d.ts.map +1 -1
  124. package/lib/deltaManager.js +10 -5
  125. package/lib/deltaManager.js.map +1 -1
  126. package/lib/deltaQueue.d.ts +1 -1
  127. package/lib/deltaQueue.d.ts.map +1 -1
  128. package/lib/deltaQueue.js.map +1 -1
  129. package/lib/error.d.ts +1 -2
  130. package/lib/error.d.ts.map +1 -1
  131. package/lib/error.js.map +1 -1
  132. package/lib/index.d.ts +1 -0
  133. package/lib/index.d.ts.map +1 -1
  134. package/lib/index.js +1 -0
  135. package/lib/index.js.map +1 -1
  136. package/lib/{alpha.d.ts → legacy.d.ts} +5 -2
  137. package/lib/loadPaused.d.ts +35 -0
  138. package/lib/loadPaused.d.ts.map +1 -0
  139. package/lib/loadPaused.js +111 -0
  140. package/lib/loadPaused.js.map +1 -0
  141. package/lib/loader.d.ts +1 -1
  142. package/lib/loader.d.ts.map +1 -1
  143. package/lib/loader.js +3 -16
  144. package/lib/loader.js.map +1 -1
  145. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  146. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +1 -1
  147. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  148. package/lib/packageVersion.d.ts +1 -1
  149. package/lib/packageVersion.js +1 -1
  150. package/lib/packageVersion.js.map +1 -1
  151. package/lib/protocol.d.ts.map +1 -1
  152. package/lib/protocol.js +3 -0
  153. package/lib/protocol.js.map +1 -1
  154. package/lib/public.d.ts +2 -1
  155. package/lib/retriableDocumentStorageService.d.ts +1 -1
  156. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  157. package/lib/retriableDocumentStorageService.js +1 -1
  158. package/lib/retriableDocumentStorageService.js.map +1 -1
  159. package/lib/serializedStateManager.d.ts +89 -9
  160. package/lib/serializedStateManager.d.ts.map +1 -1
  161. package/lib/serializedStateManager.js +149 -33
  162. package/lib/serializedStateManager.js.map +1 -1
  163. package/lib/tsdoc-metadata.json +1 -1
  164. package/lib/utils.d.ts +13 -3
  165. package/lib/utils.d.ts.map +1 -1
  166. package/lib/utils.js +17 -4
  167. package/lib/utils.js.map +1 -1
  168. package/package.json +33 -30
  169. package/src/attachment.ts +12 -13
  170. package/src/audience.ts +30 -9
  171. package/src/catchUpMonitor.ts +1 -1
  172. package/src/connectionManager.ts +53 -23
  173. package/src/connectionStateHandler.ts +78 -45
  174. package/src/container.ts +181 -160
  175. package/src/containerContext.ts +2 -2
  176. package/src/containerStorageAdapter.ts +61 -6
  177. package/src/contracts.ts +5 -4
  178. package/src/debugLogger.ts +1 -1
  179. package/src/deltaManager.ts +15 -8
  180. package/src/deltaQueue.ts +1 -1
  181. package/src/error.ts +1 -1
  182. package/src/index.ts +1 -0
  183. package/src/loadPaused.ts +140 -0
  184. package/src/loader.ts +6 -23
  185. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +1 -1
  186. package/src/packageVersion.ts +1 -1
  187. package/src/protocol.ts +4 -0
  188. package/src/retriableDocumentStorageService.ts +5 -2
  189. package/src/serializedStateManager.ts +224 -51
  190. package/src/utils.ts +22 -5
package/lib/utils.d.ts CHANGED
@@ -6,7 +6,7 @@ import { IDocumentStorageService, type ISnapshot } from "@fluidframework/driver-
6
6
  import { CombinedAppAndProtocolSummary, DeltaStreamConnectionForbiddenError } from "@fluidframework/driver-utils/internal";
7
7
  import { IDocumentAttributes, ISnapshotTree, ISummaryTree } from "@fluidframework/protocol-definitions";
8
8
  import { ISerializableBlobContents } from "./containerStorageAdapter.js";
9
- import type { IPendingDetachedContainerState, ISnapshotInfo, SnapshotWithBlobs } from "./serializedStateManager.js";
9
+ import type { IPendingContainerState, IPendingDetachedContainerState, ISnapshotInfo, SnapshotWithBlobs } from "./serializedStateManager.js";
10
10
  export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
11
11
  blobsContents: {
12
12
  [path: string]: ArrayBufferLike;
@@ -19,7 +19,7 @@ export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
19
19
  * Interface to represent the parsed parts of IResolvedUrl.url to help
20
20
  * in getting info about different parts of the url.
21
21
  * May not be compatible or relevant for any Url Resolver
22
- * @internal
22
+ * @alpha
23
23
  */
24
24
  export interface IParsedUrl {
25
25
  /**
@@ -47,7 +47,7 @@ export interface IParsedUrl {
47
47
  * with urls of type: protocol://<string>/.../..?<querystring>
48
48
  * @param url - This is the IResolvedUrl.url part of the resolved url.
49
49
  * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported
50
- * @internal
50
+ * @alpha
51
51
  */
52
52
  export declare function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined;
53
53
  /**
@@ -77,7 +77,17 @@ export declare const getSnapshotTreeAndBlobsFromSerializedContainer: (detachedCo
77
77
  export declare function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree;
78
78
  export declare const combineSnapshotTreeAndSnapshotBlobs: (baseSnapshot: ISnapshotTree, snapshotBlobs: ISerializableBlobContents) => ISnapshotTreeWithBlobContents;
79
79
  export declare function isDeltaStreamConnectionForbiddenError(error: any): error is DeltaStreamConnectionForbiddenError;
80
+ /**
81
+ * Parses the given string into {@link IPendingDetachedContainerState} format,
82
+ * with validation (if invalid, throws a UsageError).
83
+ * This is the inverse of the JSON.stringify call in {@link Container.serialize}
84
+ */
80
85
  export declare function getDetachedContainerStateFromSerializedContainer(serializedContainer: string): IPendingDetachedContainerState;
86
+ /**
87
+ * Blindly parses the given string into {@link IPendingContainerState} format.
88
+ * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}
89
+ */
90
+ export declare function getAttachedContainerStateFromSerializedContainer(serializedContainer: string | undefined): IPendingContainerState | undefined;
81
91
  /**
82
92
  * Ensures only a single instance of the provided async function is running.
83
93
  * If there are multiple calls they will all get the same promise to wait on.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACN,uBAAuB,EACvB,KAAK,SAAS,EACd,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAGnC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACN,mBAAmB,EACnB,aAAa,EACb,YAAY,EAEZ,MAAM,sCAAsC,CAAC;AAI9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EACX,8BAA8B,EAC9B,aAAa,EACb,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAiBjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AAsDD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,GAAG,aAAa,CAWhF;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC5C,YAAY,EAAE,aAAa,EAC3B,sBAAsB,EAAE,MAAM,GAC5B,SAAS,CAaX;AAqBD,eAAO,MAAM,8CAA8C,8BAC/B,YAAY,KACrC,iBAYF,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,eAAO,MAAM,mCAAmC,iBACjC,aAAa,iBACZ,yBAAyB,KACtC,6BAwBF,CAAC;AAEF,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,GAAG,GACR,KAAK,IAAI,mCAAmC,CAM9C;AAoBD,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,8BAA8B,CAkBhC;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,sFAsBrB,CAAC;AAEF,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAClD,IAAI,EAAE,aAAa,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAiB9B"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACN,uBAAuB,EACvB,KAAK,SAAS,EACd,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACN,6BAA6B,EAC7B,mCAAmC,EAGnC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACN,mBAAmB,EACnB,aAAa,EACb,YAAY,EAEZ,MAAM,sCAAsC,CAAC;AAI9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EACX,sBAAsB,EACtB,8BAA8B,EAC9B,aAAa,EACb,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,MAAM,WAAW,6BAA8B,SAAQ,aAAa;IACnE,aAAa,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAAA;KAAE,CAAC;IACnD,KAAK,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;KAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAiBjF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,YAAY,EACxB,eAAe,EAAE,YAAY,GAC3B,6BAA6B,CAiB/B;AAqDD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,GAAG,aAAa,CAWhF;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC5C,YAAY,EAAE,aAAa,EAC3B,sBAAsB,EAAE,MAAM,GAC5B,SAAS,CAaX;AAqBD,eAAO,MAAM,8CAA8C,8BAC/B,YAAY,KACrC,iBAYF,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CAE9E;AAED,eAAO,MAAM,mCAAmC,iBACjC,aAAa,iBACZ,yBAAyB,KACtC,6BAwBF,CAAC;AAEF,wBAAgB,qCAAqC,CACpD,KAAK,EAAE,GAAG,GACR,KAAK,IAAI,mCAAmC,CAM9C;AAoBD;;;;GAIG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GACzB,8BAA8B,CAkBhC;AAED;;;GAGG;AACH,wBAAgB,gDAAgD,CAC/D,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACrC,sBAAsB,GAAG,SAAS,CAIpC;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,sFAsBrB,CAAC;AAEF,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAClD,IAAI,EAAE,aAAa,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAiB9B"}
package/lib/utils.js CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { Uint8ArrayToString, bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
6
6
  import { assert, compareArrays, unreachableCase } from "@fluidframework/core-utils/internal";
7
- import { DriverErrorTypes } from "@fluidframework/driver-definitions";
7
+ import { DriverErrorTypes } from "@fluidframework/driver-definitions/internal";
8
8
  import { isCombinedAppAndProtocolSummary, readAndParse, } from "@fluidframework/driver-utils/internal";
9
9
  import { SummaryType, } from "@fluidframework/protocol-definitions";
10
10
  import { LoggingError, UsageError } from "@fluidframework/telemetry-utils/internal";
@@ -16,7 +16,7 @@ import { v4 as uuid } from "uuid";
16
16
  * with urls of type: protocol://<string>/.../..?<querystring>
17
17
  * @param url - This is the IResolvedUrl.url part of the resolved url.
18
18
  * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported
19
- * @internal
19
+ * @alpha
20
20
  */
21
21
  export function tryParseCompatibleResolvedUrl(url) {
22
22
  const parsed = new URL(url);
@@ -92,7 +92,6 @@ function convertSummaryToSnapshotAndBlobs(summary) {
92
92
  }
93
93
  case SummaryType.Handle:
94
94
  throw new LoggingError("No handles should be there in summary in detached container!!");
95
- break;
96
95
  default: {
97
96
  unreachableCase(summaryObject, `Unknown tree type ${summaryObject.type}`);
98
97
  }
@@ -109,7 +108,7 @@ function convertSummaryToSnapshotAndBlobs(summary) {
109
108
  * @param snapshot - ISnapshot
110
109
  */
111
110
  export function convertSnapshotToSnapshotInfo(snapshot) {
112
- assert(snapshot.sequenceNumber !== undefined, "Snapshot sequence number is missing");
111
+ assert(snapshot.sequenceNumber !== undefined, 0x93a /* Snapshot sequence number is missing */);
113
112
  const snapshotBlobs = {};
114
113
  for (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {
115
114
  snapshotBlobs[blobId] = bufferToString(arrayBufferLike, "utf8");
@@ -204,6 +203,11 @@ function isPendingDetachedContainerState(detachedContainerState) {
204
203
  }
205
204
  return true;
206
205
  }
206
+ /**
207
+ * Parses the given string into {@link IPendingDetachedContainerState} format,
208
+ * with validation (if invalid, throws a UsageError).
209
+ * This is the inverse of the JSON.stringify call in {@link Container.serialize}
210
+ */
207
211
  export function getDetachedContainerStateFromSerializedContainer(serializedContainer) {
208
212
  const hasBlobsSummaryTree = ".hasAttachmentBlobs";
209
213
  const parsedContainerState = JSON.parse(serializedContainer);
@@ -224,6 +228,15 @@ export function getDetachedContainerStateFromSerializedContainer(serializedConta
224
228
  throw new UsageError("Cannot rehydrate detached container. Incorrect format");
225
229
  }
226
230
  }
231
+ /**
232
+ * Blindly parses the given string into {@link IPendingContainerState} format.
233
+ * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}
234
+ */
235
+ export function getAttachedContainerStateFromSerializedContainer(serializedContainer) {
236
+ return serializedContainer !== undefined
237
+ ? JSON.parse(serializedContainer)
238
+ : undefined;
239
+ }
227
240
  /**
228
241
  * Ensures only a single instance of the provided async function is running.
229
242
  * If there are multiple calls they will all get the same promise to wait on.
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAKtE,OAAO,EAGN,+BAA+B,EAC/B,YAAY,GACZ,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAIN,WAAW,GACX,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AA0ClC;;;;;;;;GAQG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAW;IACxD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE;QACxC,MAAM,IAAI,YAAY,CAAC,0BAA0B,CAAC,CAAC;KACnD;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,2BAA2B,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,OAAO,KAAK,EAAE,MAAM,KAAK,CAAC;QACzB,CAAC,CAAC;YACA,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;YACZ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACd,KAAK;YACL,6DAA6D;YAC7D,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS;SACvD;QACH,CAAC,CAAC,SAAS,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAC3C,UAAwB,EACxB,eAA6B;IAE7B,MAAM,CACL,CAAC,+BAA+B,CAAC,UAAU,CAAC,EAC5C,KAAK,CAAC,6CAA6C,CACnD,CAAC;IACF,MAAM,CACL,CAAC,+BAA+B,CAAC,eAAe,CAAC,EACjD,KAAK,CAAC,kDAAkD,CACxD,CAAC;IACF,MAAM,gBAAgB,GAAkC;QACvD,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,IAAI,EAAE;YACL,WAAW,EAAE,eAAe;YAC5B,MAAM,EAAE,UAAU;SAClB;KACD,CAAC;IACF,OAAO,gBAAgB,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,SAAS,gCAAgC,CAAC,OAAqB;IAC9D,IAAI,YAAY,GAA8B,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAkB;QAC/B,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE;QACT,EAAE,EAAE,IAAI,EAAE;QACV,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;KACxB,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;QACvB,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAExC,QAAQ,aAAa,CAAC,IAAI,EAAE;YAC3B,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC;gBACtB,MAAM,aAAa,GAAG,gCAAgC,CAAC,aAAa,CAAC,CAAC;gBACtE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,YAAY,CAAC;gBACjD,YAAY,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,aAAa,CAAC,aAAa,EAAE,CAAC;gBACnE,MAAM;aACN;YACD,KAAK,WAAW,CAAC,UAAU;gBAC1B,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC;gBACvC,MAAM;YACP,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC;gBACtB,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC;gBACtB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;gBAC7B,MAAM,aAAa,GAClB,aAAa,CAAC,OAAO,YAAY,UAAU;oBAC1C,CAAC,CAAC,kBAAkB,CAAC,aAAa,CAAC,OAAO,CAAC;oBAC3C,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC;gBAC1B,YAAY,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC;gBACrC,MAAM;aACN;YACD,KAAK,WAAW,CAAC,MAAM;gBACtB,MAAM,IAAI,YAAY,CACrB,+DAA+D,CAC/D,CAAC;gBACF,MAAM;YACP,OAAO,CAAC,CAAC;gBACR,eAAe,CAAC,aAAa,EAAE,qBAAsB,aAAqB,CAAC,IAAI,EAAE,CAAC,CAAC;aACnF;SACD;KACD;IACD,MAAM,eAAe,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC;IAChF,OAAO,eAAe,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAAmB;IAChE,MAAM,CAAC,QAAQ,CAAC,cAAc,KAAK,SAAS,EAAE,qCAAqC,CAAC,CAAC;IACrF,MAAM,aAAa,GAA8B,EAAE,CAAC;IACpD,KAAK,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE;QACxE,aAAa,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;KAChE;IACD,OAAO;QACN,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,aAAa;QACb,sBAAsB,EAAE,QAAQ,CAAC,cAAc;KAC/C,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,CAC5C,YAA2B,EAC3B,sBAA8B;IAE9B,MAAM,YAAY,GAAG,IAAI,GAAG,EAA2B,CAAC;IACxD,KAAK,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE;QACrF,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC;KACpE;IACD,OAAO;QACN,YAAY,EAAE,YAAY,CAAC,YAAY;QACvC,YAAY;QACZ,GAAG,EAAE,EAAE;QACP,cAAc,EAAE,sBAAsB;QACtC,oBAAoB,EAAE,SAAS;QAC/B,eAAe,EAAE,CAAC;KAClB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,8CAA8C,CACtD,mBAAiC,EACjC,cAA4B;IAE5B,MAAM,eAAe,GAAiB;QACrC,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,IAAI,EAAE,EAAE,GAAG,cAAc,CAAC,IAAI,EAAE;KAChC,CAAC;IAEF,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,mBAAmB,CAAC;IACxD,MAAM,4BAA4B,GAAG,gCAAgC,CAAC,eAAe,CAAC,CAAC;IACvF,OAAO,4BAA4B,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,MAAM,8CAA8C,GAAG,CAC7D,yBAAuC,EACnB,EAAE;IACtB,MAAM,CACL,+BAA+B,CAAC,yBAAyB,CAAC,EAC1D,KAAK,CAAC,sDAAsD,CAC5D,CAAC;IACF,MAAM,mBAAmB,GAAG,yBAAyB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxE,MAAM,cAAc,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,4BAA4B,GAAG,8CAA8C,CAClF,mBAAmB,EACnB,cAAc,CACd,CAAC;IACF,OAAO,4BAA4B,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC9D,OAAO,WAAW,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAClD,YAA2B,EAC3B,aAAwC,EACR,EAAE;IAClC,MAAM,aAAa,GAAwC,EAAE,CAAC;IAE9D,qCAAqC;IACrC,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;QACxD,IAAI,aAAa,CAAC,EAAE,CAAC,EAAE;YACtB,aAAa,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;SAC9D;KACD;IAED,iDAAiD;IACjD,MAAM,KAAK,GAAsD,EAAE,CAAC;IACpE,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;QAC9D,KAAK,CAAC,IAAI,CAAC,GAAG,mCAAmC,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;KACvE;IAED,oEAAoE;IACpE,MAAM,4BAA4B,GAAkC;QACnE,GAAG,YAAY;QACf,aAAa;QACb,KAAK;KACL,CAAC;IAEF,OAAO,4BAA4B,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,UAAU,qCAAqC,CACpD,KAAU;IAEV,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,KAAK,EAAE,SAAS,KAAK,gBAAgB,CAAC,8BAA8B,CACpE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,+BAA+B,CACvC,sBAAsD;IAEtD,IACC,sBAAsB,EAAE,QAAQ,KAAK,SAAS;QAC9C,sBAAsB,EAAE,YAAY,KAAK,SAAS;QAClD,sBAAsB,EAAE,aAAa,KAAK,SAAS;QACnD,sBAAsB,EAAE,kBAAkB,KAAK,SAAS,EACvD;QACD,OAAO,KAAK,CAAC;KACb;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gDAAgD,CAC/D,mBAA2B;IAE3B,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;IAClD,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC7D,IAAI,+BAA+B,CAAC,oBAAoB,CAAC,EAAE;QAC1D,OAAO,oBAAoB,CAAC;KAC5B;SAAM,IAAI,+BAA+B,CAAC,oBAAoB,CAAC,EAAE;QACjE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GACpC,8CAA8C,CAAC,oBAAoB,CAAC,CAAC;QACtE,MAAM,sBAAsB,GAAmC;YAC9D,QAAQ,EAAE,KAAK;YACf,YAAY;YACZ,aAAa;YACb,kBAAkB,EAAE,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,SAAS;SAChF,CAAC;QACF,OAAO,sBAAsB,CAAC;KAC9B;SAAM;QACN,MAAM,IAAI,UAAU,CAAC,uDAAuD,CAAC,CAAC;KAC9E;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAqB,IAAgC,EAAE,EAAE;IACjF,IAAI,OAKQ,CAAC;IACb,iEAAiE;IACjE,+CAA+C;IAC/C,qEAAqE;IACrE,OAAO,CAAC,GAAG,IAAO,EAAE,EAAE;QACrB,IAAI,OAAO,KAAK,SAAS,EAAE;YAC1B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;gBACvC,OAAO,OAAO,CAAC,MAAM,CACpB,IAAI,UAAU,CAAC,kDAAkD,CAAC,CAClE,CAAC;aACF;YACD,OAAO,OAAO,CAAC,MAAM,CAAC;SACtB;QACD,OAAO,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC;QAC/E,OAAO,OAAO,CAAC,MAAM,CAAC;IACvB,CAAC,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,OAAkD,EAClD,IAA+B;IAE/B,IAAI,IAAI,KAAK,SAAS,EAAE;QACvB,OAAO;YACN,qBAAqB,EAAE,CAAC;YACxB,cAAc,EAAE,CAAC;SACjB,CAAC;KACF;IAED,oFAAoF;IACpF,MAAM,cAAc,GACnB,WAAW,IAAI,IAAI,CAAC,KAAK;QACxB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,UAAU;QAC1C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,MAAM,YAAY,CAAsB,OAAO,EAAE,cAAc,CAAC,CAAC;IAEpF,OAAO,UAAU,CAAC;AACnB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { Uint8ArrayToString, bufferToString, stringToBuffer } from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions\";\nimport {\n\tIDocumentStorageService,\n\ttype ISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n\treadAndParse,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tIDocumentAttributes,\n\tISnapshotTree,\n\tISummaryTree,\n\tSummaryType,\n} from \"@fluidframework/protocol-definitions\";\nimport { LoggingError, UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport type {\n\tIPendingDetachedContainerState,\n\tISnapshotInfo,\n\tSnapshotWithBlobs,\n} from \"./serializedStateManager.js\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n * @internal\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Undefined means load latest snapshot, otherwise it's version ID passed to IDocumentStorageService.getVersions()\n\t * to figure out what snapshot to use.\n\t */\n\tversion: string | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n * @internal\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = new URL(url);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? {\n\t\t\t\tid: match[1],\n\t\t\t\tpath: match[2],\n\t\t\t\tquery,\n\t\t\t\t// URLSearchParams returns null if the param is not provided.\n\t\t\t\tversion: parsed.searchParams.get(\"version\") ?? undefined,\n\t\t }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts a summary to snapshot tree and separate its blob contents\n * to align detached container format with IPendingContainerState\n * @param summary - ISummaryTree\n */\nfunction convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): SnapshotWithBlobs {\n\tlet blobContents: ISerializableBlobContents = {};\n\tconst treeNode: ISnapshotTree = {\n\t\tblobs: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t\tgroupId: summary.groupId,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\tconst innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);\n\t\t\t\ttreeNode.trees[key] = innerSnapshot.baseSnapshot;\n\t\t\t\tblobContents = { ...blobContents, ...innerSnapshot.snapshotBlobs };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentString: string =\n\t\t\t\t\tsummaryObject.content instanceof Uint8Array\n\t\t\t\t\t\t? Uint8ArrayToString(summaryObject.content)\n\t\t\t\t\t\t: summaryObject.content;\n\t\t\t\tblobContents[blobId] = contentString;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\tconst pendingSnapshot = { baseSnapshot: treeNode, snapshotBlobs: blobContents };\n\treturn pendingSnapshot;\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotToSnapshotInfo(snapshot: ISnapshot): ISnapshotInfo {\n\tassert(snapshot.sequenceNumber !== undefined, \"Snapshot sequence number is missing\");\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[blobId] = bufferToString(arrayBufferLike, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t\tsnapshotSequenceNumber: snapshot.sequenceNumber,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotInfoToSnapshot(\n\tsnapshotInfo: ISnapshotInfo,\n\tsnapshotSequenceNumber: number,\n): ISnapshot {\n\tconst blobContents = new Map<string, ArrayBufferLike>();\n\tfor (const [blobId, serializedContent] of Object.entries(snapshotInfo.snapshotBlobs)) {\n\t\tblobContents.set(blobId, stringToBuffer(serializedContent, \"utf8\"));\n\t}\n\treturn {\n\t\tsnapshotTree: snapshotInfo.baseSnapshot,\n\t\tblobContents,\n\t\tops: [],\n\t\tsequenceNumber: snapshotSequenceNumber,\n\t\tlatestSequenceNumber: undefined,\n\t\tsnapshotFormatV: 1,\n\t};\n}\n\n/**\n * Converts summary parts into a SnapshotTree and its blob contents.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nfunction convertProtocolAndAppSummaryToSnapshotAndBlobs(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): SnapshotWithBlobs {\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents = convertSummaryToSnapshotAndBlobs(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\nexport const getSnapshotTreeAndBlobsFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): SnapshotWithBlobs => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x8e6 /* Protocol and App summary trees should be present */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotAndBlobs(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport const combineSnapshotTreeAndSnapshotBlobs = (\n\tbaseSnapshot: ISnapshotTree,\n\tsnapshotBlobs: ISerializableBlobContents,\n): ISnapshotTreeWithBlobContents => {\n\tconst blobsContents: { [path: string]: ArrayBufferLike } = {};\n\n\t// Process blobs in the current level\n\tfor (const [, id] of Object.entries(baseSnapshot.blobs)) {\n\t\tif (snapshotBlobs[id]) {\n\t\t\tblobsContents[id] = stringToBuffer(snapshotBlobs[id], \"utf8\");\n\t\t}\n\t}\n\n\t// Recursively process trees in the current level\n\tconst trees: { [path: string]: ISnapshotTreeWithBlobContents } = {};\n\tfor (const [path, tree] of Object.entries(baseSnapshot.trees)) {\n\t\ttrees[path] = combineSnapshotTreeAndSnapshotBlobs(tree, snapshotBlobs);\n\t}\n\n\t// Create a new snapshot tree with blob contents and processed trees\n\tconst snapshotTreeWithBlobContents: ISnapshotTreeWithBlobContents = {\n\t\t...baseSnapshot,\n\t\tblobsContents,\n\t\ttrees,\n\t};\n\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n\n/**\n * Validates format in parsed string get from detached container\n * serialization using IPendingDetachedContainerState format.\n */\nfunction isPendingDetachedContainerState(\n\tdetachedContainerState: IPendingDetachedContainerState,\n): detachedContainerState is IPendingDetachedContainerState {\n\tif (\n\t\tdetachedContainerState?.attached === undefined ||\n\t\tdetachedContainerState?.baseSnapshot === undefined ||\n\t\tdetachedContainerState?.snapshotBlobs === undefined ||\n\t\tdetachedContainerState?.hasAttachmentBlobs === undefined\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst { baseSnapshot, snapshotBlobs } =\n\t\t\tgetSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\tbaseSnapshot,\n\t\t\tsnapshotBlobs,\n\t\t\thasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,\n\t\t};\n\t\treturn detachedContainerState;\n\t} else {\n\t\tthrow new UsageError(\"Cannot rehydrate detached container. Incorrect format\");\n\t}\n}\n\n/**\n * Ensures only a single instance of the provided async function is running.\n * If there are multiple calls they will all get the same promise to wait on.\n */\nexport const runSingle = <A extends any[], R>(func: (...args: A) => Promise<R>) => {\n\tlet running:\n\t\t| {\n\t\t\t\targs: A;\n\t\t\t\tresult: Promise<R>;\n\t\t }\n\t\t| undefined;\n\t// don't mark this function async, so we return the same promise,\n\t// rather than one that is wrapped due to async\n\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\treturn (...args: A) => {\n\t\tif (running !== undefined) {\n\t\t\tif (!compareArrays(running.args, args)) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew UsageError(\"Subsequent calls cannot use different arguments.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn running.result;\n\t\t}\n\t\trunning = { args, result: func(...args).finally(() => (running = undefined)) };\n\t\treturn running.result;\n\t};\n};\n\nexport async function getDocumentAttributes(\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\ttree: ISnapshotTree | undefined,\n): Promise<IDocumentAttributes> {\n\tif (tree === undefined) {\n\t\treturn {\n\t\t\tminimumSequenceNumber: 0,\n\t\t\tsequenceNumber: 0,\n\t\t};\n\t}\n\n\t// Backward compatibility: old docs would have \".attributes\" instead of \"attributes\"\n\tconst attributesHash =\n\t\t\".protocol\" in tree.trees\n\t\t\t? tree.trees[\".protocol\"].blobs.attributes\n\t\t\t: tree.blobs[\".attributes\"];\n\n\tconst attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);\n\n\treturn attributes;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.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 { Uint8ArrayToString, bufferToString, stringToBuffer } from \"@fluid-internal/client-utils\";\nimport { assert, compareArrays, unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport { DriverErrorTypes } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tIDocumentStorageService,\n\ttype ISnapshot,\n} from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tCombinedAppAndProtocolSummary,\n\tDeltaStreamConnectionForbiddenError,\n\tisCombinedAppAndProtocolSummary,\n\treadAndParse,\n} from \"@fluidframework/driver-utils/internal\";\nimport {\n\tIDocumentAttributes,\n\tISnapshotTree,\n\tISummaryTree,\n\tSummaryType,\n} from \"@fluidframework/protocol-definitions\";\nimport { LoggingError, UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { ISerializableBlobContents } from \"./containerStorageAdapter.js\";\nimport type {\n\tIPendingContainerState,\n\tIPendingDetachedContainerState,\n\tISnapshotInfo,\n\tSnapshotWithBlobs,\n} from \"./serializedStateManager.js\";\n\n// This is used when we rehydrate a container from the snapshot. Here we put the blob contents\n// in separate property: blobContents.\nexport interface ISnapshotTreeWithBlobContents extends ISnapshotTree {\n\tblobsContents: { [path: string]: ArrayBufferLike };\n\ttrees: { [path: string]: ISnapshotTreeWithBlobContents };\n}\n\n/**\n * Interface to represent the parsed parts of IResolvedUrl.url to help\n * in getting info about different parts of the url.\n * May not be compatible or relevant for any Url Resolver\n * @alpha\n */\nexport interface IParsedUrl {\n\t/**\n\t * It is combination of tenantid/docId part of the url.\n\t */\n\tid: string;\n\t/**\n\t * It is the deep link path in the url.\n\t */\n\tpath: string;\n\t/**\n\t * Query string part of the url.\n\t */\n\tquery: string;\n\t/**\n\t * Undefined means load latest snapshot, otherwise it's version ID passed to IDocumentStorageService.getVersions()\n\t * to figure out what snapshot to use.\n\t */\n\tversion: string | undefined;\n}\n\n/**\n * Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get\n * deep link info etc.\n * Warning - This function may not be compatible with any Url Resolver's resolved url. It works\n * with urls of type: protocol://<string>/.../..?<querystring>\n * @param url - This is the IResolvedUrl.url part of the resolved url.\n * @returns The IParsedUrl representing the input URL, or undefined if the format was not supported\n * @alpha\n */\nexport function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {\n\tconst parsed = new URL(url);\n\tif (typeof parsed.pathname !== \"string\") {\n\t\tthrow new LoggingError(\"Failed to parse pathname\");\n\t}\n\tconst query = parsed.search ?? \"\";\n\tconst regex = /^\\/([^/]*\\/[^/]*)(\\/?.*)$/;\n\tconst match = regex.exec(parsed.pathname);\n\treturn match?.length === 3\n\t\t? {\n\t\t\t\tid: match[1],\n\t\t\t\tpath: match[2],\n\t\t\t\tquery,\n\t\t\t\t// URLSearchParams returns null if the param is not provided.\n\t\t\t\tversion: parsed.searchParams.get(\"version\") ?? undefined,\n\t\t }\n\t\t: undefined;\n}\n\n/**\n * Combine the app summary and protocol summary in 1 tree.\n * @param appSummary - Summary of the app.\n * @param protocolSummary - Summary of the protocol.\n * @internal\n */\nexport function combineAppAndProtocolSummary(\n\tappSummary: ISummaryTree,\n\tprotocolSummary: ISummaryTree,\n): CombinedAppAndProtocolSummary {\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(appSummary),\n\t\t0x5a8 /* app summary is already a combined tree! */,\n\t);\n\tassert(\n\t\t!isCombinedAppAndProtocolSummary(protocolSummary),\n\t\t0x5a9 /* protocol summary is already a combined tree! */,\n\t);\n\tconst createNewSummary: CombinedAppAndProtocolSummary = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: {\n\t\t\t\".protocol\": protocolSummary,\n\t\t\t\".app\": appSummary,\n\t\t},\n\t};\n\treturn createNewSummary;\n}\n\n/**\n * Converts a summary to snapshot tree and separate its blob contents\n * to align detached container format with IPendingContainerState\n * @param summary - ISummaryTree\n */\nfunction convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): SnapshotWithBlobs {\n\tlet blobContents: ISerializableBlobContents = {};\n\tconst treeNode: ISnapshotTree = {\n\t\tblobs: {},\n\t\ttrees: {},\n\t\tid: uuid(),\n\t\tunreferenced: summary.unreferenced,\n\t\tgroupId: summary.groupId,\n\t};\n\tconst keys = Object.keys(summary.tree);\n\tfor (const key of keys) {\n\t\tconst summaryObject = summary.tree[key];\n\n\t\tswitch (summaryObject.type) {\n\t\t\tcase SummaryType.Tree: {\n\t\t\t\tconst innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);\n\t\t\t\ttreeNode.trees[key] = innerSnapshot.baseSnapshot;\n\t\t\t\tblobContents = { ...blobContents, ...innerSnapshot.snapshotBlobs };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Attachment:\n\t\t\t\ttreeNode.blobs[key] = summaryObject.id;\n\t\t\t\tbreak;\n\t\t\tcase SummaryType.Blob: {\n\t\t\t\tconst blobId = uuid();\n\t\t\t\ttreeNode.blobs[key] = blobId;\n\t\t\t\tconst contentString: string =\n\t\t\t\t\tsummaryObject.content instanceof Uint8Array\n\t\t\t\t\t\t? Uint8ArrayToString(summaryObject.content)\n\t\t\t\t\t\t: summaryObject.content;\n\t\t\t\tblobContents[blobId] = contentString;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SummaryType.Handle:\n\t\t\t\tthrow new LoggingError(\n\t\t\t\t\t\"No handles should be there in summary in detached container!!\",\n\t\t\t\t);\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(summaryObject, `Unknown tree type ${(summaryObject as any).type}`);\n\t\t\t}\n\t\t}\n\t}\n\tconst pendingSnapshot = { baseSnapshot: treeNode, snapshotBlobs: blobContents };\n\treturn pendingSnapshot;\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotToSnapshotInfo(snapshot: ISnapshot): ISnapshotInfo {\n\tassert(snapshot.sequenceNumber !== undefined, 0x93a /* Snapshot sequence number is missing */);\n\tconst snapshotBlobs: ISerializableBlobContents = {};\n\tfor (const [blobId, arrayBufferLike] of snapshot.blobContents.entries()) {\n\t\tsnapshotBlobs[blobId] = bufferToString(arrayBufferLike, \"utf8\");\n\t}\n\treturn {\n\t\tbaseSnapshot: snapshot.snapshotTree,\n\t\tsnapshotBlobs,\n\t\tsnapshotSequenceNumber: snapshot.sequenceNumber,\n\t};\n}\n\n/**\n * Converts a snapshot to snapshotInfo with its blob contents\n * to align detached container format with IPendingContainerState\n *\n * Note, this assumes the ISnapshot sequence number is defined. Otherwise an assert will be thrown\n * @param snapshot - ISnapshot\n */\nexport function convertSnapshotInfoToSnapshot(\n\tsnapshotInfo: ISnapshotInfo,\n\tsnapshotSequenceNumber: number,\n): ISnapshot {\n\tconst blobContents = new Map<string, ArrayBufferLike>();\n\tfor (const [blobId, serializedContent] of Object.entries(snapshotInfo.snapshotBlobs)) {\n\t\tblobContents.set(blobId, stringToBuffer(serializedContent, \"utf8\"));\n\t}\n\treturn {\n\t\tsnapshotTree: snapshotInfo.baseSnapshot,\n\t\tblobContents,\n\t\tops: [],\n\t\tsequenceNumber: snapshotSequenceNumber,\n\t\tlatestSequenceNumber: undefined,\n\t\tsnapshotFormatV: 1,\n\t};\n}\n\n/**\n * Converts summary parts into a SnapshotTree and its blob contents.\n * @param protocolSummaryTree - Protocol Summary Tree\n * @param appSummaryTree - App Summary Tree\n */\nfunction convertProtocolAndAppSummaryToSnapshotAndBlobs(\n\tprotocolSummaryTree: ISummaryTree,\n\tappSummaryTree: ISummaryTree,\n): SnapshotWithBlobs {\n\tconst combinedSummary: ISummaryTree = {\n\t\ttype: SummaryType.Tree,\n\t\ttree: { ...appSummaryTree.tree },\n\t};\n\n\tcombinedSummary.tree[\".protocol\"] = protocolSummaryTree;\n\tconst snapshotTreeWithBlobContents = convertSummaryToSnapshotAndBlobs(combinedSummary);\n\treturn snapshotTreeWithBlobContents;\n}\n\nexport const getSnapshotTreeAndBlobsFromSerializedContainer = (\n\tdetachedContainerSnapshot: ISummaryTree,\n): SnapshotWithBlobs => {\n\tassert(\n\t\tisCombinedAppAndProtocolSummary(detachedContainerSnapshot),\n\t\t0x8e6 /* Protocol and App summary trees should be present */,\n\t);\n\tconst protocolSummaryTree = detachedContainerSnapshot.tree[\".protocol\"];\n\tconst appSummaryTree = detachedContainerSnapshot.tree[\".app\"];\n\tconst snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotAndBlobs(\n\t\tprotocolSummaryTree,\n\t\tappSummaryTree,\n\t);\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function getProtocolSnapshotTree(snapshot: ISnapshotTree): ISnapshotTree {\n\treturn \".protocol\" in snapshot.trees ? snapshot.trees[\".protocol\"] : snapshot;\n}\n\nexport const combineSnapshotTreeAndSnapshotBlobs = (\n\tbaseSnapshot: ISnapshotTree,\n\tsnapshotBlobs: ISerializableBlobContents,\n): ISnapshotTreeWithBlobContents => {\n\tconst blobsContents: { [path: string]: ArrayBufferLike } = {};\n\n\t// Process blobs in the current level\n\tfor (const [, id] of Object.entries(baseSnapshot.blobs)) {\n\t\tif (snapshotBlobs[id]) {\n\t\t\tblobsContents[id] = stringToBuffer(snapshotBlobs[id], \"utf8\");\n\t\t}\n\t}\n\n\t// Recursively process trees in the current level\n\tconst trees: { [path: string]: ISnapshotTreeWithBlobContents } = {};\n\tfor (const [path, tree] of Object.entries(baseSnapshot.trees)) {\n\t\ttrees[path] = combineSnapshotTreeAndSnapshotBlobs(tree, snapshotBlobs);\n\t}\n\n\t// Create a new snapshot tree with blob contents and processed trees\n\tconst snapshotTreeWithBlobContents: ISnapshotTreeWithBlobContents = {\n\t\t...baseSnapshot,\n\t\tblobsContents,\n\t\ttrees,\n\t};\n\n\treturn snapshotTreeWithBlobContents;\n};\n\nexport function isDeltaStreamConnectionForbiddenError(\n\terror: any,\n): error is DeltaStreamConnectionForbiddenError {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\terror?.errorType === DriverErrorTypes.deltaStreamConnectionForbidden\n\t);\n}\n\n/**\n * Validates format in parsed string get from detached container\n * serialization using IPendingDetachedContainerState format.\n */\nfunction isPendingDetachedContainerState(\n\tdetachedContainerState: IPendingDetachedContainerState,\n): detachedContainerState is IPendingDetachedContainerState {\n\tif (\n\t\tdetachedContainerState?.attached === undefined ||\n\t\tdetachedContainerState?.baseSnapshot === undefined ||\n\t\tdetachedContainerState?.snapshotBlobs === undefined ||\n\t\tdetachedContainerState?.hasAttachmentBlobs === undefined\n\t) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Parses the given string into {@link IPendingDetachedContainerState} format,\n * with validation (if invalid, throws a UsageError).\n * This is the inverse of the JSON.stringify call in {@link Container.serialize}\n */\nexport function getDetachedContainerStateFromSerializedContainer(\n\tserializedContainer: string,\n): IPendingDetachedContainerState {\n\tconst hasBlobsSummaryTree = \".hasAttachmentBlobs\";\n\tconst parsedContainerState = JSON.parse(serializedContainer);\n\tif (isPendingDetachedContainerState(parsedContainerState)) {\n\t\treturn parsedContainerState;\n\t} else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {\n\t\tconst { baseSnapshot, snapshotBlobs } =\n\t\t\tgetSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);\n\t\tconst detachedContainerState: IPendingDetachedContainerState = {\n\t\t\tattached: false,\n\t\t\tbaseSnapshot,\n\t\t\tsnapshotBlobs,\n\t\t\thasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,\n\t\t};\n\t\treturn detachedContainerState;\n\t} else {\n\t\tthrow new UsageError(\"Cannot rehydrate detached container. Incorrect format\");\n\t}\n}\n\n/**\n * Blindly parses the given string into {@link IPendingContainerState} format.\n * This is the inverse of the JSON.stringify call in {@link SerializedStateManager.getPendingLocalState}\n */\nexport function getAttachedContainerStateFromSerializedContainer(\n\tserializedContainer: string | undefined,\n): IPendingContainerState | undefined {\n\treturn serializedContainer !== undefined\n\t\t? (JSON.parse(serializedContainer) as IPendingContainerState)\n\t\t: undefined;\n}\n\n/**\n * Ensures only a single instance of the provided async function is running.\n * If there are multiple calls they will all get the same promise to wait on.\n */\nexport const runSingle = <A extends any[], R>(func: (...args: A) => Promise<R>) => {\n\tlet running:\n\t\t| {\n\t\t\t\targs: A;\n\t\t\t\tresult: Promise<R>;\n\t\t }\n\t\t| undefined;\n\t// don't mark this function async, so we return the same promise,\n\t// rather than one that is wrapped due to async\n\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\treturn (...args: A) => {\n\t\tif (running !== undefined) {\n\t\t\tif (!compareArrays(running.args, args)) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew UsageError(\"Subsequent calls cannot use different arguments.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn running.result;\n\t\t}\n\t\trunning = { args, result: func(...args).finally(() => (running = undefined)) };\n\t\treturn running.result;\n\t};\n};\n\nexport async function getDocumentAttributes(\n\tstorage: Pick<IDocumentStorageService, \"readBlob\">,\n\ttree: ISnapshotTree | undefined,\n): Promise<IDocumentAttributes> {\n\tif (tree === undefined) {\n\t\treturn {\n\t\t\tminimumSequenceNumber: 0,\n\t\t\tsequenceNumber: 0,\n\t\t};\n\t}\n\n\t// Backward compatibility: old docs would have \".attributes\" instead of \"attributes\"\n\tconst attributesHash =\n\t\t\".protocol\" in tree.trees\n\t\t\t? tree.trees[\".protocol\"].blobs.attributes\n\t\t\t: tree.blobs[\".attributes\"];\n\n\tconst attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);\n\n\treturn attributes;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "2.0.0-dev-rc.3.0.0.254866",
3
+ "version": "2.0.0-dev-rc.5.0.0.263932",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -73,13 +73,13 @@
73
73
  "default": "./dist/utils.js"
74
74
  }
75
75
  },
76
- "./alpha": {
76
+ "./legacy": {
77
77
  "import": {
78
- "types": "./lib/alpha.d.ts",
78
+ "types": "./lib/legacy.d.ts",
79
79
  "default": "./lib/index.js"
80
80
  },
81
81
  "require": {
82
- "types": "./dist/alpha.d.ts",
82
+ "types": "./dist/legacy.d.ts",
83
83
  "default": "./dist/index.js"
84
84
  }
85
85
  },
@@ -94,8 +94,8 @@
94
94
  }
95
95
  }
96
96
  },
97
- "main": "dist/index.js",
98
- "types": "./dist/public.d.ts",
97
+ "main": "lib/index.js",
98
+ "types": "lib/public.d.ts",
99
99
  "c8": {
100
100
  "all": true,
101
101
  "cache-dir": "nyc/.cache",
@@ -117,15 +117,15 @@
117
117
  "temp-directory": "nyc/.nyc_output"
118
118
  },
119
119
  "dependencies": {
120
- "@fluid-internal/client-utils": "2.0.0-dev-rc.3.0.0.254866",
121
- "@fluidframework/container-definitions": "2.0.0-dev-rc.3.0.0.254866",
122
- "@fluidframework/core-interfaces": "2.0.0-dev-rc.3.0.0.254866",
123
- "@fluidframework/core-utils": "2.0.0-dev-rc.3.0.0.254866",
124
- "@fluidframework/driver-definitions": "2.0.0-dev-rc.3.0.0.254866",
125
- "@fluidframework/driver-utils": "2.0.0-dev-rc.3.0.0.254866",
120
+ "@fluid-internal/client-utils": "2.0.0-dev-rc.5.0.0.263932",
121
+ "@fluidframework/container-definitions": "2.0.0-dev-rc.5.0.0.263932",
122
+ "@fluidframework/core-interfaces": "2.0.0-dev-rc.5.0.0.263932",
123
+ "@fluidframework/core-utils": "2.0.0-dev-rc.5.0.0.263932",
124
+ "@fluidframework/driver-definitions": "2.0.0-dev-rc.5.0.0.263932",
125
+ "@fluidframework/driver-utils": "2.0.0-dev-rc.5.0.0.263932",
126
126
  "@fluidframework/protocol-base": "^4.0.0",
127
127
  "@fluidframework/protocol-definitions": "^3.2.0",
128
- "@fluidframework/telemetry-utils": "2.0.0-dev-rc.3.0.0.254866",
128
+ "@fluidframework/telemetry-utils": "2.0.0-dev-rc.5.0.0.263932",
129
129
  "@ungap/structured-clone": "^1.2.0",
130
130
  "debug": "^4.3.4",
131
131
  "double-ended-queue": "^2.1.0-0",
@@ -134,14 +134,14 @@
134
134
  "devDependencies": {
135
135
  "@arethetypeswrong/cli": "^0.15.2",
136
136
  "@biomejs/biome": "^1.6.2",
137
- "@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.3.0.0.254866",
138
- "@fluid-private/test-loader-utils": "2.0.0-dev-rc.3.0.0.254866",
139
- "@fluid-tools/build-cli": "^0.35.0",
137
+ "@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.5.0.0.263932",
138
+ "@fluid-private/test-loader-utils": "2.0.0-dev-rc.5.0.0.263932",
139
+ "@fluid-tools/build-cli": "^0.38.0",
140
140
  "@fluidframework/build-common": "^2.0.3",
141
- "@fluidframework/build-tools": "^0.35.0",
142
- "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.8.0.0",
141
+ "@fluidframework/build-tools": "^0.38.0",
142
+ "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-rc.3.0.0",
143
143
  "@fluidframework/eslint-config-fluid": "^5.1.0",
144
- "@microsoft/api-extractor": "^7.42.3",
144
+ "@microsoft/api-extractor": "^7.43.1",
145
145
  "@types/debug": "^4.1.5",
146
146
  "@types/double-ended-queue": "^2.1.0",
147
147
  "@types/mocha": "^9.1.1",
@@ -164,18 +164,20 @@
164
164
  },
165
165
  "typeValidation": {
166
166
  "broken": {
167
- "InterfaceDeclaration_IContainerExperimental": {
168
- "forwardCompat": false
167
+ "InterfaceDeclaration_IProtocolHandler": {
168
+ "forwardCompat": false,
169
+ "backCompat": false
169
170
  },
170
- "InterfaceDeclaration_IParsedUrl": {
171
- "forwardCompat": false
171
+ "InterfaceDeclaration_IContainerExperimental": {
172
+ "forwardCompat": false,
173
+ "backCompat": false
172
174
  }
173
175
  }
174
176
  },
175
177
  "scripts": {
176
178
  "api": "fluid-build . --task api",
177
- "api-extractor:commonjs": "flub generate entrypoints --outDir ./dist",
178
- "api-extractor:esnext": "flub generate entrypoints --outDir ./lib",
179
+ "api-extractor:commonjs": "flub generate entrypoints --outFileAlpha legacy --outDir ./dist",
180
+ "api-extractor:esnext": "flub generate entrypoints --outFileAlpha legacy --outDir ./lib --node10TypeCompat",
179
181
  "build": "fluid-build . --task build",
180
182
  "build:commonjs": "fluid-build . --task commonjs",
181
183
  "build:compile": "fluid-build . --task compile",
@@ -185,26 +187,27 @@
185
187
  "build:test": "npm run build:test:esm && npm run build:test:cjs",
186
188
  "build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
187
189
  "build:test:esm": "tsc --project ./src/test/tsconfig.json",
188
- "check:are-the-types-wrong": "attw --pack . --entrypoints .",
190
+ "check:are-the-types-wrong": "attw --pack . --exclude-entrypoints ./internal/test/container ./internal/test/contracts ./internal/test/connectionManager ./internal/test/deltaManager ./internal/test/utils",
189
191
  "check:prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
190
192
  "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json",
191
193
  "ci:build:docs": "api-extractor run",
192
- "clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
194
+ "clean": "rimraf --glob dist lib \"*.d.ts\" \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
193
195
  "eslint": "eslint --format stylish src",
194
196
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
195
197
  "format": "fluid-build --task format .",
196
198
  "format:prettier": "prettier --write . --cache --ignore-path ../../../.prettierignore",
197
199
  "lint": "fluid-build . --task lint",
198
200
  "lint:fix": "fluid-build . --task eslint:fix --task format",
201
+ "place:cjs:package-stub": "copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
199
202
  "test": "npm run test:mocha",
200
203
  "test:coverage": "c8 npm test",
201
204
  "test:mocha": "npm run test:mocha:esm && echo skipping cjs to avoid overhead - npm run test:mocha:cjs",
202
205
  "test:mocha:cjs": "mocha --recursive \"dist/test/**/*.spec.*js\" --exit",
203
206
  "test:mocha:esm": "mocha --recursive \"lib/test/**/*.spec.*js\" --exit",
204
207
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
205
- "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
206
- "tsc:watch": "tsc --watch",
207
- "typetests:gen": "fluid-type-test-generator",
208
+ "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && npm run place:cjs:package-stub",
209
+ "tsc:watch": "npm run place:cjs:package-stub && fluid-tsc commonjs --project ./tsconfig.cjs.json --watch",
210
+ "typetests:gen": "flub generate typetests --dir . -v --publicFallback",
208
211
  "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
209
212
  }
210
213
  }
package/src/attachment.ts CHANGED
@@ -132,19 +132,18 @@ export interface AttachProcessProps {
132
132
  * This method is retriable on failure. Based on the provided initialAttachmentData
133
133
  * this method will resume the attachment process and attempt to complete it.
134
134
  *
135
- * @param props - The data and services necessary to run the attachment process
135
+ * @param AttachProcessProps - The data and services necessary to run the attachment process
136
+ * @returns - The attach summary (only if offline load is enabled), or undefined
136
137
  */
137
- export const runRetriableAttachProcess = async (
138
- props: AttachProcessProps,
139
- ): Promise<SnapshotWithBlobs | undefined> => {
140
- const {
141
- detachedBlobStorage,
142
- createOrGetStorageService,
143
- setAttachmentData,
144
- createAttachmentSummary,
145
- offlineLoadEnabled,
146
- } = props;
147
- let currentData: AttachmentData = props.initialAttachmentData;
138
+ export const runRetriableAttachProcess = async ({
139
+ detachedBlobStorage,
140
+ createOrGetStorageService,
141
+ setAttachmentData,
142
+ createAttachmentSummary,
143
+ offlineLoadEnabled,
144
+ initialAttachmentData,
145
+ }: AttachProcessProps): Promise<SnapshotWithBlobs | undefined> => {
146
+ let currentData: AttachmentData = initialAttachmentData;
148
147
 
149
148
  if (currentData.blobs === undefined) {
150
149
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
@@ -161,7 +160,7 @@ export const runRetriableAttachProcess = async (
161
160
  }
162
161
  : {
163
162
  state: AttachState.Attaching,
164
- summary: props.createAttachmentSummary(),
163
+ summary: createAttachmentSummary(),
165
164
  blobs: "none",
166
165
  };
167
166
  setAttachmentData(currentData);
package/src/audience.ts CHANGED
@@ -3,16 +3,21 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { EventEmitter } from "@fluid-internal/client-utils";
7
- import { IAudienceOwner } from "@fluidframework/container-definitions/internal";
6
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
+ import {
8
+ IAudienceEvents,
9
+ IAudienceOwner,
10
+ ISelf,
11
+ } from "@fluidframework/container-definitions/internal";
8
12
  import { assert } from "@fluidframework/core-utils/internal";
9
13
  import { IClient } from "@fluidframework/protocol-definitions";
10
14
 
11
15
  /**
12
16
  * Audience represents all clients connected to the op stream.
13
17
  */
14
- export class Audience extends EventEmitter implements IAudienceOwner {
18
+ export class Audience extends TypedEventEmitter<IAudienceEvents> implements IAudienceOwner {
15
19
  private readonly members = new Map<string, IClient>();
20
+ private _currentClientId: string | undefined;
16
21
 
17
22
  constructor() {
18
23
  super();
@@ -20,12 +25,28 @@ export class Audience extends EventEmitter implements IAudienceOwner {
20
25
  super.setMaxListeners(0);
21
26
  }
22
27
 
23
- public on(
24
- event: "addMember" | "removeMember",
25
- listener: (clientId: string, client: IClient) => void,
26
- ): this;
27
- public on(event: string, listener: (...args: any[]) => void): this {
28
- return super.on(event, listener);
28
+ public getSelf(): ISelf | undefined {
29
+ return this._currentClientId === undefined
30
+ ? undefined
31
+ : {
32
+ clientId: this._currentClientId,
33
+ client: this.getMember(this._currentClientId),
34
+ };
35
+ }
36
+
37
+ public setCurrentClientId(clientId: string): void {
38
+ if (this._currentClientId !== clientId) {
39
+ const oldId = this._currentClientId;
40
+ this._currentClientId = clientId;
41
+ // this.getMember(clientId) could resolve to undefined in these two cases:
42
+ // 1) Feature gates controlling ConnectionStateHandler() behavior are off
43
+ // 2) we are loading from stashed state and audience is empty, but we remember and set prior clientId
44
+ this.emit(
45
+ "selfChanged",
46
+ oldId === undefined ? undefined : ({ clientId: oldId } satisfies ISelf),
47
+ { clientId, client: this.getMember(clientId) } satisfies ISelf,
48
+ );
49
+ }
29
50
  }
30
51
 
31
52
  /**
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IDeltaManager } from "@fluidframework/container-definitions";
6
+ import { IDeltaManager } from "@fluidframework/container-definitions/internal";
7
7
  import { IDisposable } from "@fluidframework/core-interfaces";
8
8
  import { assert } from "@fluidframework/core-utils/internal";
9
9
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
@@ -8,14 +8,15 @@ import {
8
8
  ICriticalContainerError,
9
9
  IDeltaQueue,
10
10
  ReadOnlyInfo,
11
- } from "@fluidframework/container-definitions";
11
+ } from "@fluidframework/container-definitions/internal";
12
12
  import { IDisposable, ITelemetryBaseProperties, LogLevel } from "@fluidframework/core-interfaces";
13
13
  import { assert } from "@fluidframework/core-utils/internal";
14
- import { DriverErrorTypes, IAnyDriverError } from "@fluidframework/driver-definitions";
15
14
  import {
16
15
  IDocumentDeltaConnection,
17
16
  IDocumentDeltaConnectionEvents,
18
17
  IDocumentService,
18
+ DriverErrorTypes,
19
+ IAnyDriverError,
19
20
  } from "@fluidframework/driver-definitions/internal";
20
21
  import {
21
22
  calculateMaxWaitTime,
@@ -42,11 +43,12 @@ import {
42
43
  MessageType,
43
44
  ScopeType,
44
45
  } from "@fluidframework/protocol-definitions";
45
- import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
46
46
  import {
47
+ ITelemetryLoggerExt,
47
48
  GenericError,
48
49
  UsageError,
49
50
  formatTick,
51
+ generateStack,
50
52
  isFluidError,
51
53
  normalizeError,
52
54
  } from "@fluidframework/telemetry-utils/internal";
@@ -203,6 +205,9 @@ export class ConnectionManager implements IConnectionManager {
203
205
  private pendingConnection: IPendingConnection | undefined;
204
206
  private connection: IDocumentDeltaConnection | undefined;
205
207
 
208
+ /** Details about connection. undefined if there is no active connection. */
209
+ private _connectionDetails?: IConnectionDetailsInternal;
210
+
206
211
  /** file ACL - whether user has only read-only access to a file */
207
212
  private _readonlyPermissions: boolean | undefined;
208
213
 
@@ -255,6 +260,12 @@ export class ConnectionManager implements IConnectionManager {
255
260
  public get clientId() {
256
261
  return this.connection?.clientId;
257
262
  }
263
+
264
+ /** Details about connection. undefined if there is no active connection. */
265
+ public get connectionDetails() {
266
+ return this._connectionDetails;
267
+ }
268
+
258
269
  /**
259
270
  * Automatic reconnecting enabled or disabled.
260
271
  * If set to Never, then reconnecting will never be allowed.
@@ -505,21 +516,7 @@ export class ConnectionManager implements IConnectionManager {
505
516
  ): Promise<void> {
506
517
  assert(!this._disposed, 0x26a /* "not closed" */);
507
518
 
508
- if (this.connection !== undefined) {
509
- return; // Connection attempt already completed successfully
510
- }
511
-
512
- let pendingConnectionMode;
513
- if (this.pendingConnection !== undefined) {
514
- pendingConnectionMode = this.pendingConnection.connectionMode;
515
- this.cancelConnection(reason); // Throw out in-progress connection attempt in favor of new attempt
516
- assert(
517
- this.pendingConnection === undefined,
518
- 0x344 /* this.pendingConnection should be undefined */,
519
- );
520
- }
521
- // If there is no specified ConnectionMode, try the previous mode, if there is no previous mode use default
522
- let requestedMode = connectionMode ?? pendingConnectionMode ?? this.defaultReconnectionMode;
519
+ let requestedMode = connectionMode ?? this.defaultReconnectionMode;
523
520
 
524
521
  // if we have any non-acked ops from last connection, reconnect as "write".
525
522
  // without that we would connect in view-only mode, which will result in immediate
@@ -530,9 +527,33 @@ export class ConnectionManager implements IConnectionManager {
530
527
  requestedMode = "write";
531
528
  }
532
529
 
530
+ if (this.connection !== undefined || this.pendingConnection !== undefined) {
531
+ // Connection attempt already completed successfully or is in progress
532
+ // In general, there should be no issues if the modes do not match:
533
+ // If at some point it was Ok to connect as "read" (i.e. there were no pending ops we had to track),
534
+ // then it should be Ok to use "read" connection even if for some reason request came in to connect as "write"
535
+ // (though that should never happen)
536
+ // The opposite should be fine as well: we may have had idle "write" connection, and request to reconnect came in,
537
+ // using default "read" mode.
538
+ // That all said, let's understand better where such mismatches are coming from.
539
+ const mode = this.connection?.mode ?? this.pendingConnection?.connectionMode;
540
+ if (mode !== requestedMode) {
541
+ this.logger.sendTelemetryEvent({
542
+ eventName: "ConnectionModeMismatch",
543
+ connected: this.connection !== undefined,
544
+ mode,
545
+ requestedMode,
546
+ stack: generateStack(),
547
+ });
548
+ }
549
+ return;
550
+ }
551
+
533
552
  const docService = this.serviceProvider();
534
553
  assert(docService !== undefined, 0x2a7 /* "Container is not attached" */);
535
554
 
555
+ this.props.establishConnectionHandler(reason);
556
+
536
557
  let connection: IDocumentDeltaConnection | undefined;
537
558
 
538
559
  if (docService.policies?.storageOnly === true) {
@@ -556,7 +577,6 @@ export class ConnectionManager implements IConnectionManager {
556
577
  connectionMode: requestedMode,
557
578
  };
558
579
 
559
- this.props.establishConnectionHandler(reason);
560
580
  // This loop will keep trying to connect until successful, with a delay between each iteration.
561
581
  while (connection === undefined) {
562
582
  if (this._disposed) {
@@ -644,6 +664,12 @@ export class ConnectionManager implements IConnectionManager {
644
664
 
645
665
  lastError = origError;
646
666
 
667
+ // We will not perform retries if the container disconnected and the ReconnectMode is set to Disabled or Never
668
+ // so break out of the re-connecting while-loop after first attempt
669
+ if (this.reconnectMode !== ReconnectMode.Enabled) {
670
+ return;
671
+ }
672
+
647
673
  const waitStartTime = performance.now();
648
674
  const retryDelayFromError = getRetryDelayFromError(origError);
649
675
  // If the error told us to wait or browser signals us that we are offline, then calculate the time we
@@ -751,6 +777,7 @@ export class ConnectionManager implements IConnectionManager {
751
777
  const connection = this.connection;
752
778
  // Avoid any re-entrancy - clear object reference
753
779
  this.connection = undefined;
780
+ this._connectionDetails = undefined;
754
781
 
755
782
  // Remove listeners first so we don't try to retrigger this flow accidentally through reconnectOnError
756
783
  connection.off("op", this.opHandler);
@@ -782,7 +809,10 @@ export class ConnectionManager implements IConnectionManager {
782
809
  );
783
810
  this.pendingConnection.abort();
784
811
  this.pendingConnection = undefined;
785
- this.logger.sendTelemetryEvent({ eventName: "ConnectionCancelReceived" });
812
+ this.logger.sendTelemetryEvent({
813
+ eventName: "ConnectionCancelReceived",
814
+ reason: reason.text,
815
+ });
786
816
  this.props.cancelConnectionHandler({
787
817
  text: `Cancel Pending Connection due to ${reason.text}`,
788
818
  error: reason.error,
@@ -903,9 +933,9 @@ export class ConnectionManager implements IConnectionManager {
903
933
  this.connectFirstConnection ? "InitialOps" : "ReconnectOps",
904
934
  );
905
935
 
906
- const details = ConnectionManager.detailsFromConnection(connection, reason);
907
- details.checkpointSequenceNumber = checkpointSequenceNumber;
908
- this.props.connectHandler(details);
936
+ this._connectionDetails = ConnectionManager.detailsFromConnection(connection, reason);
937
+ this._connectionDetails.checkpointSequenceNumber = checkpointSequenceNumber;
938
+ this.props.connectHandler(this._connectionDetails);
909
939
 
910
940
  this.connectFirstConnection = false;
911
941