@fluidframework/container-loader 2.0.0-rc.3.0.3 → 2.0.0-rc.4.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 (188) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/api-report/container-loader.api.md +5 -1
  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 +57 -38
  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/legacy.d.ts +2 -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 +1 -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 +150 -34
  78. package/dist/serializedStateManager.js.map +1 -1
  79. package/dist/utils.d.ts +11 -1
  80. package/dist/utils.d.ts.map +1 -1
  81. package/dist/utils.js +29 -14
  82. package/dist/utils.js.map +1 -1
  83. package/lib/attachment.d.ts +3 -2
  84. package/lib/attachment.d.ts.map +1 -1
  85. package/lib/attachment.js +5 -5
  86. package/lib/attachment.js.map +1 -1
  87. package/lib/audience.d.ts +6 -4
  88. package/lib/audience.d.ts.map +1 -1
  89. package/lib/audience.js +19 -4
  90. package/lib/audience.js.map +1 -1
  91. package/lib/catchUpMonitor.d.ts +1 -1
  92. package/lib/catchUpMonitor.d.ts.map +1 -1
  93. package/lib/catchUpMonitor.js.map +1 -1
  94. package/lib/connectionManager.d.ts +7 -3
  95. package/lib/connectionManager.d.ts.map +1 -1
  96. package/lib/connectionManager.js +36 -17
  97. package/lib/connectionManager.js.map +1 -1
  98. package/lib/connectionStateHandler.d.ts +31 -10
  99. package/lib/connectionStateHandler.d.ts.map +1 -1
  100. package/lib/connectionStateHandler.js +49 -36
  101. package/lib/connectionStateHandler.js.map +1 -1
  102. package/lib/container.d.ts +22 -13
  103. package/lib/container.d.ts.map +1 -1
  104. package/lib/container.js +146 -118
  105. package/lib/container.js.map +1 -1
  106. package/lib/containerContext.d.ts +3 -3
  107. package/lib/containerContext.d.ts.map +1 -1
  108. package/lib/containerContext.js.map +1 -1
  109. package/lib/containerStorageAdapter.d.ts +12 -3
  110. package/lib/containerStorageAdapter.d.ts.map +1 -1
  111. package/lib/containerStorageAdapter.js +42 -4
  112. package/lib/containerStorageAdapter.js.map +1 -1
  113. package/lib/contracts.d.ts +2 -2
  114. package/lib/contracts.d.ts.map +1 -1
  115. package/lib/contracts.js +1 -1
  116. package/lib/contracts.js.map +1 -1
  117. package/lib/debugLogger.d.ts +1 -2
  118. package/lib/debugLogger.d.ts.map +1 -1
  119. package/lib/debugLogger.js.map +1 -1
  120. package/lib/deltaManager.d.ts +5 -6
  121. package/lib/deltaManager.d.ts.map +1 -1
  122. package/lib/deltaManager.js +10 -5
  123. package/lib/deltaManager.js.map +1 -1
  124. package/lib/deltaQueue.d.ts +1 -1
  125. package/lib/deltaQueue.d.ts.map +1 -1
  126. package/lib/deltaQueue.js.map +1 -1
  127. package/lib/error.d.ts +1 -2
  128. package/lib/error.d.ts.map +1 -1
  129. package/lib/error.js.map +1 -1
  130. package/lib/index.d.ts +1 -0
  131. package/lib/index.d.ts.map +1 -1
  132. package/lib/index.js +1 -0
  133. package/lib/index.js.map +1 -1
  134. package/lib/legacy.d.ts +2 -2
  135. package/lib/loadPaused.d.ts +35 -0
  136. package/lib/loadPaused.d.ts.map +1 -0
  137. package/lib/loadPaused.js +111 -0
  138. package/lib/loadPaused.js.map +1 -0
  139. package/lib/loader.d.ts +1 -1
  140. package/lib/loader.d.ts.map +1 -1
  141. package/lib/loader.js +3 -16
  142. package/lib/loader.js.map +1 -1
  143. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  144. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +1 -1
  145. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  146. package/lib/packageVersion.d.ts +1 -1
  147. package/lib/packageVersion.js +1 -1
  148. package/lib/packageVersion.js.map +1 -1
  149. package/lib/protocol.d.ts.map +1 -1
  150. package/lib/protocol.js +3 -0
  151. package/lib/protocol.js.map +1 -1
  152. package/lib/public.d.ts +1 -1
  153. package/lib/retriableDocumentStorageService.d.ts +1 -1
  154. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  155. package/lib/retriableDocumentStorageService.js +1 -1
  156. package/lib/retriableDocumentStorageService.js.map +1 -1
  157. package/lib/serializedStateManager.d.ts +89 -9
  158. package/lib/serializedStateManager.d.ts.map +1 -1
  159. package/lib/serializedStateManager.js +146 -30
  160. package/lib/serializedStateManager.js.map +1 -1
  161. package/lib/tsdoc-metadata.json +1 -1
  162. package/lib/utils.d.ts +11 -1
  163. package/lib/utils.d.ts.map +1 -1
  164. package/lib/utils.js +15 -1
  165. package/lib/utils.js.map +1 -1
  166. package/package.json +24 -21
  167. package/src/attachment.ts +12 -13
  168. package/src/audience.ts +30 -9
  169. package/src/catchUpMonitor.ts +1 -1
  170. package/src/connectionManager.ts +45 -22
  171. package/src/connectionStateHandler.ts +78 -45
  172. package/src/container.ts +181 -160
  173. package/src/containerContext.ts +2 -2
  174. package/src/containerStorageAdapter.ts +61 -6
  175. package/src/contracts.ts +5 -4
  176. package/src/debugLogger.ts +1 -1
  177. package/src/deltaManager.ts +15 -8
  178. package/src/deltaQueue.ts +1 -1
  179. package/src/error.ts +1 -1
  180. package/src/index.ts +1 -0
  181. package/src/loadPaused.ts +140 -0
  182. package/src/loader.ts +6 -23
  183. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +1 -1
  184. package/src/packageVersion.ts +1 -1
  185. package/src/protocol.ts +4 -0
  186. package/src/retriableDocumentStorageService.ts +5 -2
  187. package/src/serializedStateManager.ts +215 -48
  188. package/src/utils.ts +19 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @fluidframework/container-loader
2
2
 
3
+ ## 2.0.0-rc.4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Audience & connection sequencing improvements [96872186d0](https://github.com/microsoft/FluidFramework/commit/96872186d0d0f245c1fece7d19b3743e501679b6)
8
+
9
+ Here are breaking changes in Audience behavior:
10
+
11
+ 1. IAudience no longer implements EventEmmiter. If you used addListener() or removeListener(), please replace with on() & off() respectively.
12
+ 2. IAudience interface implements getSelf() method and "selfChanged" event.
13
+ 3. IContainerContext.audience is no longer optional
14
+ 4. "connected" events are now raised (various API surfaces - IContainer, IContainerRuntime, IFluidDataStoreRuntime, etc.) a bit later in reconnection sequence for "read" connections - only after client receives its own "join" signal and caught up on ops, which makes it symmetrical with "write" connections.
15
+
16
+ - If this change in behavior breaks some scenario, please let us know immediately, but you can revert that behavior using the following feature gates:
17
+ - "Fluid.Container.DisableCatchUpBeforeDeclaringConnected"
18
+ - "Fluid.Container.DisableJoinSignalWait"
19
+
3
20
  ## 2.0.0-rc.3.0.0
4
21
 
5
22
  ### Major Changes
@@ -15,6 +15,7 @@ import { IDocumentStorageService } from '@fluidframework/driver-definitions/inte
15
15
  import { IFluidCodeDetails } from '@fluidframework/container-definitions/internal';
16
16
  import { IFluidModule } from '@fluidframework/container-definitions/internal';
17
17
  import { IHostLoader } from '@fluidframework/container-definitions/internal';
18
+ import { ILoader } from '@fluidframework/container-definitions/internal';
18
19
  import { ILoaderOptions as ILoaderOptions_2 } from '@fluidframework/container-definitions/internal';
19
20
  import { ILocationRedirectionError } from '@fluidframework/driver-definitions/internal';
20
21
  import { IProtocolHandler as IProtocolHandler_2 } from '@fluidframework/protocol-base';
@@ -23,7 +24,7 @@ import { IQuorumSnapshot } from '@fluidframework/protocol-base';
23
24
  import { IRequest } from '@fluidframework/core-interfaces';
24
25
  import { ISignalMessage } from '@fluidframework/protocol-definitions';
25
26
  import { ITelemetryBaseLogger } from '@fluidframework/core-interfaces';
26
- import { ITelemetryLoggerExt } from '@fluidframework/telemetry-utils';
27
+ import { ITelemetryLoggerExt } from '@fluidframework/telemetry-utils/internal';
27
28
  import { IUrlResolver } from '@fluidframework/driver-definitions/internal';
28
29
 
29
30
  // @public
@@ -107,6 +108,9 @@ export interface IProtocolHandler extends IProtocolHandler_2 {
107
108
  // @internal
108
109
  export function isLocationRedirectionError(error: any): error is ILocationRedirectionError;
109
110
 
111
+ // @internal
112
+ export function loadContainerPaused(loader: ILoader, request: IRequest, loadToSequenceNumber?: number, signal?: AbortSignal): Promise<IContainer>;
113
+
110
114
  // @alpha
111
115
  export class Loader implements IHostLoader {
112
116
  constructor(loaderProps: ILoaderProps);
@@ -106,7 +106,8 @@ export interface AttachProcessProps {
106
106
  * This method is retriable on failure. Based on the provided initialAttachmentData
107
107
  * this method will resume the attachment process and attempt to complete it.
108
108
  *
109
- * @param props - The data and services necessary to run the attachment process
109
+ * @param AttachProcessProps - The data and services necessary to run the attachment process
110
+ * @returns - The attach summary (only if offline load is enabled), or undefined
110
111
  */
111
- export declare const runRetriableAttachProcess: (props: AttachProcessProps) => Promise<SnapshotWithBlobs | undefined>;
112
+ export declare const runRetriableAttachProcess: ({ detachedBlobStorage, createOrGetStorageService, setAttachmentData, createAttachmentSummary, offlineLoadEnabled, initialAttachmentData, }: AttachProcessProps) => Promise<SnapshotWithBlobs | undefined>;
112
113
  //# sourceMappingURL=attachment.d.ts.map
@@ -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,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAC;AACtF,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE;;;;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;;;;;8DAK0D;IAC1D,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,CAAC,oBAAoB,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;IAE9F;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE,CACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B,6BAA6B,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACrC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,UAC9B,kBAAkB,KACvB,QAAQ,iBAAiB,GAAG,SAAS,CAqFvC,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,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAC;AACtF,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE;;;;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;;;;;8DAK0D;IAC1D,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,CAAC,oBAAoB,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;IAE9F;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE,CACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B,6BAA6B,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,+IAOnC,kBAAkB,KAAG,QAAQ,iBAAiB,GAAG,SAAS,CA8E5D,CAAC"}
@@ -13,11 +13,11 @@ const utils_js_1 = require("./utils.js");
13
13
  * This method is retriable on failure. Based on the provided initialAttachmentData
14
14
  * this method will resume the attachment process and attempt to complete it.
15
15
  *
16
- * @param props - The data and services necessary to run the attachment process
16
+ * @param AttachProcessProps - The data and services necessary to run the attachment process
17
+ * @returns - The attach summary (only if offline load is enabled), or undefined
17
18
  */
18
- const runRetriableAttachProcess = async (props) => {
19
- const { detachedBlobStorage, createOrGetStorageService, setAttachmentData, createAttachmentSummary, offlineLoadEnabled, } = props;
20
- let currentData = props.initialAttachmentData;
19
+ const runRetriableAttachProcess = async ({ detachedBlobStorage, createOrGetStorageService, setAttachmentData, createAttachmentSummary, offlineLoadEnabled, initialAttachmentData, }) => {
20
+ let currentData = initialAttachmentData;
21
21
  if (currentData.blobs === undefined) {
22
22
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
23
23
  const outstandingAttachmentBlobs = detachedBlobStorage !== undefined && detachedBlobStorage.size > 0;
@@ -32,7 +32,7 @@ const runRetriableAttachProcess = async (props) => {
32
32
  }
33
33
  : {
34
34
  state: container_definitions_1.AttachState.Attaching,
35
- summary: props.createAttachmentSummary(),
35
+ summary: createAttachmentSummary(),
36
36
  blobs: "none",
37
37
  };
38
38
  setAttachmentData(currentData);
@@ -1 +1 @@
1
- {"version":3,"file":"attachment.js","sourceRoot":"","sources":["../src/attachment.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 { AttachState } from \"@fluidframework/container-definitions\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions/internal\";\nimport { CombinedAppAndProtocolSummary } from \"@fluidframework/driver-utils/internal\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\n\nimport { IDetachedBlobStorage } from \"./loader.js\";\nimport type { SnapshotWithBlobs } from \"./serializedStateManager.js\";\nimport { getSnapshotTreeAndBlobsFromSerializedContainer } from \"./utils.js\";\n\n/**\n * The default state a newly created detached container will have.\n * All but the state are optional and undefined, they just exist\n * to make the union easy to deal with for both Detached types\n */\nexport interface DetachedDefaultData {\n\treadonly state: AttachState.Detached;\n\treadonly blobs?: undefined;\n\treadonly summary?: undefined;\n\treadonly redirectTable?: undefined;\n}\n\n/**\n * This always follows DetachedDefaultData when there are\n * outstanding blobs in the detached blob storage.\n * The redirect table will get filled up to include data\n * about the blobs as they are uploaded.\n */\nexport interface DetachedDataWithOutstandingBlobs {\n\treadonly state: AttachState.Detached;\n\treadonly blobs: \"outstanding\";\n\treadonly summary?: undefined;\n\treadonly redirectTable: Map<string, string>;\n}\n\n/**\n * This state always follows DetachedDataWithOutstandingBlobs.\n * It signals that all outstanding blobs are done being uploaded,\n * so the container can move to the attaching state.\n */\nexport interface AttachingDataWithBlobs {\n\treadonly state: AttachState.Attaching;\n\treadonly blobs: \"done\";\n\treadonly summary: CombinedAppAndProtocolSummary;\n}\n\n/**\n * This always follows DefaultDetachedState when there are\n * no blobs in the detached blob storage. Because there are\n * no blobs we can immediately get the summary and transition\n * to the attaching state.\n */\nexport interface AttachingDataWithoutBlobs {\n\treadonly state: AttachState.Attaching;\n\treadonly summary: CombinedAppAndProtocolSummary;\n\treadonly blobs: \"none\";\n}\n\n/**\n * The final attachment state which signals the container is fully attached.\n * The baseSnapshotAndBlobs will only be enabled when offline load is enabled.\n */\nexport interface AttachedData {\n\treadonly state: AttachState.Attached;\n}\n\n/**\n * A union of all the attachment data types for\n * tracking across all container attachment states\n */\nexport type AttachmentData =\n\t| DetachedDefaultData\n\t| DetachedDataWithOutstandingBlobs\n\t| AttachingDataWithoutBlobs\n\t| AttachingDataWithBlobs\n\t| AttachedData;\n\n/**\n * The data and services necessary for runRetriableAttachProcess.\n */\nexport interface AttachProcessProps {\n\t/**\n\t * The initial attachment data this call should start with\n\t */\n\treadonly initialAttachmentData: Exclude<AttachmentData, AttachedData>;\n\n\t/**\n\t * The caller should use this callback to keep track of the current\n\t * attachment data, and perform any other operations necessary\n\t * for dealing with attachment state changes, like emitting events\n\t *\n\t * @param attachmentData - the updated attachment data\t */\n\treadonly setAttachmentData: (attachmentData: AttachmentData) => void;\n\n\t/**\n\t * The caller should create and or get services based on the data, and its own information.\n\t * @param data - the data to create services from,\n\t * the summary property being the most relevant part of the data.\n\t * @returns A compatible storage service\n\t */\n\treadonly createOrGetStorageService: (\n\t\tdata: ISummaryTree | undefined,\n\t) => Promise<Pick<IDocumentStorageService, \"createBlob\" | \"uploadSummaryWithContext\">>;\n\n\t/**\n\t * The detached blob storage if it exists.\n\t */\n\treadonly detachedBlobStorage?: Pick<IDetachedBlobStorage, \"getBlobIds\" | \"readBlob\" | \"size\">;\n\n\t/**\n\t * The caller should create the attachment summary for the container.\n\t * @param redirectTable - Maps local blob ids to remote blobs ids.\n\t * @returns The attachment summary for the container.\n\t */\n\treadonly createAttachmentSummary: (\n\t\tredirectTable?: Map<string, string>,\n\t) => CombinedAppAndProtocolSummary;\n\n\t/**\n\t * Whether offline load is enabled or not.\n\t */\n\treadonly offlineLoadEnabled: boolean;\n}\n\n/**\n * Executes the attach process state machine based on the provided data and services.\n * This method is retriable on failure. Based on the provided initialAttachmentData\n * this method will resume the attachment process and attempt to complete it.\n *\n * @param props - The data and services necessary to run the attachment process\n */\nexport const runRetriableAttachProcess = async (\n\tprops: AttachProcessProps,\n): Promise<SnapshotWithBlobs | undefined> => {\n\tconst {\n\t\tdetachedBlobStorage,\n\t\tcreateOrGetStorageService,\n\t\tsetAttachmentData,\n\t\tcreateAttachmentSummary,\n\t\tofflineLoadEnabled,\n\t} = props;\n\tlet currentData: AttachmentData = props.initialAttachmentData;\n\n\tif (currentData.blobs === undefined) {\n\t\t// If attachment blobs were uploaded in detached state we will go through a different attach flow\n\t\tconst outstandingAttachmentBlobs =\n\t\t\tdetachedBlobStorage !== undefined && detachedBlobStorage.size > 0;\n\t\t// Determine the next phase of attaching which depends on if there are attachment blobs\n\t\t// if there are, we will stay detached, so an empty file can be created, and the blobs\n\t\t// uploaded, otherwise we will get the summary to create the file with and move to attaching\n\t\tcurrentData = outstandingAttachmentBlobs\n\t\t\t? {\n\t\t\t\t\tstate: AttachState.Detached,\n\t\t\t\t\tblobs: \"outstanding\",\n\t\t\t\t\tredirectTable: new Map<string, string>(),\n\t\t\t }\n\t\t\t: {\n\t\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\t\tsummary: props.createAttachmentSummary(),\n\t\t\t\t\tblobs: \"none\",\n\t\t\t };\n\t\tsetAttachmentData(currentData);\n\t}\n\n\t// this has to run here, as it is what creates the file\n\t// and we need to file for all possible cases after this point\n\tconst storage = await createOrGetStorageService(currentData.summary);\n\n\tif (currentData.blobs === \"outstanding\") {\n\t\tconst { redirectTable } = currentData;\n\t\t// upload blobs to storage\n\t\tassert(!!detachedBlobStorage, 0x24e /* \"assertion for type narrowing\" */);\n\n\t\t// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to\n\t\t// support blob handles that only know about the local IDs\n\t\twhile (redirectTable.size < detachedBlobStorage.size) {\n\t\t\tconst newIds = detachedBlobStorage.getBlobIds().filter((id) => !redirectTable.has(id));\n\t\t\tfor (const id of newIds) {\n\t\t\t\tconst blob = await detachedBlobStorage.readBlob(id);\n\t\t\t\tconst response = await storage.createBlob(blob);\n\t\t\t\tredirectTable.set(id, response.id);\n\t\t\t}\n\t\t}\n\t\tsetAttachmentData(\n\t\t\t(currentData = {\n\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\tsummary: createAttachmentSummary(redirectTable),\n\t\t\t\tblobs: \"done\",\n\t\t\t}),\n\t\t);\n\t}\n\n\tassert(\n\t\tcurrentData.state === AttachState.Attaching,\n\t\t0x8e2 /* must be attaching by this point */,\n\t);\n\n\tif (currentData.blobs === \"done\") {\n\t\t// done means outstanding blobs were uploaded.\n\t\t// in that case an empty file was created, the blobs were uploaded\n\t\t// and now this finally uploads the summary\n\t\tawait storage.uploadSummaryWithContext(currentData.summary, {\n\t\t\treferenceSequenceNumber: 0,\n\t\t\tackHandle: undefined,\n\t\t\tproposalHandle: undefined,\n\t\t});\n\t}\n\n\tconst snapshot: SnapshotWithBlobs | undefined = offlineLoadEnabled\n\t\t? getSnapshotTreeAndBlobsFromSerializedContainer(currentData.summary)\n\t\t: undefined;\n\n\tsetAttachmentData(\n\t\t(currentData = {\n\t\t\tstate: AttachState.Attached,\n\t\t}),\n\t);\n\treturn snapshot;\n};\n"]}
1
+ {"version":3,"file":"attachment.js","sourceRoot":"","sources":["../src/attachment.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 { AttachState } from \"@fluidframework/container-definitions\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions/internal\";\nimport { CombinedAppAndProtocolSummary } from \"@fluidframework/driver-utils/internal\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\n\nimport { IDetachedBlobStorage } from \"./loader.js\";\nimport type { SnapshotWithBlobs } from \"./serializedStateManager.js\";\nimport { getSnapshotTreeAndBlobsFromSerializedContainer } from \"./utils.js\";\n\n/**\n * The default state a newly created detached container will have.\n * All but the state are optional and undefined, they just exist\n * to make the union easy to deal with for both Detached types\n */\nexport interface DetachedDefaultData {\n\treadonly state: AttachState.Detached;\n\treadonly blobs?: undefined;\n\treadonly summary?: undefined;\n\treadonly redirectTable?: undefined;\n}\n\n/**\n * This always follows DetachedDefaultData when there are\n * outstanding blobs in the detached blob storage.\n * The redirect table will get filled up to include data\n * about the blobs as they are uploaded.\n */\nexport interface DetachedDataWithOutstandingBlobs {\n\treadonly state: AttachState.Detached;\n\treadonly blobs: \"outstanding\";\n\treadonly summary?: undefined;\n\treadonly redirectTable: Map<string, string>;\n}\n\n/**\n * This state always follows DetachedDataWithOutstandingBlobs.\n * It signals that all outstanding blobs are done being uploaded,\n * so the container can move to the attaching state.\n */\nexport interface AttachingDataWithBlobs {\n\treadonly state: AttachState.Attaching;\n\treadonly blobs: \"done\";\n\treadonly summary: CombinedAppAndProtocolSummary;\n}\n\n/**\n * This always follows DefaultDetachedState when there are\n * no blobs in the detached blob storage. Because there are\n * no blobs we can immediately get the summary and transition\n * to the attaching state.\n */\nexport interface AttachingDataWithoutBlobs {\n\treadonly state: AttachState.Attaching;\n\treadonly summary: CombinedAppAndProtocolSummary;\n\treadonly blobs: \"none\";\n}\n\n/**\n * The final attachment state which signals the container is fully attached.\n * The baseSnapshotAndBlobs will only be enabled when offline load is enabled.\n */\nexport interface AttachedData {\n\treadonly state: AttachState.Attached;\n}\n\n/**\n * A union of all the attachment data types for\n * tracking across all container attachment states\n */\nexport type AttachmentData =\n\t| DetachedDefaultData\n\t| DetachedDataWithOutstandingBlobs\n\t| AttachingDataWithoutBlobs\n\t| AttachingDataWithBlobs\n\t| AttachedData;\n\n/**\n * The data and services necessary for runRetriableAttachProcess.\n */\nexport interface AttachProcessProps {\n\t/**\n\t * The initial attachment data this call should start with\n\t */\n\treadonly initialAttachmentData: Exclude<AttachmentData, AttachedData>;\n\n\t/**\n\t * The caller should use this callback to keep track of the current\n\t * attachment data, and perform any other operations necessary\n\t * for dealing with attachment state changes, like emitting events\n\t *\n\t * @param attachmentData - the updated attachment data\t */\n\treadonly setAttachmentData: (attachmentData: AttachmentData) => void;\n\n\t/**\n\t * The caller should create and or get services based on the data, and its own information.\n\t * @param data - the data to create services from,\n\t * the summary property being the most relevant part of the data.\n\t * @returns A compatible storage service\n\t */\n\treadonly createOrGetStorageService: (\n\t\tdata: ISummaryTree | undefined,\n\t) => Promise<Pick<IDocumentStorageService, \"createBlob\" | \"uploadSummaryWithContext\">>;\n\n\t/**\n\t * The detached blob storage if it exists.\n\t */\n\treadonly detachedBlobStorage?: Pick<IDetachedBlobStorage, \"getBlobIds\" | \"readBlob\" | \"size\">;\n\n\t/**\n\t * The caller should create the attachment summary for the container.\n\t * @param redirectTable - Maps local blob ids to remote blobs ids.\n\t * @returns The attachment summary for the container.\n\t */\n\treadonly createAttachmentSummary: (\n\t\tredirectTable?: Map<string, string>,\n\t) => CombinedAppAndProtocolSummary;\n\n\t/**\n\t * Whether offline load is enabled or not.\n\t */\n\treadonly offlineLoadEnabled: boolean;\n}\n\n/**\n * Executes the attach process state machine based on the provided data and services.\n * This method is retriable on failure. Based on the provided initialAttachmentData\n * this method will resume the attachment process and attempt to complete it.\n *\n * @param AttachProcessProps - The data and services necessary to run the attachment process\n * @returns - The attach summary (only if offline load is enabled), or undefined\n */\nexport const runRetriableAttachProcess = async ({\n\tdetachedBlobStorage,\n\tcreateOrGetStorageService,\n\tsetAttachmentData,\n\tcreateAttachmentSummary,\n\tofflineLoadEnabled,\n\tinitialAttachmentData,\n}: AttachProcessProps): Promise<SnapshotWithBlobs | undefined> => {\n\tlet currentData: AttachmentData = initialAttachmentData;\n\n\tif (currentData.blobs === undefined) {\n\t\t// If attachment blobs were uploaded in detached state we will go through a different attach flow\n\t\tconst outstandingAttachmentBlobs =\n\t\t\tdetachedBlobStorage !== undefined && detachedBlobStorage.size > 0;\n\t\t// Determine the next phase of attaching which depends on if there are attachment blobs\n\t\t// if there are, we will stay detached, so an empty file can be created, and the blobs\n\t\t// uploaded, otherwise we will get the summary to create the file with and move to attaching\n\t\tcurrentData = outstandingAttachmentBlobs\n\t\t\t? {\n\t\t\t\t\tstate: AttachState.Detached,\n\t\t\t\t\tblobs: \"outstanding\",\n\t\t\t\t\tredirectTable: new Map<string, string>(),\n\t\t\t }\n\t\t\t: {\n\t\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\t\tsummary: createAttachmentSummary(),\n\t\t\t\t\tblobs: \"none\",\n\t\t\t };\n\t\tsetAttachmentData(currentData);\n\t}\n\n\t// this has to run here, as it is what creates the file\n\t// and we need to file for all possible cases after this point\n\tconst storage = await createOrGetStorageService(currentData.summary);\n\n\tif (currentData.blobs === \"outstanding\") {\n\t\tconst { redirectTable } = currentData;\n\t\t// upload blobs to storage\n\t\tassert(!!detachedBlobStorage, 0x24e /* \"assertion for type narrowing\" */);\n\n\t\t// build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to\n\t\t// support blob handles that only know about the local IDs\n\t\twhile (redirectTable.size < detachedBlobStorage.size) {\n\t\t\tconst newIds = detachedBlobStorage.getBlobIds().filter((id) => !redirectTable.has(id));\n\t\t\tfor (const id of newIds) {\n\t\t\t\tconst blob = await detachedBlobStorage.readBlob(id);\n\t\t\t\tconst response = await storage.createBlob(blob);\n\t\t\t\tredirectTable.set(id, response.id);\n\t\t\t}\n\t\t}\n\t\tsetAttachmentData(\n\t\t\t(currentData = {\n\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\tsummary: createAttachmentSummary(redirectTable),\n\t\t\t\tblobs: \"done\",\n\t\t\t}),\n\t\t);\n\t}\n\n\tassert(\n\t\tcurrentData.state === AttachState.Attaching,\n\t\t0x8e2 /* must be attaching by this point */,\n\t);\n\n\tif (currentData.blobs === \"done\") {\n\t\t// done means outstanding blobs were uploaded.\n\t\t// in that case an empty file was created, the blobs were uploaded\n\t\t// and now this finally uploads the summary\n\t\tawait storage.uploadSummaryWithContext(currentData.summary, {\n\t\t\treferenceSequenceNumber: 0,\n\t\t\tackHandle: undefined,\n\t\t\tproposalHandle: undefined,\n\t\t});\n\t}\n\n\tconst snapshot: SnapshotWithBlobs | undefined = offlineLoadEnabled\n\t\t? getSnapshotTreeAndBlobsFromSerializedContainer(currentData.summary)\n\t\t: undefined;\n\n\tsetAttachmentData(\n\t\t(currentData = {\n\t\t\tstate: AttachState.Attached,\n\t\t}),\n\t);\n\treturn snapshot;\n};\n"]}
@@ -2,16 +2,18 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { EventEmitter } from "@fluid-internal/client-utils";
6
- import { IAudienceOwner } from "@fluidframework/container-definitions/internal";
5
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
6
+ import { IAudienceEvents, IAudienceOwner, ISelf } from "@fluidframework/container-definitions/internal";
7
7
  import { IClient } from "@fluidframework/protocol-definitions";
8
8
  /**
9
9
  * Audience represents all clients connected to the op stream.
10
10
  */
11
- export declare class Audience extends EventEmitter implements IAudienceOwner {
11
+ export declare class Audience extends TypedEventEmitter<IAudienceEvents> implements IAudienceOwner {
12
12
  private readonly members;
13
+ private _currentClientId;
13
14
  constructor();
14
- on(event: "addMember" | "removeMember", listener: (clientId: string, client: IClient) => void): this;
15
+ getSelf(): ISelf | undefined;
16
+ setCurrentClientId(clientId: string): void;
15
17
  /**
16
18
  * Adds a new client to the audience
17
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"audience.d.ts","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAEhF,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAE/D;;GAEG;AACH,qBAAa,QAAS,SAAQ,YAAa,YAAW,cAAc;IACnE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;;IAQ/C,EAAE,CACR,KAAK,EAAE,WAAW,GAAG,cAAc,EACnC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GACnD,IAAI;IAKP;;OAEG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAenD;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAW9C;;;;;OAKG;IACI,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAIzC;;;;;OAKG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;CAGvD"}
1
+ {"version":3,"file":"audience.d.ts","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EACN,eAAe,EACf,cAAc,EACd,KAAK,EACL,MAAM,gDAAgD,CAAC;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAE/D;;GAEG;AACH,qBAAa,QAAS,SAAQ,iBAAiB,CAAC,eAAe,CAAE,YAAW,cAAc;IACzF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,OAAO,CAAC,gBAAgB,CAAqB;;IAQtC,OAAO,IAAI,KAAK,GAAG,SAAS;IAS5B,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAejD;;OAEG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAenD;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAW9C;;;;;OAKG;IACI,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAIzC;;;;;OAKG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;CAGvD"}
package/dist/audience.js CHANGED
@@ -10,15 +10,30 @@ const internal_1 = require("@fluidframework/core-utils/internal");
10
10
  /**
11
11
  * Audience represents all clients connected to the op stream.
12
12
  */
13
- class Audience extends client_utils_1.EventEmitter {
13
+ class Audience extends client_utils_1.TypedEventEmitter {
14
14
  constructor() {
15
15
  super();
16
16
  this.members = new Map();
17
17
  // We are expecting this class to have many listeners, so we suppress noisy "MaxListenersExceededWarning" logging.
18
18
  super.setMaxListeners(0);
19
19
  }
20
- on(event, listener) {
21
- return super.on(event, listener);
20
+ getSelf() {
21
+ return this._currentClientId === undefined
22
+ ? undefined
23
+ : {
24
+ clientId: this._currentClientId,
25
+ client: this.getMember(this._currentClientId),
26
+ };
27
+ }
28
+ setCurrentClientId(clientId) {
29
+ if (this._currentClientId !== clientId) {
30
+ const oldId = this._currentClientId;
31
+ this._currentClientId = clientId;
32
+ // this.getMember(clientId) could resolve to undefined in these two cases:
33
+ // 1) Feature gates controlling ConnectionStateHandler() behavior are off
34
+ // 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
+ }
22
37
  }
23
38
  /**
24
39
  * Adds a new client to the audience
@@ -1 +1 @@
1
- {"version":3,"file":"audience.js","sourceRoot":"","sources":["../src/audience.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAA4D;AAE5D,kEAA6D;AAG7D;;GAEG;AACH,MAAa,QAAS,SAAQ,2BAAY;IAGzC;QACC,KAAK,EAAE,CAAC;QAHQ,YAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;QAIrD,kHAAkH;QAClH,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAMM,EAAE,CAAC,KAAa,EAAE,QAAkC;QAC1D,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAClC,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;YAC/B,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;SACF;aAAM;YACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;SAC1C;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;YAChC,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;SACZ;aAAM;YACN,OAAO,KAAK,CAAC;SACb;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;AArED,4BAqEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitter } from \"@fluid-internal/client-utils\";\nimport { IAudienceOwner } from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IClient } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Audience represents all clients connected to the op stream.\n */\nexport class Audience extends EventEmitter implements IAudienceOwner {\n\tprivate readonly members = new Map<string, IClient>();\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 on(\n\t\tevent: \"addMember\" | \"removeMember\",\n\t\tlistener: (clientId: string, client: IClient) => void,\n\t): this;\n\tpublic on(event: string, listener: (...args: any[]) => void): this {\n\t\treturn super.on(event, listener);\n\t}\n\n\t/**\n\t * Adds a new client to the audience\n\t */\n\tpublic addMember(clientId: string, details: IClient) {\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\tthis.members.delete(clientId);\n\t\t\tthis.emit(\"removeMember\", clientId, removedClient);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\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;AAMjE,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;aAC5C,CAAC;IACN,CAAC;IAEM,kBAAkB,CAAC,QAAgB;QACzC,IAAI,IAAI,CAAC,gBAAgB,KAAK,QAAQ,EAAE;YACvC,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;SACF;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;YAC/B,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;SACF;aAAM;YACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;SAC1C;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;YAChC,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;SACZ;aAAM;YACN,OAAO,KAAK,CAAC;SACb;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 {\n\tIAudienceEvents,\n\tIAudienceOwner,\n\tISelf,\n} from \"@fluidframework/container-definitions/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { IClient } from \"@fluidframework/protocol-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 };\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) {\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\tthis.members.delete(clientId);\n\t\t\tthis.emit(\"removeMember\", clientId, removedClient);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\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"]}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IDeltaManager } from "@fluidframework/container-definitions";
5
+ import { IDeltaManager } from "@fluidframework/container-definitions/internal";
6
6
  import { IDisposable } from "@fluidframework/core-interfaces";
7
7
  /** @see CatchUpMonitor for usage */
8
8
  type CaughtUpListener = () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"catchUpMonitor.d.ts","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAI9D,oCAAoC;AACpC,KAAK,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAEnC,mGAAmG;AACnG,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC;AAE1C;;;GAGG;AACH,qBAAa,cAAe,YAAW,eAAe;IAepD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAf1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAKxB;IAEF;;OAEG;gBAEe,YAAY,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EACrC,QAAQ,EAAE,gBAAgB;IAerC,QAAQ,EAAE,OAAO,CAAS;IAC1B,OAAO;CAQd"}
1
+ {"version":3,"file":"catchUpMonitor.d.ts","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAI9D,oCAAoC;AACpC,KAAK,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAEnC,mGAAmG;AACnG,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC;AAE1C;;;GAGG;AACH,qBAAa,cAAe,YAAW,eAAe;IAepD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAf1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAKxB;IAEF;;OAEG;gBAEe,YAAY,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EACrC,QAAQ,EAAE,gBAAgB;IAerC,QAAQ,EAAE,OAAO,CAAS;IAC1B,OAAO;CAQd"}
@@ -1 +1 @@
1
- {"version":3,"file":"catchUpMonitor.js","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,kEAA6D;AAS7D;;;GAGG;AACH,MAAa,cAAc;IAW1B;;OAEG;IACH,YACkB,YAAqC,EACrC,QAA0B;QAD1B,iBAAY,GAAZ,YAAY,CAAyB;QACrC,aAAQ,GAAR,QAAQ,CAAkB;QAdpC,aAAQ,GAAY,KAAK,CAAC;QAEjB,cAAS,GAAG,CAAC,OAA0D,EAAE,EAAE;YAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,EAAE;gBACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;aAChB;QACF,CAAC,CAAC;QAsBK,aAAQ,GAAY,KAAK,CAAC;QAbhC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;QAE5D,IAAA,iBAAM,EACL,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAC5D,KAAK,CAAC,oEAAoE,CAC1E,CAAC;QAEF,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE3C,wEAAwE;QACxE,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1E,CAAC;IAGM,OAAO;QACb,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,OAAO;SACP;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;CACD;AAxCD,wCAwCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\n\n/** @see CatchUpMonitor for usage */\ntype CaughtUpListener = () => void;\n\n/** Monitor that emits an event when a Container has caught up to a given point in the op stream */\nexport type ICatchUpMonitor = IDisposable;\n\n/**\n * Monitors a Container's DeltaManager, notifying listeners when all ops have been processed\n * that were known at the time the monitor was created.\n */\nexport class CatchUpMonitor implements ICatchUpMonitor {\n\tprivate readonly targetSeqNumber: number;\n\tprivate caughtUp: boolean = false;\n\n\tprivate readonly opHandler = (message: Pick<ISequencedDocumentMessage, \"sequenceNumber\">) => {\n\t\tif (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {\n\t\t\tthis.caughtUp = true;\n\t\t\tthis.listener();\n\t\t}\n\t};\n\n\t/**\n\t * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.\n\t */\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<any, any>,\n\t\tprivate readonly listener: CaughtUpListener,\n\t) {\n\t\tthis.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;\n\n\t\tassert(\n\t\t\tthis.targetSeqNumber >= this.deltaManager.lastSequenceNumber,\n\t\t\t0x37c /* Cannot wait for seqNumber below last processed sequence number */,\n\t\t);\n\n\t\tthis.deltaManager.on(\"op\", this.opHandler);\n\n\t\t// Simulate the last processed op to set caughtUp in case we already are\n\t\tthis.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });\n\t}\n\n\tpublic disposed: boolean = false;\n\tpublic dispose() {\n\t\tif (this.disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.disposed = true;\n\n\t\tthis.deltaManager.off(\"op\", this.opHandler);\n\t}\n}\n"]}
1
+ {"version":3,"file":"catchUpMonitor.js","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,kEAA6D;AAS7D;;;GAGG;AACH,MAAa,cAAc;IAW1B;;OAEG;IACH,YACkB,YAAqC,EACrC,QAA0B;QAD1B,iBAAY,GAAZ,YAAY,CAAyB;QACrC,aAAQ,GAAR,QAAQ,CAAkB;QAdpC,aAAQ,GAAY,KAAK,CAAC;QAEjB,cAAS,GAAG,CAAC,OAA0D,EAAE,EAAE;YAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,EAAE;gBACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;aAChB;QACF,CAAC,CAAC;QAsBK,aAAQ,GAAY,KAAK,CAAC;QAbhC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;QAE5D,IAAA,iBAAM,EACL,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAC5D,KAAK,CAAC,oEAAoE,CAC1E,CAAC;QAEF,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE3C,wEAAwE;QACxE,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1E,CAAC;IAGM,OAAO;QACb,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,OAAO;SACP;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;CACD;AAxCD,wCAwCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDeltaManager } from \"@fluidframework/container-definitions/internal\";\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\n\n/** @see CatchUpMonitor for usage */\ntype CaughtUpListener = () => void;\n\n/** Monitor that emits an event when a Container has caught up to a given point in the op stream */\nexport type ICatchUpMonitor = IDisposable;\n\n/**\n * Monitors a Container's DeltaManager, notifying listeners when all ops have been processed\n * that were known at the time the monitor was created.\n */\nexport class CatchUpMonitor implements ICatchUpMonitor {\n\tprivate readonly targetSeqNumber: number;\n\tprivate caughtUp: boolean = false;\n\n\tprivate readonly opHandler = (message: Pick<ISequencedDocumentMessage, \"sequenceNumber\">) => {\n\t\tif (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {\n\t\t\tthis.caughtUp = true;\n\t\t\tthis.listener();\n\t\t}\n\t};\n\n\t/**\n\t * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.\n\t */\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<any, any>,\n\t\tprivate readonly listener: CaughtUpListener,\n\t) {\n\t\tthis.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;\n\n\t\tassert(\n\t\t\tthis.targetSeqNumber >= this.deltaManager.lastSequenceNumber,\n\t\t\t0x37c /* Cannot wait for seqNumber below last processed sequence number */,\n\t\t);\n\n\t\tthis.deltaManager.on(\"op\", this.opHandler);\n\n\t\t// Simulate the last processed op to set caughtUp in case we already are\n\t\tthis.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });\n\t}\n\n\tpublic disposed: boolean = false;\n\tpublic dispose() {\n\t\tif (this.disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.disposed = true;\n\n\t\tthis.deltaManager.off(\"op\", this.opHandler);\n\t}\n}\n"]}
@@ -2,12 +2,12 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ICriticalContainerError, IDeltaQueue, ReadOnlyInfo } from "@fluidframework/container-definitions";
5
+ import { ICriticalContainerError, IDeltaQueue, ReadOnlyInfo } from "@fluidframework/container-definitions/internal";
6
6
  import { ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
7
7
  import { IDocumentService } from "@fluidframework/driver-definitions/internal";
8
8
  import { ConnectionMode, IClient, IClientConfiguration, IClientDetails, IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
9
- import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
10
- import { IConnectionManager, IConnectionManagerFactoryArgs, IConnectionStateChangeReason, ReconnectMode } from "./contracts.js";
9
+ import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
10
+ import { IConnectionDetailsInternal, IConnectionManager, IConnectionManagerFactoryArgs, IConnectionStateChangeReason, ReconnectMode } from "./contracts.js";
11
11
  /**
12
12
  * Implementation of IConnectionManager, used by Container class
13
13
  * Implements constant connectivity to relay service, by reconnecting in case of lost connection or error.
@@ -28,6 +28,8 @@ export declare class ConnectionManager implements IConnectionManager {
28
28
  */
29
29
  private pendingConnection;
30
30
  private connection;
31
+ /** Details about connection. undefined if there is no active connection. */
32
+ private _connectionDetails?;
31
33
  /** file ACL - whether user has only read-only access to a file */
32
34
  private _readonlyPermissions;
33
35
  /** tracks host requiring read-only mode. */
@@ -57,6 +59,8 @@ export declare class ConnectionManager implements IConnectionManager {
57
59
  get connectionMode(): ConnectionMode;
58
60
  get connected(): boolean;
59
61
  get clientId(): string | undefined;
62
+ /** Details about connection. undefined if there is no active connection. */
63
+ get connectionDetails(): IConnectionDetailsInternal | undefined;
60
64
  /**
61
65
  * Automatic reconnecting enabled or disabled.
62
66
  * If set to Never, then reconnecting will never be allowed.
@@ -1 +1 @@
1
- {"version":3,"file":"connectionManager.d.ts","sourceRoot":"","sources":["../src/connectionManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAe,wBAAwB,EAAY,MAAM,iCAAiC,CAAC;AAGlG,OAAO,EAGN,gBAAgB,EAChB,MAAM,6CAA6C,CAAC;AAUrD,OAAO,EACN,cAAc,EACd,OAAO,EACP,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAGhB,yBAAyB,EAOzB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAStE,OAAO,EAEN,kBAAkB,EAClB,6BAA6B,EAC7B,4BAA4B,EAC5B,aAAa,EACb,MAAM,gBAAgB,CAAC;AAiIxB;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,kBAAkB;IAoL1D,OAAO,CAAC,QAAQ,CAAC,eAAe;aAChB,cAAc,EAAE,MAAM,OAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAxLvB,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAiB;IAEzD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB,CAAiC;IAC1D,OAAO,CAAC,UAAU,CAAuC;IAEzD,kEAAkE;IAClE,OAAO,CAAC,oBAAoB,CAAsB;IAElD,4CAA4C;IAC5C,OAAO,CAAC,cAAc,CAAS;IAE/B;;OAEG;IACH,OAAO,CAAC,cAAc,CAAgB;IAEtC,2EAA2E;IAC3E,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,4BAA4B,CAAK;IACzC,sFAAsF;IACtF,OAAO,CAAC,gBAAgB,CAAK;IAE7B,yDAAyD;IACzD,OAAO,CAAC,qBAAqB,CAAqB;IAElD,OAAO,CAAC,sBAAsB,CAAQ;IAEtC,OAAO,CAAC,uBAAuB,CAAuC;IAEtE,OAAO,CAAC,gBAAgB,CAAgC;IAExD,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAE3D,IAAW,sBAAsB,oCAEhC;IAED,SAAgB,aAAa,EAAE,cAAc,CAAC;IAE9C;;OAEG;IACH,IAAW,cAAc,IAAI,cAAc,CAE1C;IAED,IAAW,SAAS,YAEnB;IAED,IAAW,QAAQ,uBAElB;IACD;;;OAGG;IACH,IAAW,aAAa,IAAI,aAAa,CAExC;IAED,IAAW,cAAc,IAAI,MAAM,CAElC;IAED,IAAW,OAAO,IAAI,MAAM,CAK3B;IAED,IAAW,oBAAoB,IAAI,oBAAoB,GAAG,SAAS,CAElE;IAED,IAAW,MAAM,IAAI,MAAM,EAAE,GAAG,SAAS,CAExC;IAED,IAAW,QAAQ,IAAI,WAAW,CAAC,gBAAgB,EAAE,CAAC,CAErD;IAED;;;OAGG;IACH,IAAW,eAAe,IAAI,wBAAwB,CAQrD;IAEM,eAAe,IAAI,OAAO;IAmBjC;;;;;;;;OAQG;IACH,OAAO,KAAK,QAAQ,GAEnB;IAED,IAAW,YAAY,IAAI,YAAY,CAkBtC;IAED,OAAO,CAAC,MAAM,CAAC,qBAAqB;gBAmBlB,eAAe,EAAE,MAAM,gBAAgB,GAAG,SAAS,EACpD,cAAc,EAAE,MAAM,OAAO,EAC5B,MAAM,EAAE,OAAO,EAChC,gBAAgB,EAAE,OAAO,EACR,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,6BAA6B;IAoB/C,OAAO,CAAC,KAAK,CAAC,EAAE,uBAAuB,EAAE,gBAAgB,GAAE,OAAc;IA4BhF;;;OAGG;IACI,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,4BAA4B,GAAG,IAAI;IAcxF;;OAEG;IACI,aAAa,CAAC,QAAQ,EAAE,OAAO;IAoCtC,OAAO,CAAC,uBAAuB;IAWxB,OAAO,CAAC,MAAM,EAAE,4BAA4B,EAAE,cAAc,CAAC,EAAE,cAAc;YAOtE,WAAW;IAuNzB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IActB;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;IAwCjC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;;OAIG;IACH,OAAO,CAAC,4BAA4B;IAwJpC;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;;;;;OAMG;YACW,SAAS;IA8DhB,oBAAoB,CAC1B,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,sBAAsB,CAAC,GACrD,gBAAgB,GAAG,SAAS;IAuCxB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM;IAQrD,YAAY,CAAC,QAAQ,EAAE,gBAAgB,EAAE;IA+BzC,0BAA0B,CAAC,OAAO,EAAE,yBAAyB;IAgDpE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAGxB;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG5B;IAGF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAkB1B;IAGF,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAIxC;IAEF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAE3B;CACF"}
1
+ {"version":3,"file":"connectionManager.d.ts","sourceRoot":"","sources":["../src/connectionManager.ts"],"names":[],"mappings":"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"}
@@ -8,10 +8,10 @@ exports.ConnectionManager = void 0;
8
8
  const client_utils_1 = require("@fluid-internal/client-utils");
9
9
  const core_interfaces_1 = require("@fluidframework/core-interfaces");
10
10
  const internal_1 = require("@fluidframework/core-utils/internal");
11
- const driver_definitions_1 = require("@fluidframework/driver-definitions");
12
- const internal_2 = require("@fluidframework/driver-utils/internal");
11
+ const internal_2 = require("@fluidframework/driver-definitions/internal");
12
+ const internal_3 = require("@fluidframework/driver-utils/internal");
13
13
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
14
- const internal_3 = require("@fluidframework/telemetry-utils/internal");
14
+ const internal_4 = require("@fluidframework/telemetry-utils/internal");
15
15
  const contracts_js_1 = require("./contracts.js");
16
16
  const deltaQueue_js_1 = require("./deltaQueue.js");
17
17
  const protocol_js_1 = require("./protocol.js");
@@ -24,7 +24,7 @@ function getNackReconnectInfo(nackContent) {
24
24
  const message = `Nack (${nackContent.type}): ${nackContent.message}`;
25
25
  const canRetry = nackContent.code !== 403;
26
26
  const retryAfterMs = nackContent.retryAfter !== undefined ? nackContent.retryAfter * 1000 : undefined;
27
- return (0, internal_2.createGenericNetworkError)(message, { canRetry, retryAfterMs }, { statusCode: nackContent.code, driverVersion: undefined });
27
+ return (0, internal_3.createGenericNetworkError)(message, { canRetry, retryAfterMs }, { statusCode: nackContent.code, driverVersion: undefined });
28
28
  }
29
29
  /**
30
30
  * Implementation of IDocumentDeltaConnection that does not support submitting
@@ -125,6 +125,10 @@ class ConnectionManager {
125
125
  get clientId() {
126
126
  return this.connection?.clientId;
127
127
  }
128
+ /** Details about connection. undefined if there is no active connection. */
129
+ get connectionDetails() {
130
+ return this._connectionDetails;
131
+ }
128
132
  /**
129
133
  * Automatic reconnecting enabled or disabled.
130
134
  * If set to Never, then reconnecting will never be allowed.
@@ -253,7 +257,7 @@ class ConnectionManager {
253
257
  this.nackHandler = (documentId, messages) => {
254
258
  const message = messages[0];
255
259
  if (this._readonlyPermissions === true) {
256
- this.props.closeHandler((0, internal_2.createWriteError)("writeOnReadOnlyDocument", { driverVersion: undefined }));
260
+ this.props.closeHandler((0, internal_3.createWriteError)("writeOnReadOnlyDocument", { driverVersion: undefined }));
257
261
  return;
258
262
  }
259
263
  const reconnectInfo = getNackReconnectInfo(message.content);
@@ -285,7 +289,7 @@ class ConnectionManager {
285
289
  this.connection.submit(messages);
286
290
  });
287
291
  this._outbound.on("error", (error) => {
288
- this.props.closeHandler((0, internal_3.normalizeError)(error));
292
+ this.props.closeHandler((0, internal_4.normalizeError)(error));
289
293
  });
290
294
  }
291
295
  dispose(error, switchToReadonly = true) {
@@ -336,7 +340,7 @@ class ConnectionManager {
336
340
  this._forceReadonly = readonly;
337
341
  if (oldValue !== this.readonly) {
338
342
  if (this._reconnectMode === contracts_js_1.ReconnectMode.Never) {
339
- throw new internal_3.UsageError("API is not supported for non-connecting or closed container");
343
+ throw new internal_4.UsageError("API is not supported for non-connecting or closed container");
340
344
  }
341
345
  let reconnect = false;
342
346
  if (this.readonly === true) {
@@ -365,23 +369,13 @@ class ConnectionManager {
365
369
  }
366
370
  connect(reason, connectionMode) {
367
371
  this.connectCore(reason, connectionMode).catch((e) => {
368
- const normalizedError = (0, internal_3.normalizeError)(e, { props: fatalConnectErrorProp });
372
+ const normalizedError = (0, internal_4.normalizeError)(e, { props: fatalConnectErrorProp });
369
373
  this.props.closeHandler(normalizedError);
370
374
  });
371
375
  }
372
376
  async connectCore(reason, connectionMode) {
373
377
  (0, internal_1.assert)(!this._disposed, 0x26a /* "not closed" */);
374
- if (this.connection !== undefined) {
375
- return; // Connection attempt already completed successfully
376
- }
377
- let pendingConnectionMode;
378
- if (this.pendingConnection !== undefined) {
379
- pendingConnectionMode = this.pendingConnection.connectionMode;
380
- this.cancelConnection(reason); // Throw out in-progress connection attempt in favor of new attempt
381
- (0, internal_1.assert)(this.pendingConnection === undefined, 0x344 /* this.pendingConnection should be undefined */);
382
- }
383
- // If there is no specified ConnectionMode, try the previous mode, if there is no previous mode use default
384
- let requestedMode = connectionMode ?? pendingConnectionMode ?? this.defaultReconnectionMode;
378
+ let requestedMode = connectionMode ?? this.defaultReconnectionMode;
385
379
  // if we have any non-acked ops from last connection, reconnect as "write".
386
380
  // without that we would connect in view-only mode, which will result in immediate
387
381
  // firing of "connected" event from Container and switch of current clientId (as tracked
@@ -390,6 +384,27 @@ class ConnectionManager {
390
384
  if (this.shouldJoinWrite()) {
391
385
  requestedMode = "write";
392
386
  }
387
+ if (this.connection !== undefined || this.pendingConnection !== undefined) {
388
+ // Connection attempt already completed successfully or is in progress
389
+ // In general, there should be no issues if the modes do not match:
390
+ // If at some point it was Ok to connect as "read" (i.e. there were no pending ops we had to track),
391
+ // then it should be Ok to use "read" connection even if for some reason request came in to connect as "write"
392
+ // (though that should never happen)
393
+ // The opposite should be fine as well: we may have had idle "write" connection, and request to reconnect came in,
394
+ // using default "read" mode.
395
+ // That all said, let's understand better where such mismatches are coming from.
396
+ const mode = this.connection?.mode ?? this.pendingConnection?.connectionMode;
397
+ if (mode !== requestedMode) {
398
+ this.logger.sendTelemetryEvent({
399
+ eventName: "ConnectionModeMismatch",
400
+ connected: this.connection !== undefined,
401
+ mode,
402
+ requestedMode,
403
+ stack: (0, internal_4.generateStack)(),
404
+ });
405
+ }
406
+ return;
407
+ }
393
408
  const docService = this.serviceProvider();
394
409
  (0, internal_1.assert)(docService !== undefined, 0x2a7 /* "Container is not attached" */);
395
410
  this.props.establishConnectionHandler(reason);
@@ -421,7 +436,7 @@ class ConnectionManager {
421
436
  this.logger.sendTelemetryEvent({
422
437
  eventName: "ConnectionAttemptCancelled",
423
438
  attempts: connectRepeatCount,
424
- duration: (0, internal_3.formatTick)(client_utils_1.performance.now() - connectStartTime),
439
+ duration: (0, internal_4.formatTick)(client_utils_1.performance.now() - connectStartTime),
425
440
  connectionEstablished: false,
426
441
  });
427
442
  return;
@@ -456,8 +471,8 @@ class ConnectionManager {
456
471
  requestedMode = "read";
457
472
  break;
458
473
  }
459
- else if ((0, internal_3.isFluidError)(origError) &&
460
- origError.errorType === driver_definitions_1.DriverErrorTypes.outOfStorageError) {
474
+ else if ((0, internal_4.isFluidError)(origError) &&
475
+ origError.errorType === internal_2.DriverErrorTypes.outOfStorageError) {
461
476
  // If we get out of storage error from calling joinsession, then use the NoDeltaStream object so
462
477
  // that user can at least load the container.
463
478
  connection = new NoDeltaStream(undefined, {
@@ -468,17 +483,17 @@ class ConnectionManager {
468
483
  break;
469
484
  }
470
485
  // Socket.io error when we connect to wrong socket, or hit some multiplexing bug
471
- if (!(0, internal_2.canRetryOnError)(origError)) {
472
- const error = (0, internal_3.normalizeError)(origError, { props: fatalConnectErrorProp });
486
+ if (!(0, internal_3.canRetryOnError)(origError)) {
487
+ const error = (0, internal_4.normalizeError)(origError, { props: fatalConnectErrorProp });
473
488
  this.props.closeHandler(error);
474
489
  throw error;
475
490
  }
476
491
  // Since the error is retryable this will not log to the error table
477
- (0, internal_2.logNetworkFailure)(this.logger, {
492
+ (0, internal_3.logNetworkFailure)(this.logger, {
478
493
  attempts: connectRepeatCount,
479
494
  delay: delayMs,
480
495
  eventName: "DeltaConnectionFailureToConnect",
481
- duration: (0, internal_3.formatTick)(client_utils_1.performance.now() - connectStartTime),
496
+ duration: (0, internal_4.formatTick)(client_utils_1.performance.now() - connectStartTime),
482
497
  }, origError);
483
498
  lastError = origError;
484
499
  // We will not perform retries if the container disconnected and the ReconnectMode is set to Disabled or Never
@@ -487,14 +502,14 @@ class ConnectionManager {
487
502
  return;
488
503
  }
489
504
  const waitStartTime = client_utils_1.performance.now();
490
- const retryDelayFromError = (0, internal_2.getRetryDelayFromError)(origError);
505
+ const retryDelayFromError = (0, internal_3.getRetryDelayFromError)(origError);
491
506
  // If the error told us to wait or browser signals us that we are offline, then calculate the time we
492
507
  // want to wait for before retrying. then we wait for that time. If the error didn't tell us to wait,
493
508
  // let's still wait a little bit before retrying. We can skip this delay if we're confident we're offline,
494
509
  // because we probably just need to wait to come back online. But we never have strong signal of being
495
510
  // offline, so we at least wait for sometime.
496
511
  if (retryDelayFromError !== undefined || globalThis.navigator?.onLine !== false) {
497
- delayMs = (0, internal_2.calculateMaxWaitTime)(delayMs, origError);
512
+ delayMs = (0, internal_3.calculateMaxWaitTime)(delayMs, origError);
498
513
  }
499
514
  // Raise event in case the delay was there from the error.
500
515
  if (retryDelayFromError !== undefined) {
@@ -519,10 +534,10 @@ class ConnectionManager {
519
534
  }
520
535
  // If we retried more than once, log an event about how long it took (this will not log to error table)
521
536
  if (connectRepeatCount > 1) {
522
- (0, internal_2.logNetworkFailure)(this.logger, {
537
+ (0, internal_3.logNetworkFailure)(this.logger, {
523
538
  eventName: "MultipleDeltaConnectionFailures",
524
539
  attempts: connectRepeatCount,
525
- duration: (0, internal_3.formatTick)(client_utils_1.performance.now() - connectStartTime),
540
+ duration: (0, internal_4.formatTick)(client_utils_1.performance.now() - connectStartTime),
526
541
  }, lastError);
527
542
  }
528
543
  // Check for abort signal after while loop as well or we've been disposed
@@ -531,7 +546,7 @@ class ConnectionManager {
531
546
  this.logger.sendTelemetryEvent({
532
547
  eventName: "ConnectionAttemptCancelled",
533
548
  attempts: connectRepeatCount,
534
- duration: (0, internal_3.formatTick)(client_utils_1.performance.now() - connectStartTime),
549
+ duration: (0, internal_4.formatTick)(client_utils_1.performance.now() - connectStartTime),
535
550
  connectionEstablished: true,
536
551
  });
537
552
  return;
@@ -574,6 +589,7 @@ class ConnectionManager {
574
589
  const connection = this.connection;
575
590
  // Avoid any re-entrancy - clear object reference
576
591
  this.connection = undefined;
592
+ this._connectionDetails = undefined;
577
593
  // Remove listeners first so we don't try to retrigger this flow accidentally through reconnectOnError
578
594
  connection.off("op", this.opHandler);
579
595
  connection.off("signal", this.signalHandler);
@@ -596,7 +612,10 @@ class ConnectionManager {
596
612
  (0, internal_1.assert)(this.pendingConnection !== undefined, 0x345 /* this.pendingConnection is undefined when trying to cancel */);
597
613
  this.pendingConnection.abort();
598
614
  this.pendingConnection = undefined;
599
- this.logger.sendTelemetryEvent({ eventName: "ConnectionCancelReceived" });
615
+ this.logger.sendTelemetryEvent({
616
+ eventName: "ConnectionCancelReceived",
617
+ reason: reason.text,
618
+ });
600
619
  this.props.cancelConnectionHandler({
601
620
  text: `Cancel Pending Connection due to ${reason.text}`,
602
621
  error: reason.error,
@@ -675,9 +694,9 @@ class ConnectionManager {
675
694
  }
676
695
  }
677
696
  this.props.incomingOpHandler(initialMessages, this.connectFirstConnection ? "InitialOps" : "ReconnectOps");
678
- const details = ConnectionManager.detailsFromConnection(connection, reason);
679
- details.checkpointSequenceNumber = checkpointSequenceNumber;
680
- this.props.connectHandler(details);
697
+ this._connectionDetails = ConnectionManager.detailsFromConnection(connection, reason);
698
+ this._connectionDetails.checkpointSequenceNumber = checkpointSequenceNumber;
699
+ this.props.connectHandler(this._connectionDetails);
681
700
  this.connectFirstConnection = false;
682
701
  // Synthesize clear & join signals out of initialClients state.
683
702
  // This allows us to have single way to process signals, and makes it simpler to initialize
@@ -752,7 +771,7 @@ class ConnectionManager {
752
771
  return;
753
772
  }
754
773
  // If the error tells us to wait before retrying, then do so.
755
- const delayMs = (0, internal_2.getRetryDelayFromError)(reason.error);
774
+ const delayMs = (0, internal_3.getRetryDelayFromError)(reason.error);
756
775
  if (reason.error !== undefined && delayMs !== undefined) {
757
776
  this.props.reconnectionDelayHandler(delayMs, reason.error);
758
777
  await new Promise((resolve) => {
@@ -773,7 +792,7 @@ class ConnectionManager {
773
792
  prepareMessageToSend(message) {
774
793
  if (this.readonly === true) {
775
794
  (0, internal_1.assert)(this.readOnlyInfo.readonly === true, 0x1f0 /* "Unexpected mismatch in readonly" */);
776
- const error = new internal_3.GenericError("deltaManagerReadonlySubmit", undefined /* error */, {
795
+ const error = new internal_4.GenericError("deltaManagerReadonlySubmit", undefined /* error */, {
777
796
  readonly: this.readOnlyInfo.readonly,
778
797
  forcedReadonly: this.readOnlyInfo.forced,
779
798
  readonlyPermissions: this.readOnlyInfo.permissions,
@@ -792,7 +811,7 @@ class ConnectionManager {
792
811
  this.clientSequenceNumber = 0;
793
812
  this.clientSequenceNumberObserved = 0;
794
813
  }
795
- if (!(0, internal_2.isRuntimeMessage)(message)) {
814
+ if (!(0, internal_3.isRuntimeMessage)(message)) {
796
815
  this.localOpsToIgnore++;
797
816
  }
798
817
  else {