@fluidframework/container-loader 2.0.0-internal.4.0.6 → 2.0.0-internal.4.1.1

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 (92) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +38 -0
  3. package/dist/connectionManager.d.ts +2 -1
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js +16 -6
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/connectionStateHandler.d.ts.map +1 -1
  8. package/dist/connectionStateHandler.js +7 -0
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts +35 -2
  11. package/dist/container.d.ts.map +1 -1
  12. package/dist/container.js +88 -43
  13. package/dist/container.js.map +1 -1
  14. package/dist/containerContext.d.ts +3 -3
  15. package/dist/containerContext.d.ts.map +1 -1
  16. package/dist/containerContext.js +5 -4
  17. package/dist/containerContext.js.map +1 -1
  18. package/dist/containerStorageAdapter.d.ts +27 -2
  19. package/dist/containerStorageAdapter.d.ts.map +1 -1
  20. package/dist/containerStorageAdapter.js +64 -6
  21. package/dist/containerStorageAdapter.js.map +1 -1
  22. package/dist/deltaManager.d.ts +1 -3
  23. package/dist/deltaManager.d.ts.map +1 -1
  24. package/dist/deltaManager.js +3 -8
  25. package/dist/deltaManager.js.map +1 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/loader.d.ts.map +1 -1
  31. package/dist/loader.js +4 -1
  32. package/dist/loader.js.map +1 -1
  33. package/dist/packageVersion.d.ts +1 -1
  34. package/dist/packageVersion.js +1 -1
  35. package/dist/packageVersion.js.map +1 -1
  36. package/dist/protocol.d.ts +1 -0
  37. package/dist/protocol.d.ts.map +1 -1
  38. package/dist/protocol.js +4 -2
  39. package/dist/protocol.js.map +1 -1
  40. package/dist/utils.d.ts.map +1 -1
  41. package/dist/utils.js.map +1 -1
  42. package/lib/connectionManager.d.ts +2 -1
  43. package/lib/connectionManager.d.ts.map +1 -1
  44. package/lib/connectionManager.js +16 -6
  45. package/lib/connectionManager.js.map +1 -1
  46. package/lib/connectionStateHandler.d.ts.map +1 -1
  47. package/lib/connectionStateHandler.js +7 -0
  48. package/lib/connectionStateHandler.js.map +1 -1
  49. package/lib/container.d.ts +35 -2
  50. package/lib/container.d.ts.map +1 -1
  51. package/lib/container.js +90 -45
  52. package/lib/container.js.map +1 -1
  53. package/lib/containerContext.d.ts +3 -3
  54. package/lib/containerContext.d.ts.map +1 -1
  55. package/lib/containerContext.js +5 -4
  56. package/lib/containerContext.js.map +1 -1
  57. package/lib/containerStorageAdapter.d.ts +27 -2
  58. package/lib/containerStorageAdapter.d.ts.map +1 -1
  59. package/lib/containerStorageAdapter.js +62 -6
  60. package/lib/containerStorageAdapter.js.map +1 -1
  61. package/lib/deltaManager.d.ts +1 -3
  62. package/lib/deltaManager.d.ts.map +1 -1
  63. package/lib/deltaManager.js +3 -8
  64. package/lib/deltaManager.js.map +1 -1
  65. package/lib/index.d.ts +3 -2
  66. package/lib/index.d.ts.map +1 -1
  67. package/lib/index.js +1 -1
  68. package/lib/index.js.map +1 -1
  69. package/lib/loader.d.ts.map +1 -1
  70. package/lib/loader.js +4 -1
  71. package/lib/loader.js.map +1 -1
  72. package/lib/packageVersion.d.ts +1 -1
  73. package/lib/packageVersion.js +1 -1
  74. package/lib/packageVersion.js.map +1 -1
  75. package/lib/protocol.d.ts +1 -0
  76. package/lib/protocol.d.ts.map +1 -1
  77. package/lib/protocol.js +3 -1
  78. package/lib/protocol.js.map +1 -1
  79. package/lib/utils.d.ts.map +1 -1
  80. package/lib/utils.js.map +1 -1
  81. package/package.json +17 -13
  82. package/src/connectionManager.ts +17 -7
  83. package/src/connectionStateHandler.ts +12 -0
  84. package/src/container.ts +138 -65
  85. package/src/containerContext.ts +6 -6
  86. package/src/containerStorageAdapter.ts +88 -5
  87. package/src/deltaManager.ts +3 -10
  88. package/src/index.ts +3 -1
  89. package/src/loader.ts +4 -1
  90. package/src/packageVersion.ts +1 -1
  91. package/src/protocol.ts +4 -1
  92. package/src/utils.ts +3 -1
package/lib/container.js CHANGED
@@ -4,6 +4,8 @@
4
4
  */
5
5
  // eslint-disable-next-line import/no-internal-modules
6
6
  import merge from "lodash/merge";
7
+ // eslint-disable-next-line import/no-internal-modules
8
+ import cloneDeep from "lodash/cloneDeep";
7
9
  import { v4 as uuid } from "uuid";
8
10
  import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
9
11
  import { AttachState, isFluidCodeDetails, } from "@fluidframework/container-definitions";
@@ -18,14 +20,14 @@ import { DeltaManager } from "./deltaManager";
18
20
  import { DeltaManagerProxy } from "./deltaManagerProxy";
19
21
  import { RelativeLoader } from "./loader";
20
22
  import { pkgVersion } from "./packageVersion";
21
- import { ContainerStorageAdapter } from "./containerStorageAdapter";
23
+ import { ContainerStorageAdapter, getBlobContentsFromTree, getBlobContentsFromTreeWithBlobContents, } from "./containerStorageAdapter";
22
24
  import { createConnectionStateHandler } from "./connectionStateHandler";
23
25
  import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
24
26
  import { initQuorumValuesFromCodeDetails, getCodeDetailsFromQuorumValues, QuorumProxy, } from "./quorum";
25
27
  import { CollabWindowTracker } from "./collabWindowTracker";
26
28
  import { ConnectionManager } from "./connectionManager";
27
29
  import { ConnectionState } from "./connectionState";
28
- import { ProtocolHandler } from "./protocol";
30
+ import { OnlyValidTermValue, ProtocolHandler, } from "./protocol";
29
31
  const detachedContainerRefSeqNumber = 0;
30
32
  const dirtyContainerEvent = "dirty";
31
33
  const savedContainerEvent = "saved";
@@ -123,8 +125,11 @@ const summarizerClientType = "summarizer";
123
125
  * @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
124
126
  */
125
127
  export class Container extends EventEmitterWithErrorHandling {
128
+ /**
129
+ * @internal
130
+ */
126
131
  constructor(loader, config, protocolHandlerBuilder) {
127
- var _a, _b;
132
+ var _a, _b, _c;
128
133
  super((name, error) => {
129
134
  this.mc.logger.sendErrorEvent({
130
135
  eventName: "ContainerEventHandlerException",
@@ -160,6 +165,7 @@ export class Container extends EventEmitterWithErrorHandling {
160
165
  this.messageCountAfterDisconnection = 0;
161
166
  this.attachStarted = false;
162
167
  this._dirtyContainer = false;
168
+ this.savedOps = [];
163
169
  this.setAutoReconnectTime = performance.now();
164
170
  this._disposed = false;
165
171
  this.clientDetailsOverride = config.clientDetailsOverride;
@@ -204,9 +210,8 @@ export class Container extends EventEmitterWithErrorHandling {
204
210
  });
205
211
  // Prefix all events in this file with container-loader
206
212
  this.mc = loggerToMonitoringContext(ChildLogger.create(this.subLogger, "Container"));
207
- this.options = Object.assign({}, this.loader.services.options);
213
+ this.options = cloneDeep(this.loader.services.options);
208
214
  this._deltaManager = this.createDeltaManager();
209
- this._clientId = (_a = config.serializedContainerState) === null || _a === void 0 ? void 0 : _a.clientId;
210
215
  this.connectionStateHandler = createConnectionStateHandler({
211
216
  logger: this.mc.logger,
212
217
  connectionStateChanged: (value, oldState, reason) => {
@@ -245,7 +250,7 @@ export class Container extends EventEmitterWithErrorHandling {
245
250
  this.connect();
246
251
  }
247
252
  },
248
- }, this.deltaManager, this._clientId);
253
+ }, this.deltaManager, (_a = config.serializedContainerState) === null || _a === void 0 ? void 0 : _a.clientId);
249
254
  this.on(savedContainerEvent, () => {
250
255
  this.connectionStateHandler.containerSaved();
251
256
  });
@@ -258,7 +263,7 @@ export class Container extends EventEmitterWithErrorHandling {
258
263
  // Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
259
264
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
260
265
  const forceEnableSummarizeProtocolTree = (_b = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _b !== void 0 ? _b : this.loader.services.options.summarizeProtocolTree;
261
- this.storageAdapter = new ContainerStorageAdapter(this.loader.services.detachedBlobStorage, this.mc.logger, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
266
+ this.storageAdapter = new ContainerStorageAdapter(this.loader.services.detachedBlobStorage, this.mc.logger, (_c = config.serializedContainerState) === null || _c === void 0 ? void 0 : _c.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
262
267
  const isDomAvailable = typeof document === "object" &&
263
268
  document !== null &&
264
269
  typeof document.addEventListener === "function" &&
@@ -282,6 +287,7 @@ export class Container extends EventEmitterWithErrorHandling {
282
287
  }
283
288
  /**
284
289
  * Load an existing container.
290
+ * @internal
285
291
  */
286
292
  static async load(loader, loadOptions, pendingLocalState, protocolHandlerBuilder) {
287
293
  const container = new Container(loader, {
@@ -430,6 +436,12 @@ export class Container extends EventEmitterWithErrorHandling {
430
436
  get clientDetails() {
431
437
  return this._deltaManager.clientDetails;
432
438
  }
439
+ get offlineLoadEnabled() {
440
+ var _a;
441
+ // summarizer will not have any pending state we want to save
442
+ return (((_a = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) !== null && _a !== void 0 ? _a : false) &&
443
+ this.clientDetails.capabilities.interactive);
444
+ }
433
445
  /**
434
446
  * Get the code details that are currently specified for the container.
435
447
  * @returns The current code details if any are specified, undefined if none are specified.
@@ -607,15 +619,21 @@ export class Container extends EventEmitterWithErrorHandling {
607
619
  // runtime matches pending ops to successful ones by clientId and client seq num, so we need to close the
608
620
  // container at the same time we get pending state, otherwise this container could reconnect and resubmit with
609
621
  // a new clientId and a future container using stale pending state without the new clientId would resubmit them
622
+ if (!this.offlineLoadEnabled) {
623
+ throw new UsageError("Can't get pending local state unless offline load is enabled");
624
+ }
610
625
  assert(this.attachState === AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
611
626
  assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
612
627
  assert(!!this._protocolHandler, 0x2e3 /* "Must have a valid protocol handler instance" */);
613
- assert(this._protocolHandler.attributes.term !== undefined, 0x37e /* Must have a valid protocol handler instance */);
628
+ assert(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
629
+ assert(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
614
630
  const pendingState = {
615
631
  pendingRuntimeState: this.context.getPendingLocalState(),
632
+ baseSnapshot: this.baseSnapshot,
633
+ snapshotBlobs: this.baseSnapshotBlobs,
634
+ savedOps: this.savedOps,
616
635
  url: this.resolvedUrl.url,
617
- protocol: this.protocolHandler.getProtocolState(),
618
- term: this._protocolHandler.attributes.term,
636
+ term: OnlyValidTermValue,
619
637
  clientId: this.clientId,
620
638
  };
621
639
  this.mc.logger.sendTelemetryEvent({ eventName: "CloseAndGetPendingLocalState" });
@@ -667,7 +685,13 @@ export class Container extends EventEmitterWithErrorHandling {
667
685
  // starting to attach the container to storage.
668
686
  // Also, this should only be fired in detached container.
669
687
  this._attachState = AttachState.Attaching;
670
- this.context.notifyAttaching(getSnapshotTreeFromSerializedContainer(summary));
688
+ this.emit("attaching");
689
+ if (this.offlineLoadEnabled) {
690
+ const snapshot = getSnapshotTreeFromSerializedContainer(summary);
691
+ this.baseSnapshot = snapshot;
692
+ this.baseSnapshotBlobs =
693
+ getBlobContentsFromTreeWithBlobContents(snapshot);
694
+ }
671
695
  }
672
696
  // Actually go and create the resolved document
673
697
  const createNewResolvedUrl = await this.urlResolver.resolve(request);
@@ -704,7 +728,13 @@ export class Container extends EventEmitterWithErrorHandling {
704
728
  const protocolSummary = this.captureProtocolSummary();
705
729
  summary = combineAppAndProtocolSummary(appSummary, protocolSummary);
706
730
  this._attachState = AttachState.Attaching;
707
- this.context.notifyAttaching(getSnapshotTreeFromSerializedContainer(summary));
731
+ this.emit("attaching");
732
+ if (this.offlineLoadEnabled) {
733
+ const snapshot = getSnapshotTreeFromSerializedContainer(summary);
734
+ this.baseSnapshot = snapshot;
735
+ this.baseSnapshotBlobs =
736
+ getBlobContentsFromTreeWithBlobContents(snapshot);
737
+ }
708
738
  await this.storageAdapter.uploadSummaryWithContext(summary, {
709
739
  referenceSequenceNumber: 0,
710
740
  ackHandle: undefined,
@@ -862,6 +892,7 @@ export class Container extends EventEmitterWithErrorHandling {
862
892
  * @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
863
893
  */
864
894
  async load(specifiedVersion, loadMode, pendingLocalState) {
895
+ var _a;
865
896
  if (this._resolvedUrl === undefined) {
866
897
  throw new Error("Attempting to load without a resolved url");
867
898
  }
@@ -882,7 +913,7 @@ export class Container extends EventEmitterWithErrorHandling {
882
913
  };
883
914
  // Start websocket connection as soon as possible. Note that there is no op handler attached yet, but the
884
915
  // DeltaManager is resilient to this and will wait to start processing ops until after it is attached.
885
- if (loadMode.deltaConnection === undefined) {
916
+ if (loadMode.deltaConnection === undefined && !pendingLocalState) {
886
917
  this.connectToDeltaStream(connectionArgs);
887
918
  }
888
919
  if (!pendingLocalState) {
@@ -900,15 +931,23 @@ export class Container extends EventEmitterWithErrorHandling {
900
931
  // Fetch specified snapshot.
901
932
  const { snapshot, versionId } = pendingLocalState === undefined
902
933
  ? await this.fetchSnapshotTree(specifiedVersion)
903
- : { snapshot: undefined, versionId: undefined };
904
- assert(snapshot !== undefined || pendingLocalState !== undefined, 0x237 /* "Snapshot should exist" */);
905
- const attributes = pendingLocalState === undefined
906
- ? await this.getDocumentAttributes(this.storageAdapter, snapshot)
907
- : {
908
- sequenceNumber: pendingLocalState.protocol.sequenceNumber,
909
- minimumSequenceNumber: pendingLocalState.protocol.minimumSequenceNumber,
910
- term: pendingLocalState.term,
911
- };
934
+ : { snapshot: pendingLocalState.baseSnapshot, versionId: undefined };
935
+ if (pendingLocalState) {
936
+ this.baseSnapshot = pendingLocalState.baseSnapshot;
937
+ this.baseSnapshotBlobs = pendingLocalState.snapshotBlobs;
938
+ }
939
+ else {
940
+ assert(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
941
+ if (this.offlineLoadEnabled) {
942
+ this.baseSnapshot = snapshot;
943
+ // Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
944
+ this.baseSnapshotBlobs = await getBlobContentsFromTree(snapshot, this.storage);
945
+ }
946
+ }
947
+ const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
948
+ // If we saved ops, we will replay them and don't need DeltaManager to fetch them
949
+ const sequenceNumber = (_a = pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.savedOps[pendingLocalState.savedOps.length - 1]) === null || _a === void 0 ? void 0 : _a.sequenceNumber;
950
+ const dmAttributes = sequenceNumber !== undefined ? Object.assign(Object.assign({}, attributes), { sequenceNumber }) : attributes;
912
951
  let opsBeforeReturnP;
913
952
  // Attach op handlers to finish initialization and be able to start processing ops
914
953
  // Kick off any ops fetching if required.
@@ -916,32 +955,35 @@ export class Container extends EventEmitterWithErrorHandling {
916
955
  case undefined:
917
956
  // Start prefetch, but not set opsBeforeReturnP - boot is not blocked by it!
918
957
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
919
- this.attachDeltaManagerOpHandler(attributes, loadMode.deltaConnection !== "none" ? "all" : "none");
958
+ this.attachDeltaManagerOpHandler(dmAttributes, loadMode.deltaConnection !== "none" ? "all" : "none");
920
959
  break;
921
960
  case "cached":
922
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(attributes, "cached");
961
+ opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "cached");
923
962
  break;
924
963
  case "all":
925
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(attributes, "all");
964
+ opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "all");
926
965
  break;
927
966
  default:
928
967
  unreachableCase(loadMode.opsBeforeReturn);
929
968
  }
930
969
  // ...load in the existing quorum
931
970
  // Initialize the protocol handler
932
- if (pendingLocalState === undefined) {
933
- await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
934
- }
935
- else {
936
- this.initializeProtocolState(attributes, {
937
- members: pendingLocalState.protocol.members,
938
- proposals: pendingLocalState.protocol.proposals,
939
- values: pendingLocalState.protocol.values,
940
- });
941
- }
971
+ await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
942
972
  const codeDetails = this.getCodeDetailsFromQuorum();
943
973
  await this.instantiateContext(true, // existing
944
974
  codeDetails, snapshot, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.pendingRuntimeState);
975
+ // replay saved ops
976
+ if (pendingLocalState) {
977
+ for (const message of pendingLocalState.savedOps) {
978
+ this.processRemoteMessage(message);
979
+ // allow runtime to apply stashed ops at this op's sequence number
980
+ await this.context.notifyOpReplay(message);
981
+ }
982
+ pendingLocalState.savedOps = [];
983
+ // now set clientId to stashed clientId so live ops are correctly processed as local
984
+ assert(this.clientId === undefined, 0x5d6 /* Unexpected clientId when setting stashed clientId */);
985
+ this._clientId = pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId;
986
+ }
945
987
  // We might have hit some failure that did not manifest itself in exception in this flow,
946
988
  // do not start op processing in such case - static version of Container.load() will handle it correctly.
947
989
  if (!this.closed) {
@@ -954,6 +996,11 @@ export class Container extends EventEmitterWithErrorHandling {
954
996
  }
955
997
  switch (loadMode.deltaConnection) {
956
998
  case undefined:
999
+ if (pendingLocalState) {
1000
+ // connect to delta stream now since we did not before
1001
+ this.connectToDeltaStream(connectionArgs);
1002
+ }
1003
+ // intentional fallthrough
957
1004
  case "delayed":
958
1005
  assert(this.inboundQueuePausedFromInit, 0x346 /* inboundQueuePausedFromInit should be true */);
959
1006
  this.inboundQueuePausedFromInit = false;
@@ -986,7 +1033,7 @@ export class Container extends EventEmitterWithErrorHandling {
986
1033
  async createDetached(source) {
987
1034
  const attributes = {
988
1035
  sequenceNumber: detachedContainerRefSeqNumber,
989
- term: 1,
1036
+ term: OnlyValidTermValue,
990
1037
  minimumSequenceNumber: 0,
991
1038
  };
992
1039
  await this.attachDeltaManagerOpHandler(attributes);
@@ -1029,7 +1076,7 @@ export class Container extends EventEmitterWithErrorHandling {
1029
1076
  return {
1030
1077
  minimumSequenceNumber: 0,
1031
1078
  sequenceNumber: 0,
1032
- term: 1,
1079
+ term: OnlyValidTermValue,
1033
1080
  };
1034
1081
  }
1035
1082
  // Backward compatibility: old docs would have ".attributes" instead of "attributes"
@@ -1037,10 +1084,6 @@ export class Container extends EventEmitterWithErrorHandling {
1037
1084
  ? tree.trees[".protocol"].blobs.attributes
1038
1085
  : tree.blobs[".attributes"];
1039
1086
  const attributes = await readAndParse(storage, attributesHash);
1040
- // Backward compatibility for older summaries with no term
1041
- if (attributes.term === undefined) {
1042
- attributes.term = 1;
1043
- }
1044
1087
  return attributes;
1045
1088
  }
1046
1089
  async initializeProtocolStateFromSnapshot(attributes, storage, snapshot) {
@@ -1160,7 +1203,7 @@ export class Container extends EventEmitterWithErrorHandling {
1160
1203
  }
1161
1204
  createDeltaManager() {
1162
1205
  const serviceProvider = () => this.service;
1163
- const deltaManager = new DeltaManager(serviceProvider, ChildLogger.create(this.subLogger, "DeltaManager"), () => this.activeConnection(), (props) => new ConnectionManager(serviceProvider, this.client, this._canReconnect, ChildLogger.create(this.subLogger, "ConnectionManager"), props));
1206
+ const deltaManager = new DeltaManager(serviceProvider, ChildLogger.create(this.subLogger, "DeltaManager"), () => this.activeConnection(), (props) => new ConnectionManager(serviceProvider, () => this.isDirty, this.client, this._canReconnect, ChildLogger.create(this.subLogger, "ConnectionManager"), props));
1164
1207
  // Disable inbound queues as Container is not ready to accept any ops until we are fully loaded!
1165
1208
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1166
1209
  deltaManager.inbound.pause();
@@ -1199,8 +1242,7 @@ export class Container extends EventEmitterWithErrorHandling {
1199
1242
  return deltaManager;
1200
1243
  }
1201
1244
  async attachDeltaManagerOpHandler(attributes, prefetchType) {
1202
- var _a;
1203
- return this._deltaManager.attachOpHandler(attributes.minimumSequenceNumber, attributes.sequenceNumber, (_a = attributes.term) !== null && _a !== void 0 ? _a : 1, {
1245
+ return this._deltaManager.attachOpHandler(attributes.minimumSequenceNumber, attributes.sequenceNumber, {
1204
1246
  process: (message) => this.processRemoteMessage(message),
1205
1247
  processSignal: (message) => {
1206
1248
  this.processSignal(message);
@@ -1263,7 +1305,7 @@ export class Container extends EventEmitterWithErrorHandling {
1263
1305
  this.messageCountAfterDisconnection = 0;
1264
1306
  }
1265
1307
  // Both protocol and context should not be undefined if we got so far.
1266
- this.setContextConnectedState(state, (_a = this._deltaManager.connectionManager.readOnlyInfo.readonly) !== null && _a !== void 0 ? _a : false);
1308
+ this.setContextConnectedState(state, (_a = this.readOnlyInfo.readonly) !== null && _a !== void 0 ? _a : false);
1267
1309
  this.protocolHandler.setConnectionState(state, this.clientId);
1268
1310
  raiseConnectedEvent(this.mc.logger, this, state, this.clientId, disconnectedReason);
1269
1311
  if (logOpsOnReconnect) {
@@ -1321,6 +1363,9 @@ export class Container extends EventEmitterWithErrorHandling {
1321
1363
  return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
1322
1364
  }
1323
1365
  processRemoteMessage(message) {
1366
+ if (this.offlineLoadEnabled) {
1367
+ this.savedOps.push(message);
1368
+ }
1324
1369
  const local = this.clientId === message.clientId;
1325
1370
  // Allow the protocol handler to process the message
1326
1371
  const result = this.protocolHandler.processMessage(message, local);