@fluidframework/container-loader 2.0.0-rc.4.0.5 → 2.0.0-rc.5.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 (232) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/api-extractor/api-extractor-lint-bundle.json +5 -0
  3. package/api-extractor/api-extractor-lint-legacy.cjs.json +5 -0
  4. package/api-extractor/api-extractor-lint-legacy.esm.json +5 -0
  5. package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
  6. package/api-extractor/api-extractor-lint-public.esm.json +5 -0
  7. package/api-extractor.json +1 -1
  8. package/api-report/{container-loader.api.md → container-loader.alpha.api.md} +60 -17
  9. package/api-report/container-loader.beta.api.md +44 -0
  10. package/api-report/container-loader.public.api.md +44 -0
  11. package/biome.jsonc +4 -0
  12. package/dist/attachment.d.ts +1 -1
  13. package/dist/attachment.d.ts.map +1 -1
  14. package/dist/attachment.js.map +1 -1
  15. package/dist/audience.d.ts +3 -2
  16. package/dist/audience.d.ts.map +1 -1
  17. package/dist/audience.js.map +1 -1
  18. package/dist/catchUpMonitor.d.ts.map +1 -1
  19. package/dist/catchUpMonitor.js.map +1 -1
  20. package/dist/connectionManager.d.ts +4 -3
  21. package/dist/connectionManager.d.ts.map +1 -1
  22. package/dist/connectionManager.js +7 -8
  23. package/dist/connectionManager.js.map +1 -1
  24. package/dist/connectionStateHandler.d.ts +1 -1
  25. package/dist/connectionStateHandler.d.ts.map +1 -1
  26. package/dist/connectionStateHandler.js +8 -4
  27. package/dist/connectionStateHandler.js.map +1 -1
  28. package/dist/container.d.ts +3 -2
  29. package/dist/container.d.ts.map +1 -1
  30. package/dist/container.js +78 -80
  31. package/dist/container.js.map +1 -1
  32. package/dist/containerContext.d.ts +2 -2
  33. package/dist/containerContext.d.ts.map +1 -1
  34. package/dist/containerContext.js.map +1 -1
  35. package/dist/containerStorageAdapter.d.ts +5 -4
  36. package/dist/containerStorageAdapter.d.ts.map +1 -1
  37. package/dist/containerStorageAdapter.js +24 -8
  38. package/dist/containerStorageAdapter.js.map +1 -1
  39. package/dist/contracts.d.ts +2 -2
  40. package/dist/contracts.d.ts.map +1 -1
  41. package/dist/contracts.js.map +1 -1
  42. package/dist/debugLogger.d.ts.map +1 -1
  43. package/dist/debugLogger.js.map +1 -1
  44. package/dist/deltaManager.d.ts +6 -5
  45. package/dist/deltaManager.d.ts.map +1 -1
  46. package/dist/deltaManager.js +15 -16
  47. package/dist/deltaManager.js.map +1 -1
  48. package/dist/deltaQueue.d.ts.map +1 -1
  49. package/dist/deltaQueue.js.map +1 -1
  50. package/dist/disposal.js.map +1 -1
  51. package/dist/error.d.ts.map +1 -1
  52. package/dist/error.js.map +1 -1
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/legacy.d.ts +5 -0
  57. package/dist/loadPaused.js.map +1 -1
  58. package/dist/loader.d.ts +1 -1
  59. package/dist/loader.d.ts.map +1 -1
  60. package/dist/loader.js.map +1 -1
  61. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  62. package/dist/memoryBlobStorage.d.ts.map +1 -1
  63. package/dist/memoryBlobStorage.js +4 -3
  64. package/dist/memoryBlobStorage.js.map +1 -1
  65. package/dist/noopHeuristic.d.ts +1 -1
  66. package/dist/noopHeuristic.d.ts.map +1 -1
  67. package/dist/noopHeuristic.js.map +1 -1
  68. package/dist/packageVersion.d.ts +1 -1
  69. package/dist/packageVersion.js +1 -1
  70. package/dist/packageVersion.js.map +1 -1
  71. package/dist/protocol/index.d.ts +7 -0
  72. package/dist/protocol/index.d.ts.map +1 -0
  73. package/dist/protocol/index.js +12 -0
  74. package/dist/protocol/index.js.map +1 -0
  75. package/dist/protocol/protocol.d.ts +52 -0
  76. package/dist/protocol/protocol.d.ts.map +1 -0
  77. package/dist/protocol/protocol.js +112 -0
  78. package/dist/protocol/protocol.js.map +1 -0
  79. package/dist/protocol/quorum.d.ts +185 -0
  80. package/dist/protocol/quorum.d.ts.map +1 -0
  81. package/dist/protocol/quorum.js +419 -0
  82. package/dist/protocol/quorum.js.map +1 -0
  83. package/dist/protocol.d.ts +4 -4
  84. package/dist/protocol.d.ts.map +1 -1
  85. package/dist/protocol.js +6 -6
  86. package/dist/protocol.js.map +1 -1
  87. package/dist/protocolTreeDocumentStorageService.d.ts +16 -9
  88. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  89. package/dist/protocolTreeDocumentStorageService.js +18 -9
  90. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  91. package/dist/quorum.d.ts +1 -1
  92. package/dist/quorum.d.ts.map +1 -1
  93. package/dist/quorum.js.map +1 -1
  94. package/dist/retriableDocumentStorageService.d.ts +2 -2
  95. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  96. package/dist/retriableDocumentStorageService.js +3 -1
  97. package/dist/retriableDocumentStorageService.js.map +1 -1
  98. package/dist/serializedStateManager.d.ts +5 -5
  99. package/dist/serializedStateManager.d.ts.map +1 -1
  100. package/dist/serializedStateManager.js +16 -12
  101. package/dist/serializedStateManager.js.map +1 -1
  102. package/dist/utils.d.ts +2 -1
  103. package/dist/utils.d.ts.map +1 -1
  104. package/dist/utils.js +7 -7
  105. package/dist/utils.js.map +1 -1
  106. package/lib/attachment.d.ts +1 -1
  107. package/lib/attachment.d.ts.map +1 -1
  108. package/lib/attachment.js.map +1 -1
  109. package/lib/audience.d.ts +3 -2
  110. package/lib/audience.d.ts.map +1 -1
  111. package/lib/audience.js.map +1 -1
  112. package/lib/catchUpMonitor.d.ts.map +1 -1
  113. package/lib/catchUpMonitor.js.map +1 -1
  114. package/lib/connectionManager.d.ts +4 -3
  115. package/lib/connectionManager.d.ts.map +1 -1
  116. package/lib/connectionManager.js +6 -7
  117. package/lib/connectionManager.js.map +1 -1
  118. package/lib/connectionStateHandler.d.ts +1 -1
  119. package/lib/connectionStateHandler.d.ts.map +1 -1
  120. package/lib/connectionStateHandler.js +8 -4
  121. package/lib/connectionStateHandler.js.map +1 -1
  122. package/lib/container.d.ts +3 -2
  123. package/lib/container.d.ts.map +1 -1
  124. package/lib/container.js +20 -22
  125. package/lib/container.js.map +1 -1
  126. package/lib/containerContext.d.ts +2 -2
  127. package/lib/containerContext.d.ts.map +1 -1
  128. package/lib/containerContext.js.map +1 -1
  129. package/lib/containerStorageAdapter.d.ts +5 -4
  130. package/lib/containerStorageAdapter.d.ts.map +1 -1
  131. package/lib/containerStorageAdapter.js +24 -8
  132. package/lib/containerStorageAdapter.js.map +1 -1
  133. package/lib/contracts.d.ts +2 -2
  134. package/lib/contracts.d.ts.map +1 -1
  135. package/lib/contracts.js.map +1 -1
  136. package/lib/debugLogger.d.ts.map +1 -1
  137. package/lib/debugLogger.js.map +1 -1
  138. package/lib/deltaManager.d.ts +6 -5
  139. package/lib/deltaManager.d.ts.map +1 -1
  140. package/lib/deltaManager.js +8 -9
  141. package/lib/deltaManager.js.map +1 -1
  142. package/lib/deltaQueue.d.ts.map +1 -1
  143. package/lib/deltaQueue.js.map +1 -1
  144. package/lib/disposal.js.map +1 -1
  145. package/lib/error.d.ts.map +1 -1
  146. package/lib/error.js.map +1 -1
  147. package/lib/index.d.ts +1 -0
  148. package/lib/index.d.ts.map +1 -1
  149. package/lib/index.js.map +1 -1
  150. package/lib/legacy.d.ts +5 -0
  151. package/lib/loadPaused.js.map +1 -1
  152. package/lib/loader.d.ts +1 -1
  153. package/lib/loader.d.ts.map +1 -1
  154. package/lib/loader.js.map +1 -1
  155. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  156. package/lib/memoryBlobStorage.d.ts.map +1 -1
  157. package/lib/memoryBlobStorage.js +4 -3
  158. package/lib/memoryBlobStorage.js.map +1 -1
  159. package/lib/noopHeuristic.d.ts +1 -1
  160. package/lib/noopHeuristic.d.ts.map +1 -1
  161. package/lib/noopHeuristic.js.map +1 -1
  162. package/lib/packageVersion.d.ts +1 -1
  163. package/lib/packageVersion.js +1 -1
  164. package/lib/packageVersion.js.map +1 -1
  165. package/lib/protocol/index.d.ts +7 -0
  166. package/lib/protocol/index.d.ts.map +1 -0
  167. package/lib/protocol/index.js +7 -0
  168. package/lib/protocol/index.js.map +1 -0
  169. package/lib/protocol/protocol.d.ts +52 -0
  170. package/lib/protocol/protocol.d.ts.map +1 -0
  171. package/lib/protocol/protocol.js +108 -0
  172. package/lib/protocol/protocol.js.map +1 -0
  173. package/lib/protocol/quorum.d.ts +185 -0
  174. package/lib/protocol/quorum.d.ts.map +1 -0
  175. package/lib/protocol/quorum.js +410 -0
  176. package/lib/protocol/quorum.js.map +1 -0
  177. package/lib/protocol.d.ts +4 -4
  178. package/lib/protocol.d.ts.map +1 -1
  179. package/lib/protocol.js +2 -2
  180. package/lib/protocol.js.map +1 -1
  181. package/lib/protocolTreeDocumentStorageService.d.ts +16 -9
  182. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  183. package/lib/protocolTreeDocumentStorageService.js +18 -9
  184. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  185. package/lib/quorum.d.ts +1 -1
  186. package/lib/quorum.d.ts.map +1 -1
  187. package/lib/quorum.js.map +1 -1
  188. package/lib/retriableDocumentStorageService.d.ts +2 -2
  189. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  190. package/lib/retriableDocumentStorageService.js +3 -1
  191. package/lib/retriableDocumentStorageService.js.map +1 -1
  192. package/lib/serializedStateManager.d.ts +5 -5
  193. package/lib/serializedStateManager.d.ts.map +1 -1
  194. package/lib/serializedStateManager.js +17 -13
  195. package/lib/serializedStateManager.js.map +1 -1
  196. package/lib/tsdoc-metadata.json +1 -1
  197. package/lib/utils.d.ts +2 -1
  198. package/lib/utils.d.ts.map +1 -1
  199. package/lib/utils.js +3 -3
  200. package/lib/utils.js.map +1 -1
  201. package/package.json +32 -31
  202. package/src/attachment.ts +8 -5
  203. package/src/audience.ts +4 -7
  204. package/src/catchUpMonitor.ts +4 -2
  205. package/src/connectionManager.ts +27 -24
  206. package/src/connectionStateHandler.ts +11 -10
  207. package/src/container.ts +64 -72
  208. package/src/containerContext.ts +5 -5
  209. package/src/containerStorageAdapter.ts +37 -22
  210. package/src/contracts.ts +4 -5
  211. package/src/debugLogger.ts +2 -3
  212. package/src/deltaManager.ts +13 -18
  213. package/src/deltaQueue.ts +4 -1
  214. package/src/error.ts +4 -1
  215. package/src/index.ts +7 -0
  216. package/src/loadPaused.ts +1 -1
  217. package/src/loader.ts +1 -1
  218. package/src/memoryBlobStorage.ts +6 -4
  219. package/src/noopHeuristic.ts +1 -1
  220. package/src/packageVersion.ts +1 -1
  221. package/src/protocol/README.md +10 -0
  222. package/src/protocol/index.ts +16 -0
  223. package/src/protocol/protocol.ts +185 -0
  224. package/src/protocol/quorum.ts +577 -0
  225. package/src/protocol.ts +6 -9
  226. package/src/protocolTreeDocumentStorageService.ts +30 -13
  227. package/src/quorum.ts +1 -1
  228. package/src/retriableDocumentStorageService.ts +6 -7
  229. package/src/serializedStateManager.ts +33 -34
  230. package/src/utils.ts +16 -10
  231. package/tsconfig.json +2 -0
  232. package/tsdoc.json +4 -0
@@ -6,8 +6,8 @@
6
6
  import { IDeltaManager } from "@fluidframework/container-definitions/internal";
7
7
  import { ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
8
8
  import { assert, Timer } from "@fluidframework/core-utils/internal";
9
+ import { IClient, ISequencedClient } from "@fluidframework/driver-definitions";
9
10
  import { IAnyDriverError } from "@fluidframework/driver-definitions/internal";
10
- import { IClient, ISequencedClient } from "@fluidframework/protocol-definitions";
11
11
  import {
12
12
  type TelemetryEventCategory,
13
13
  ITelemetryLoggerExt,
@@ -260,10 +260,7 @@ class ConnectionStateCatchup extends ConnectionStateHandlerPassThrough {
260
260
  // In addition to that, in its current form, doing this in ConnectionState.CatchingUp is dangerous as
261
261
  // we might get callback right away, and it will screw up state transition (as code outside of switch
262
262
  // statement will overwrite current state).
263
- assert(
264
- this.catchUpMonitor === undefined,
265
- 0x3eb /* catchUpMonitor should be gone */,
266
- );
263
+ assert(this.catchUpMonitor === undefined, 0x3eb /* catchUpMonitor should be gone */);
267
264
  this.catchUpMonitor = new CatchUpMonitor(
268
265
  this.deltaManager,
269
266
  this.transitionToConnectedState,
@@ -652,9 +649,6 @@ class ConnectionStateHandler implements IConnectionStateHandler {
652
649
  }
653
650
  this._clientId = this.pendingClientId;
654
651
  } else if (value === ConnectionState.Disconnected) {
655
- // Clear pending state immediately to prepare for reconnect
656
- this._pendingClientId = undefined;
657
-
658
652
  if (this.joinTimer.hasTimer) {
659
653
  this.stopjoinTimer();
660
654
  }
@@ -683,8 +677,15 @@ class ConnectionStateHandler implements IConnectionStateHandler {
683
677
  }
684
678
  }
685
679
 
686
- // Report transition before we propagate event across layers
680
+ // Report transition
687
681
  this.handler.connectionStateChanged(this._connectionState, oldState, reason);
682
+
683
+ // Clear pending state immediately to prepare for reconnect
684
+ // Do it after calling connectionStateChanged() above, such that our telemetry contains pendingClientId on disconnect events
685
+ // and we can pair attempts to connect with disconnects (that's the only ID we have if connection did not move far enough before being disconnected)
686
+ if (value === ConnectionState.Disconnected) {
687
+ this._pendingClientId = undefined;
688
+ }
688
689
  }
689
690
 
690
691
  protected get membership(): IMembership | undefined {
@@ -731,7 +732,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
731
732
 
732
733
  assert(
733
734
  !this.waitingForLeaveOp,
734
- "leave timer can't be set as we have not had access to quorum",
735
+ 0x99d /* leave timer can't be set as we have not had access to quorum */,
735
736
  );
736
737
 
737
738
  // This check is required for scenario of loading container from pending state, and ensuring there is no way
package/src/container.ts CHANGED
@@ -37,6 +37,14 @@ import {
37
37
  } from "@fluidframework/core-interfaces";
38
38
  import { type ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
39
39
  import { assert, isPromiseLike, unreachableCase } from "@fluidframework/core-utils/internal";
40
+ import {
41
+ IClient,
42
+ IClientDetails,
43
+ IQuorumClients,
44
+ ISequencedClient,
45
+ ISummaryTree,
46
+ SummaryType,
47
+ } from "@fluidframework/driver-definitions";
40
48
  import {
41
49
  IDocumentService,
42
50
  IDocumentServiceFactory,
@@ -45,6 +53,17 @@ import {
45
53
  ISnapshot,
46
54
  IThrottlingWarning,
47
55
  IUrlResolver,
56
+ ICommittedProposal,
57
+ IDocumentAttributes,
58
+ IDocumentMessage,
59
+ IQuorumProposals,
60
+ ISequencedProposal,
61
+ ISnapshotTree,
62
+ ISummaryContent,
63
+ IVersion,
64
+ MessageType,
65
+ ISequencedDocumentMessage,
66
+ ISignalMessage,
48
67
  } from "@fluidframework/driver-definitions/internal";
49
68
  import {
50
69
  getSnapshotTree,
@@ -56,26 +75,6 @@ import {
56
75
  readAndParse,
57
76
  runWithRetry,
58
77
  } from "@fluidframework/driver-utils/internal";
59
- import { IQuorumSnapshot } from "@fluidframework/protocol-base";
60
- import {
61
- IClient,
62
- IClientDetails,
63
- ICommittedProposal,
64
- IDocumentAttributes,
65
- IDocumentMessage,
66
- IQuorumClients,
67
- IQuorumProposals,
68
- ISequencedClient,
69
- ISequencedDocumentMessage,
70
- ISequencedProposal,
71
- ISignalMessage,
72
- ISnapshotTree,
73
- ISummaryContent,
74
- ISummaryTree,
75
- IVersion,
76
- MessageType,
77
- SummaryType,
78
- } from "@fluidframework/protocol-definitions";
79
78
  import {
80
79
  type TelemetryEventCategory,
81
80
  ITelemetryLoggerExt,
@@ -97,11 +96,18 @@ import {
97
96
  import structuredClone from "@ungap/structured-clone";
98
97
  import { v4 as uuid } from "uuid";
99
98
 
100
- import { AttachProcessProps, AttachmentData, runRetriableAttachProcess } from "./attachment.js";
99
+ import {
100
+ AttachProcessProps,
101
+ AttachmentData,
102
+ runRetriableAttachProcess,
103
+ } from "./attachment.js";
101
104
  import { Audience } from "./audience.js";
102
105
  import { ConnectionManager } from "./connectionManager.js";
103
106
  import { ConnectionState } from "./connectionState.js";
104
- import { IConnectionStateHandler, createConnectionStateHandler } from "./connectionStateHandler.js";
107
+ import {
108
+ IConnectionStateHandler,
109
+ createConnectionStateHandler,
110
+ } from "./connectionStateHandler.js";
105
111
  import { ContainerContext } from "./containerContext.js";
106
112
  import { ContainerStorageAdapter } from "./containerStorageAdapter.js";
107
113
  import {
@@ -114,8 +120,14 @@ import {
114
120
  import { DeltaManager, IConnectionArgs } from "./deltaManager.js";
115
121
  // eslint-disable-next-line import/no-deprecated
116
122
  import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader.js";
123
+ import {
124
+ serializeMemoryDetachedBlobStorage,
125
+ createMemoryDetachedBlobStorage,
126
+ tryInitializeMemoryDetachedBlobStorage,
127
+ } from "./memoryBlobStorage.js";
117
128
  import { NoopHeuristic } from "./noopHeuristic.js";
118
129
  import { pkgVersion } from "./packageVersion.js";
130
+ import { IQuorumSnapshot } from "./protocol/index.js";
119
131
  import {
120
132
  IProtocolHandler,
121
133
  ProtocolHandler,
@@ -138,11 +150,6 @@ import {
138
150
  getSnapshotTreeAndBlobsFromSerializedContainer,
139
151
  runSingle,
140
152
  } from "./utils.js";
141
- import {
142
- serializeMemoryDetachedBlobStorage,
143
- createMemoryDetachedBlobStorage,
144
- tryInitializeMemoryDetachedBlobStorage,
145
- } from "./memoryBlobStorage.js";
146
153
 
147
154
  const detachedContainerRefSeqNumber = 0;
148
155
 
@@ -269,7 +276,7 @@ export async function waitContainerToCatchUp(container: IContainer) {
269
276
  ? wrapError(
270
277
  err,
271
278
  (innerMessage) => new GenericError(`${baseMessage}: ${innerMessage}`),
272
- )
279
+ )
273
280
  : new GenericError(baseMessage),
274
281
  );
275
282
  };
@@ -328,7 +335,8 @@ export async function waitContainerToCatchUp(container: IContainer) {
328
335
  });
329
336
  }
330
337
 
331
- const getCodeProposal = (quorum: IQuorumProposals) => quorum.get("code") ?? quorum.get("code2");
338
+ const getCodeProposal = (quorum: IQuorumProposals) =>
339
+ quorum.get("code") ?? quorum.get("code2");
332
340
 
333
341
  /**
334
342
  * Helper function to report to telemetry cases where operation takes longer than expected (200ms)
@@ -384,9 +392,7 @@ export class Container
384
392
 
385
393
  const onClosed = (err?: ICriticalContainerError) => {
386
394
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
387
- reject(
388
- err ?? new GenericError("Container closed without error during load"),
389
- );
395
+ reject(err ?? new GenericError("Container closed without error during load"));
390
396
  };
391
397
  container.on("closed", onClosed);
392
398
 
@@ -678,6 +684,13 @@ export class Container
678
684
  return this.deltaManager.clientDetails.capabilities.interactive;
679
685
  }
680
686
 
687
+ private supportGetSnapshotApi(): boolean {
688
+ const supportGetSnapshotApi: boolean =
689
+ this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch2") ===
690
+ true && this.service?.policies?.supportGetSnapshotApi === true;
691
+ return supportGetSnapshotApi;
692
+ }
693
+
681
694
  /**
682
695
  * Get the code details that are currently specified for the container.
683
696
  * @returns The current code details if any are specified, undefined if none are specified.
@@ -905,8 +918,7 @@ export class Container
905
918
  mode,
906
919
  category: this._lifecycleState === "loading" ? "generic" : category,
907
920
  duration:
908
- performance.now() -
909
- this.connectionTransitionTimes[ConnectionState.CatchingUp],
921
+ performance.now() - this.connectionTransitionTimes[ConnectionState.CatchingUp],
910
922
  ...(details === undefined ? {} : { details: JSON.stringify(details) }),
911
923
  });
912
924
 
@@ -958,9 +970,8 @@ export class Container
958
970
  ? summaryTree
959
971
  : combineAppAndProtocolSummary(summaryTree, this.captureProtocolSummary());
960
972
 
961
- // Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
962
- // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
963
- const forceEnableSummarizeProtocolTree =
973
+ // Whether the combined summary tree has been forced on by either the supportedFeatures flag by the service or the the loader option or the monitoring context
974
+ const enableSummarizeProtocolTree =
964
975
  this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
965
976
  options.summarizeProtocolTree;
966
977
 
@@ -970,7 +981,7 @@ export class Container
970
981
  pendingLocalState?.snapshotBlobs,
971
982
  pendingLocalState?.loadedGroupIdSnapshots,
972
983
  addProtocolSummaryIfMissing,
973
- forceEnableSummarizeProtocolTree,
984
+ enableSummarizeProtocolTree,
974
985
  );
975
986
 
976
987
  const offlineLoadEnabled =
@@ -983,7 +994,8 @@ export class Container
983
994
  this.storageAdapter,
984
995
  offlineLoadEnabled,
985
996
  this,
986
- () => this.isDirty,
997
+ () => this._deltaManager.connectionManager.shouldJoinWrite(),
998
+ () => this.supportGetSnapshotApi(),
987
999
  );
988
1000
 
989
1001
  const isDomAvailable =
@@ -1055,9 +1067,7 @@ export class Container
1055
1067
  {
1056
1068
  eventName: "ContainerClose",
1057
1069
  category:
1058
- this._lifecycleState !== "loading" && error !== undefined
1059
- ? "error"
1060
- : "generic",
1070
+ this._lifecycleState !== "loading" && error !== undefined ? "error" : "generic",
1061
1071
  },
1062
1072
  error,
1063
1073
  );
@@ -1129,10 +1139,7 @@ export class Container
1129
1139
  // Driver need to ensure all caches are cleared on critical errors
1130
1140
  this.service?.dispose(error);
1131
1141
  } catch (exception) {
1132
- this.mc.logger.sendErrorEvent(
1133
- { eventName: "ContainerDisposeException" },
1134
- exception,
1135
- );
1142
+ this.mc.logger.sendErrorEvent({ eventName: "ContainerDisposeException" }, exception);
1136
1143
  }
1137
1144
 
1138
1145
  this.emit("disposed", error);
@@ -1301,8 +1308,7 @@ export class Container
1301
1308
  async (summary) => {
1302
1309
  // Actually go and create the resolved document
1303
1310
  if (this.service === undefined) {
1304
- const createNewResolvedUrl =
1305
- await this.urlResolver.resolve(request);
1311
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
1306
1312
  assert(
1307
1313
  this.client.details.type !== summarizerClientType &&
1308
1314
  createNewResolvedUrl !== undefined,
@@ -1337,9 +1343,7 @@ export class Container
1337
1343
  });
1338
1344
 
1339
1345
  // only enable the new behavior if the config is set
1340
- if (
1341
- this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true
1342
- ) {
1346
+ if (this.mc.config.getBoolean("Fluid.Container.RetryOnAttachFailure") !== true) {
1343
1347
  attachP = attachP.catch((error) => {
1344
1348
  throw normalizeErrorAndClose(error);
1345
1349
  });
@@ -1348,7 +1352,6 @@ export class Container
1348
1352
  // If offline load is enabled, attachP will return the attach summary (in Snapshot format) so we can initialize SerializedStateManager
1349
1353
  const snapshotWithBlobs = await attachP;
1350
1354
  this.serializedStateManager.setInitialSnapshot(snapshotWithBlobs);
1351
-
1352
1355
  if (!this.closed) {
1353
1356
  this.detachedBlobStorage.dispose?.();
1354
1357
  this.handleDeltaConnectionArg(attachProps?.deltaConnection, {
@@ -1451,7 +1454,9 @@ export class Container
1451
1454
  this.connectToDeltaStream(args);
1452
1455
  }
1453
1456
 
1454
- public readonly getAbsoluteUrl = async (relativeUrl: string): Promise<string | undefined> => {
1457
+ public readonly getAbsoluteUrl = async (
1458
+ relativeUrl: string,
1459
+ ): Promise<string | undefined> => {
1455
1460
  if (this.resolvedUrl === undefined) {
1456
1461
  return undefined;
1457
1462
  }
@@ -1615,14 +1620,9 @@ export class Container
1615
1620
 
1616
1621
  timings.phase2 = performance.now();
1617
1622
 
1618
- const supportGetSnapshotApi: boolean =
1619
- this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch") ===
1620
- true && this.service?.policies?.supportGetSnapshotApi === true;
1621
1623
  // Fetch specified snapshot.
1622
- const { baseSnapshot, version } = await this.serializedStateManager.fetchSnapshot(
1623
- specifiedVersion,
1624
- supportGetSnapshotApi,
1625
- );
1624
+ const { baseSnapshot, version } =
1625
+ await this.serializedStateManager.fetchSnapshot(specifiedVersion);
1626
1626
  const baseSnapshotTree: ISnapshotTree | undefined = getSnapshotTree(baseSnapshot);
1627
1627
  this._loadedFromVersion = version;
1628
1628
  const attributes: IDocumentAttributes = await getDocumentAttributes(
@@ -1845,18 +1845,12 @@ export class Container
1845
1845
  const baseTree = getProtocolSnapshotTree(snapshot);
1846
1846
  [quorumSnapshot.members, quorumSnapshot.proposals, quorumSnapshot.values] =
1847
1847
  await Promise.all([
1848
- readAndParse<[string, ISequencedClient][]>(
1849
- storage,
1850
- baseTree.blobs.quorumMembers,
1851
- ),
1848
+ readAndParse<[string, ISequencedClient][]>(storage, baseTree.blobs.quorumMembers),
1852
1849
  readAndParse<[number, ISequencedProposal, string[]][]>(
1853
1850
  storage,
1854
1851
  baseTree.blobs.quorumProposals,
1855
1852
  ),
1856
- readAndParse<[string, ICommittedProposal][]>(
1857
- storage,
1858
- baseTree.blobs.quorumValues,
1859
- ),
1853
+ readAndParse<[string, ICommittedProposal][]>(storage, baseTree.blobs.quorumValues),
1860
1854
  ]);
1861
1855
  }
1862
1856
 
@@ -1958,7 +1952,7 @@ export class Container
1958
1952
  permission: [],
1959
1953
  scopes: [],
1960
1954
  user: { id: "" },
1961
- };
1955
+ };
1962
1956
 
1963
1957
  if (clientDetailsOverride !== undefined) {
1964
1958
  client.details = {
@@ -2151,9 +2145,7 @@ export class Container
2151
2145
  opsBehind,
2152
2146
  online: OnlineStatus[isOnline()],
2153
2147
  lastVisible:
2154
- this.lastVisible !== undefined
2155
- ? performance.now() - this.lastVisible
2156
- : undefined,
2148
+ this.lastVisible !== undefined ? performance.now() - this.lastVisible : undefined,
2157
2149
  checkpointSequenceNumber,
2158
2150
  quorumSize: this._protocolHandler?.quorum.getMembers().size,
2159
2151
  isDirty: this.isDirty,
@@ -17,17 +17,17 @@ import {
17
17
  } from "@fluidframework/container-definitions/internal";
18
18
  import { type FluidObject } from "@fluidframework/core-interfaces";
19
19
  import { type ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
20
- import { IDocumentStorageService, ISnapshot } from "@fluidframework/driver-definitions/internal";
20
+ import { IClientDetails, IQuorumClients } from "@fluidframework/driver-definitions";
21
21
  import {
22
- IClientDetails,
22
+ IDocumentStorageService,
23
+ ISnapshot,
23
24
  IDocumentMessage,
24
- IQuorumClients,
25
- ISequencedDocumentMessage,
26
25
  ISnapshotTree,
27
26
  ISummaryContent,
28
27
  IVersion,
29
28
  MessageType,
30
- } from "@fluidframework/protocol-definitions";
29
+ ISequencedDocumentMessage,
30
+ } from "@fluidframework/driver-definitions/internal";
31
31
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
32
32
 
33
33
  /**
@@ -7,6 +7,7 @@ import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
7
7
  import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions/internal";
8
8
  import { IDisposable } from "@fluidframework/core-interfaces";
9
9
  import { assert } from "@fluidframework/core-utils/internal";
10
+ import { ISummaryHandle, ISummaryTree } from "@fluidframework/driver-definitions";
10
11
  import {
11
12
  FetchSource,
12
13
  IDocumentService,
@@ -15,15 +16,11 @@ import {
15
16
  ISnapshot,
16
17
  ISnapshotFetchOptions,
17
18
  ISummaryContext,
18
- } from "@fluidframework/driver-definitions/internal";
19
- import { UsageError } from "@fluidframework/driver-utils/internal";
20
- import {
21
19
  ICreateBlobResponse,
22
20
  ISnapshotTree,
23
- ISummaryHandle,
24
- ISummaryTree,
25
21
  IVersion,
26
- } from "@fluidframework/protocol-definitions";
22
+ } from "@fluidframework/driver-definitions/internal";
23
+ import { UsageError } from "@fluidframework/driver-utils/internal";
27
24
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
28
25
 
29
26
  // eslint-disable-next-line import/no-deprecated
@@ -49,7 +46,10 @@ export interface ISerializableBlobContents {
49
46
  * container attach state.
50
47
  */
51
48
  export class ContainerStorageAdapter
52
- implements ISerializedStateManagerDocumentStorageService, IDocumentStorageService, IDisposable
49
+ implements
50
+ ISerializedStateManagerDocumentStorageService,
51
+ IDocumentStorageService,
52
+ IDisposable
53
53
  {
54
54
  private _storageService: IDocumentStorageService & Partial<IDisposable>;
55
55
 
@@ -77,7 +77,7 @@ export class ContainerStorageAdapter
77
77
  * @param loadingGroupIdSnapshotsFromPendingState - in offline mode, any loading group snapshots we've downloaded from the service that were stored in the pending state
78
78
  * @param addProtocolSummaryIfMissing - a callback to permit the container to inspect the summary we're about to
79
79
  * upload, and fix it up with a protocol tree if needed
80
- * @param forceEnableSummarizeProtocolTree - Enforce uploading a protocol summary regardless of the service's policy
80
+ * @param enableSummarizeProtocolTree - Enable uploading a protocol summary. Note: preference is given to service policy's "summarizeProtocolTree" before this value.
81
81
  */
82
82
  public constructor(
83
83
  // eslint-disable-next-line import/no-deprecated
@@ -89,10 +89,9 @@ export class ContainerStorageAdapter
89
89
  private readonly blobContents: { [id: string]: ArrayBufferLike | string } = {},
90
90
  private loadingGroupIdSnapshotsFromPendingState: Record<string, ISnapshotInfo> | undefined,
91
91
  private readonly addProtocolSummaryIfMissing: (summaryTree: ISummaryTree) => ISummaryTree,
92
- forceEnableSummarizeProtocolTree: boolean | undefined,
92
+ private readonly enableSummarizeProtocolTree: boolean | undefined,
93
93
  ) {
94
94
  this._storageService = new BlobOnlyStorage(detachedBlobStorage, logger);
95
- this._summarizeProtocolTree = forceEnableSummarizeProtocolTree;
96
95
  }
97
96
 
98
97
  disposed: boolean = false;
@@ -112,15 +111,33 @@ export class ContainerStorageAdapter
112
111
  this.logger,
113
112
  ));
114
113
 
115
- this._summarizeProtocolTree =
116
- this._summarizeProtocolTree ?? service.policies?.summarizeProtocolTree;
117
- if (this.summarizeProtocolTree) {
118
- this.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
119
- this._storageService = new ProtocolTreeStorageService(
120
- retriableStorage,
121
- this.addProtocolSummaryIfMissing,
122
- );
123
- }
114
+ // A storage service wrapper which intercept calls to uploadSummaryWithContext and ensure they include
115
+ // the protocol summary, provided single-commit summary is enabled.
116
+ this._storageService = new ProtocolTreeStorageService(
117
+ retriableStorage,
118
+ (...props) => {
119
+ this.logger.sendTelemetryEvent({ eventName: "summarizeProtocolTreeEnabled" });
120
+ return this.addProtocolSummaryIfMissing(...props);
121
+ },
122
+ // A callback to ensure we fetch the most updated value of service.policies.summarizeProtocolTree, which could be set
123
+ // based on the response received from the service after connection is established.
124
+ () => {
125
+ // Determine whether or not container should upload the protocol summary along with the summary.
126
+ // This is determined based on what value is set for serve policy's summariProtocolTree value or the enableSummarizeProtocolTree
127
+ // retrievd from the loader options or monitoring context config.
128
+ const shouldSummarizeProtocolTree =
129
+ service.policies?.summarizeProtocolTree ?? this.enableSummarizeProtocolTree ?? false;
130
+
131
+ if (this._summarizeProtocolTree !== shouldSummarizeProtocolTree) {
132
+ this.logger.sendTelemetryEvent({
133
+ eventName: "isSummarizeProtocolTreeEnabled",
134
+ details: { value: shouldSummarizeProtocolTree },
135
+ });
136
+ }
137
+ this._summarizeProtocolTree = shouldSummarizeProtocolTree;
138
+ return this._summarizeProtocolTree;
139
+ },
140
+ );
124
141
  }
125
142
 
126
143
  public loadSnapshotFromSnapshotBlobs(snapshotBlobs: ISerializableBlobContents) {
@@ -156,9 +173,7 @@ export class ContainerStorageAdapter
156
173
  snapshotFetchOptions?.loadingGroupIds !== undefined
157
174
  ) {
158
175
  const localSnapshot =
159
- this.loadingGroupIdSnapshotsFromPendingState[
160
- snapshotFetchOptions.loadingGroupIds[0]
161
- ];
176
+ this.loadingGroupIdSnapshotsFromPendingState[snapshotFetchOptions.loadingGroupIds[0]];
162
177
  assert(localSnapshot !== undefined, 0x970 /* Local snapshot must be present */);
163
178
  const attributes = await getDocumentAttributes(this, localSnapshot.baseSnapshot);
164
179
  snapshot = convertSnapshotInfoToSnapshot(localSnapshot, attributes.sequenceNumber);
package/src/contracts.ts CHANGED
@@ -12,16 +12,15 @@ import {
12
12
  IConnectionDetails,
13
13
  } from "@fluidframework/container-definitions/internal";
14
14
  import { IErrorBase, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
15
- import { IContainerPackageInfo } from "@fluidframework/driver-definitions/internal";
15
+ import { ConnectionMode, IClientDetails } from "@fluidframework/driver-definitions";
16
16
  import {
17
- ConnectionMode,
17
+ IContainerPackageInfo,
18
18
  IClientConfiguration,
19
- IClientDetails,
20
19
  IDocumentMessage,
21
- ISequencedDocumentMessage,
22
20
  ISignalClient,
21
+ ISequencedDocumentMessage,
23
22
  ISignalMessage,
24
- } from "@fluidframework/protocol-definitions";
23
+ } from "@fluidframework/driver-definitions/internal";
25
24
 
26
25
  export enum ReconnectMode {
27
26
  Never = "Never",
@@ -16,13 +16,12 @@ import {
16
16
  eventNamespaceSeparator,
17
17
  formatTick,
18
18
  } from "@fluidframework/telemetry-utils/internal";
19
-
20
19
  // This import style is necessary to ensure the emitted JS code works in both CJS and ESM.
21
20
  import debugPkg from "debug";
22
- const { debug: registerDebug } = debugPkg;
23
-
24
21
  import type { IDebugger } from "debug";
25
22
 
23
+ const { debug: registerDebug } = debugPkg;
24
+
26
25
  /**
27
26
  * Implementation of debug logger
28
27
  */
@@ -3,8 +3,8 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ import { ICriticalContainerError } from "@fluidframework/container-definitions";
6
7
  import {
7
- ICriticalContainerError,
8
8
  IDeltaManager,
9
9
  IDeltaManagerEvents,
10
10
  IDeltaQueue,
@@ -16,23 +16,21 @@ import {
16
16
  } from "@fluidframework/core-interfaces";
17
17
  import { IThrottlingWarning } from "@fluidframework/core-interfaces/internal";
18
18
  import { assert } from "@fluidframework/core-utils/internal";
19
+ import { ConnectionMode } from "@fluidframework/driver-definitions";
19
20
  import {
20
21
  IDocumentDeltaStorageService,
21
22
  IDocumentService,
22
23
  DriverErrorTypes,
24
+ IDocumentMessage,
25
+ MessageType,
26
+ ISequencedDocumentMessage,
27
+ ISignalMessage,
23
28
  } from "@fluidframework/driver-definitions/internal";
24
29
  import {
25
30
  MessageType2,
26
31
  NonRetryableError,
27
32
  isRuntimeMessage,
28
33
  } from "@fluidframework/driver-utils/internal";
29
- import {
30
- ConnectionMode,
31
- IDocumentMessage,
32
- ISequencedDocumentMessage,
33
- ISignalMessage,
34
- MessageType,
35
- } from "@fluidframework/protocol-definitions";
36
34
  import {
37
35
  type ITelemetryErrorEventExt,
38
36
  type ITelemetryGenericEventExt,
@@ -70,7 +68,10 @@ export interface IConnectionArgs {
70
68
  export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
71
69
  (event: "throttled", listener: (error: IThrottlingWarning) => void);
72
70
  (event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
73
- (event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
71
+ (
72
+ event: "connect",
73
+ listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void,
74
+ );
74
75
  (event: "establishingConnection", listener: (reason: IConnectionStateChangeReason) => void);
75
76
  (
76
77
  event: "cancelEstablishingConnection",
@@ -471,9 +472,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
471
472
  // Inbound signal queue
472
473
  this._inboundSignal = new DeltaQueue<ISignalMessage>((message) => {
473
474
  if (this.handler === undefined) {
474
- throw new Error(
475
- "Attempted to process an inbound signal without a handler attached",
476
- );
475
+ throw new Error("Attempted to process an inbound signal without a handler attached");
477
476
  }
478
477
  this.handler.processSignal({
479
478
  clientId: message.clientId,
@@ -1039,8 +1038,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
1039
1038
  if (message.type === MessageType.NoOp) {
1040
1039
  this.noOpCount--;
1041
1040
  }
1042
- const clientSeqNumGap =
1043
- message.clientSequenceNumber - this.lastClientSequenceNumber - 1;
1041
+ const clientSeqNumGap = message.clientSequenceNumber - this.lastClientSequenceNumber - 1;
1044
1042
  this.noOpCount -= clientSeqNumGap;
1045
1043
  if (this.noOpCount < 0) {
1046
1044
  throw new Error(`gap in client sequence number: ${clientSeqNumGap}`);
@@ -1144,10 +1142,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
1144
1142
  // Knowing about this mechanism, we could ask for op we already observed to increase validation.
1145
1143
  // This is especially useful when coming out of offline mode or loading from
1146
1144
  // very old cached (by client / driver) snapshot.
1147
- assert(
1148
- n === this.lastQueuedSequenceNumber,
1149
- 0x0f2 /* "previouslyProcessedMessage" */,
1150
- );
1145
+ assert(n === this.lastQueuedSequenceNumber, 0x0f2 /* "previouslyProcessedMessage" */);
1151
1146
  assert(from > 1, 0x0f3 /* "not positive" */);
1152
1147
  from--;
1153
1148
  }
package/src/deltaQueue.ts CHANGED
@@ -4,7 +4,10 @@
4
4
  */
5
5
 
6
6
  import { TypedEventEmitter, performance } from "@fluid-internal/client-utils";
7
- import { IDeltaQueue, IDeltaQueueEvents } from "@fluidframework/container-definitions/internal";
7
+ import {
8
+ IDeltaQueue,
9
+ IDeltaQueueEvents,
10
+ } from "@fluidframework/container-definitions/internal";
8
11
  import { assert } from "@fluidframework/core-utils/internal";
9
12
  import Deque from "double-ended-queue";
10
13
 
package/src/error.ts CHANGED
@@ -16,7 +16,10 @@ import {
16
16
  /**
17
17
  * Warning emitted when requests to storage are being throttled.
18
18
  */
19
- export class ThrottlingWarning extends LoggingError implements IThrottlingWarning, IFluidErrorBase {
19
+ export class ThrottlingWarning
20
+ extends LoggingError
21
+ implements IThrottlingWarning, IFluidErrorBase
22
+ {
20
23
  /**
21
24
  * {@inheritDoc @fluidframework/telemetry-utils#IFluidErrorBase.errorType}
22
25
  */
package/src/index.ts CHANGED
@@ -21,3 +21,10 @@ export {
21
21
  } from "./location-redirection-utilities/index.js";
22
22
  export { IProtocolHandler, ProtocolHandlerBuilder } from "./protocol.js";
23
23
  export { tryParseCompatibleResolvedUrl, IParsedUrl } from "./utils.js";
24
+ export {
25
+ IBaseProtocolHandler,
26
+ IScribeProtocolState,
27
+ IQuorumSnapshot,
28
+ QuorumClientsSnapshot,
29
+ QuorumProposalsSnapshot,
30
+ } from "./protocol/index.js";
package/src/loadPaused.ts CHANGED
@@ -5,8 +5,8 @@
5
5
 
6
6
  import { ILoader, LoaderHeader } from "@fluidframework/container-definitions/internal";
7
7
  import { IRequest } from "@fluidframework/core-interfaces";
8
- import { GenericError } from "@fluidframework/telemetry-utils/internal";
9
8
  import type { IErrorBase } from "@fluidframework/core-interfaces";
9
+ import { GenericError } from "@fluidframework/telemetry-utils/internal";
10
10
 
11
11
  /* eslint-disable jsdoc/check-indentation */
12
12