@fluidframework/container-loader 2.0.0-internal.5.4.0 → 2.0.0-internal.6.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 (100) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/connectionManager.d.ts +1 -1
  3. package/dist/connectionManager.d.ts.map +1 -1
  4. package/dist/connectionManager.js +24 -25
  5. package/dist/connectionManager.js.map +1 -1
  6. package/dist/connectionStateHandler.d.ts +2 -1
  7. package/dist/connectionStateHandler.d.ts.map +1 -1
  8. package/dist/connectionStateHandler.js +9 -16
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts +10 -5
  11. package/dist/container.d.ts.map +1 -1
  12. package/dist/container.js +160 -99
  13. package/dist/container.js.map +1 -1
  14. package/dist/containerContext.d.ts +2 -12
  15. package/dist/containerContext.d.ts.map +1 -1
  16. package/dist/containerContext.js +1 -20
  17. package/dist/containerContext.js.map +1 -1
  18. package/dist/containerStorageAdapter.js +3 -5
  19. package/dist/containerStorageAdapter.js.map +1 -1
  20. package/dist/contracts.d.ts +11 -2
  21. package/dist/contracts.d.ts.map +1 -1
  22. package/dist/contracts.js +3 -3
  23. package/dist/contracts.js.map +1 -1
  24. package/dist/debugLogger.js +2 -3
  25. package/dist/debugLogger.js.map +1 -1
  26. package/dist/deltaManager.d.ts +16 -3
  27. package/dist/deltaManager.d.ts.map +1 -1
  28. package/dist/deltaManager.js +62 -24
  29. package/dist/deltaManager.js.map +1 -1
  30. package/dist/deltaQueue.js +1 -2
  31. package/dist/deltaQueue.js.map +1 -1
  32. package/dist/loader.d.ts +12 -0
  33. package/dist/loader.d.ts.map +1 -1
  34. package/dist/loader.js +57 -42
  35. package/dist/loader.js.map +1 -1
  36. package/dist/packageVersion.d.ts +1 -1
  37. package/dist/packageVersion.js +1 -1
  38. package/dist/packageVersion.js.map +1 -1
  39. package/dist/protocol.d.ts.map +1 -1
  40. package/dist/protocol.js +2 -3
  41. package/dist/protocol.js.map +1 -1
  42. package/dist/utils.d.ts +8 -1
  43. package/dist/utils.d.ts.map +1 -1
  44. package/dist/utils.js +24 -6
  45. package/dist/utils.js.map +1 -1
  46. package/lib/connectionManager.d.ts +1 -1
  47. package/lib/connectionManager.d.ts.map +1 -1
  48. package/lib/connectionManager.js +25 -26
  49. package/lib/connectionManager.js.map +1 -1
  50. package/lib/connectionStateHandler.d.ts +2 -1
  51. package/lib/connectionStateHandler.d.ts.map +1 -1
  52. package/lib/connectionStateHandler.js +9 -16
  53. package/lib/connectionStateHandler.js.map +1 -1
  54. package/lib/container.d.ts +10 -5
  55. package/lib/container.d.ts.map +1 -1
  56. package/lib/container.js +159 -98
  57. package/lib/container.js.map +1 -1
  58. package/lib/containerContext.d.ts +2 -12
  59. package/lib/containerContext.d.ts.map +1 -1
  60. package/lib/containerContext.js +1 -20
  61. package/lib/containerContext.js.map +1 -1
  62. package/lib/containerStorageAdapter.js +3 -5
  63. package/lib/containerStorageAdapter.js.map +1 -1
  64. package/lib/contracts.d.ts +11 -2
  65. package/lib/contracts.d.ts.map +1 -1
  66. package/lib/contracts.js +3 -3
  67. package/lib/contracts.js.map +1 -1
  68. package/lib/debugLogger.js +2 -3
  69. package/lib/debugLogger.js.map +1 -1
  70. package/lib/deltaManager.d.ts +16 -3
  71. package/lib/deltaManager.d.ts.map +1 -1
  72. package/lib/deltaManager.js +62 -24
  73. package/lib/deltaManager.js.map +1 -1
  74. package/lib/deltaQueue.js +1 -2
  75. package/lib/deltaQueue.js.map +1 -1
  76. package/lib/loader.d.ts +12 -0
  77. package/lib/loader.d.ts.map +1 -1
  78. package/lib/loader.js +57 -42
  79. package/lib/loader.js.map +1 -1
  80. package/lib/packageVersion.d.ts +1 -1
  81. package/lib/packageVersion.js +1 -1
  82. package/lib/packageVersion.js.map +1 -1
  83. package/lib/protocol.d.ts.map +1 -1
  84. package/lib/protocol.js +2 -3
  85. package/lib/protocol.js.map +1 -1
  86. package/lib/utils.d.ts +8 -1
  87. package/lib/utils.d.ts.map +1 -1
  88. package/lib/utils.js +22 -5
  89. package/lib/utils.js.map +1 -1
  90. package/package.json +11 -11
  91. package/src/connectionManager.ts +7 -3
  92. package/src/connectionStateHandler.ts +3 -2
  93. package/src/container.ts +113 -28
  94. package/src/containerContext.ts +0 -24
  95. package/src/contracts.ts +16 -5
  96. package/src/deltaManager.ts +22 -5
  97. package/src/loader.ts +37 -23
  98. package/src/packageVersion.ts +1 -1
  99. package/src/protocol.ts +0 -1
  100. package/src/utils.ts +29 -0
package/lib/container.js CHANGED
@@ -8,18 +8,18 @@ import { v4 as uuid } from "uuid";
8
8
  import { TypedEventEmitter, assert, performance, unreachableCase, } from "@fluidframework/common-utils";
9
9
  import { AttachState, isFluidCodeDetails, } from "@fluidframework/container-definitions";
10
10
  import { GenericError, UsageError } from "@fluidframework/container-utils";
11
- import { readAndParse, OnlineStatus, isOnline, combineAppAndProtocolSummary, runWithRetry, isCombinedAppAndProtocolSummary, MessageType2, canBeCoalescedByService, } from "@fluidframework/driver-utils";
11
+ import { readAndParse, OnlineStatus, isOnline, runWithRetry, isCombinedAppAndProtocolSummary, MessageType2, canBeCoalescedByService, } from "@fluidframework/driver-utils";
12
12
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
13
13
  import { createChildLogger, EventEmitterWithErrorHandling, PerformanceEvent, raiseConnectedEvent, connectedEventName, normalizeError, createChildMonitoringContext, wrapError, formatTick, } from "@fluidframework/telemetry-utils";
14
14
  import { Audience } from "./audience";
15
15
  import { ContainerContext } from "./containerContext";
16
- import { ReconnectMode, getPackageName } from "./contracts";
16
+ import { ReconnectMode, getPackageName, } from "./contracts";
17
17
  import { DeltaManager } from "./deltaManager";
18
18
  import { RelativeLoader } from "./loader";
19
19
  import { pkgVersion } from "./packageVersion";
20
20
  import { ContainerStorageAdapter, getBlobContentsFromTree, getBlobContentsFromTreeWithBlobContents, } from "./containerStorageAdapter";
21
21
  import { createConnectionStateHandler } from "./connectionStateHandler";
22
- import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
22
+ import { combineAppAndProtocolSummary, getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer, } from "./utils";
23
23
  import { initQuorumValuesFromCodeDetails } from "./quorum";
24
24
  import { NoopHeuristic } from "./noopHeuristic";
25
25
  import { ConnectionManager } from "./connectionManager";
@@ -104,7 +104,7 @@ export async function waitContainerToCatchUp(container) {
104
104
  }
105
105
  const getCodeProposal =
106
106
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
107
- (quorum) => { var _a; return (_a = quorum.get("code")) !== null && _a !== void 0 ? _a : quorum.get("code2"); };
107
+ (quorum) => quorum.get("code") ?? quorum.get("code2");
108
108
  /**
109
109
  * Helper function to report to telemetry cases where operation takes longer than expected (200ms)
110
110
  * @param logger - logger to use
@@ -124,7 +124,6 @@ export class Container extends EventEmitterWithErrorHandling {
124
124
  * @internal
125
125
  */
126
126
  constructor(createProps, loadProps) {
127
- var _a;
128
127
  super((name, error) => {
129
128
  this.mc.logger.sendErrorEvent({
130
129
  eventName: "ContainerEventHandlerException",
@@ -174,8 +173,8 @@ export class Container extends EventEmitterWithErrorHandling {
174
173
  };
175
174
  const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
176
175
  this.connectionTransitionTimes[ConnectionState.Disconnected] = performance.now();
177
- const pendingLocalState = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState;
178
- this._canReconnect = canReconnect !== null && canReconnect !== void 0 ? canReconnect : true;
176
+ const pendingLocalState = loadProps?.pendingLocalState;
177
+ this._canReconnect = canReconnect ?? true;
179
178
  this.clientDetailsOverride = clientDetailsOverride;
180
179
  this.urlResolver = urlResolver;
181
180
  this.serviceFactory = documentServiceFactory;
@@ -183,14 +182,17 @@ export class Container extends EventEmitterWithErrorHandling {
183
182
  // Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
184
183
  // all clients that were loaded from the same loader (including summarizer clients).
185
184
  // Tracking alternative ways to handle this in AB#4129.
186
- this.options = Object.assign({}, options);
185
+ this.options = { ...options };
187
186
  this.scope = scope;
188
187
  this.detachedBlobStorage = detachedBlobStorage;
189
188
  this.protocolHandlerBuilder =
190
- protocolHandlerBuilder !== null && protocolHandlerBuilder !== void 0 ? protocolHandlerBuilder : ((...args) => new ProtocolHandler(...args, new Audience()));
189
+ protocolHandlerBuilder ?? ((...args) => new ProtocolHandler(...args, new Audience()));
191
190
  // Note that we capture the createProps here so we can replicate the creation call when we want to clone.
192
191
  this.clone = async (_loadProps, createParamOverrides) => {
193
- return Container.load(_loadProps, Object.assign(Object.assign({}, createProps), createParamOverrides));
192
+ return Container.load(_loadProps, {
193
+ ...createProps,
194
+ ...createParamOverrides,
195
+ });
194
196
  };
195
197
  // Create logger for data stores to use
196
198
  const type = this.client.details.type;
@@ -204,7 +206,7 @@ export class Container extends EventEmitterWithErrorHandling {
204
206
  all: {
205
207
  clientType,
206
208
  containerId: uuid(),
207
- docId: () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; },
209
+ docId: () => this.resolvedUrl?.id,
208
210
  containerAttachState: () => this._attachState,
209
211
  containerLifecycleState: () => this._lifecycleState,
210
212
  containerConnectionState: () => ConnectionState[this.connectionState],
@@ -215,22 +217,19 @@ export class Container extends EventEmitterWithErrorHandling {
215
217
  // specific error or class of errors
216
218
  error: {
217
219
  // load information to associate errors with the specific load point
218
- dmInitialSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.initialSequenceNumber; },
219
- dmLastProcessedSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.lastSequenceNumber; },
220
- dmLastKnownSeqNumber: () => { var _a; return (_a = this._deltaManager) === null || _a === void 0 ? void 0 : _a.lastKnownSeqNumber; },
221
- containerLoadedFromVersionId: () => { var _a; return (_a = this._loadedFromVersion) === null || _a === void 0 ? void 0 : _a.id; },
222
- containerLoadedFromVersionDate: () => { var _a; return (_a = this._loadedFromVersion) === null || _a === void 0 ? void 0 : _a.date; },
220
+ dmInitialSeqNumber: () => this._deltaManager?.initialSequenceNumber,
221
+ dmLastProcessedSeqNumber: () => this._deltaManager?.lastSequenceNumber,
222
+ dmLastKnownSeqNumber: () => this._deltaManager?.lastKnownSeqNumber,
223
+ containerLoadedFromVersionId: () => this._loadedFromVersion?.id,
224
+ containerLoadedFromVersionDate: () => this._loadedFromVersion?.date,
223
225
  // message information to associate errors with the specific execution state
224
226
  // dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
225
- dmLastMsqSeqNumber: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.sequenceNumber; },
226
- dmLastMsqSeqTimestamp: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.timestamp; },
227
- dmLastMsqSeqClientId: () => {
228
- var _a, _b, _c, _d;
229
- return ((_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientId) === null
230
- ? "null"
231
- : (_d = (_c = this.deltaManager) === null || _c === void 0 ? void 0 : _c.lastMessage) === null || _d === void 0 ? void 0 : _d.clientId;
232
- },
233
- dmLastMsgClientSeq: () => { var _a, _b; return (_b = (_a = this.deltaManager) === null || _a === void 0 ? void 0 : _a.lastMessage) === null || _b === void 0 ? void 0 : _b.clientSequenceNumber; },
227
+ dmLastMsqSeqNumber: () => this.deltaManager?.lastMessage?.sequenceNumber,
228
+ dmLastMsqSeqTimestamp: () => this.deltaManager?.lastMessage?.timestamp,
229
+ dmLastMsqSeqClientId: () => this.deltaManager?.lastMessage?.clientId === null
230
+ ? "null"
231
+ : this.deltaManager?.lastMessage?.clientId,
232
+ dmLastMsgClientSeq: () => this.deltaManager?.lastMessage?.clientSequenceNumber,
234
233
  connectionStateDuration: () => performance.now() - this.connectionTransitionTimes[this.connectionState],
235
234
  },
236
235
  },
@@ -260,9 +259,14 @@ export class Container extends EventEmitterWithErrorHandling {
260
259
  // Report issues only if we already loaded container - op processing is paused while container is loading,
261
260
  // so we always time-out processing of join op in cases where fetching snapshot takes a minute.
262
261
  // It's not a problem with op processing itself - such issues should be tracked as part of boot perf monitoring instead.
263
- this._deltaManager.logConnectionIssue(Object.assign({ eventName,
264
- mode, category: this._lifecycleState === "loading" ? "generic" : category, duration: performance.now() -
265
- this.connectionTransitionTimes[ConnectionState.CatchingUp] }, (details === undefined ? {} : { details: JSON.stringify(details) })));
262
+ this._deltaManager.logConnectionIssue({
263
+ eventName,
264
+ mode,
265
+ category: this._lifecycleState === "loading" ? "generic" : category,
266
+ duration: performance.now() -
267
+ this.connectionTransitionTimes[ConnectionState.CatchingUp],
268
+ ...(details === undefined ? {} : { details: JSON.stringify(details) }),
269
+ });
266
270
  // If this is "write" connection, it took too long to receive join op. But in most cases that's due
267
271
  // to very slow op fetches and we will eventually get there.
268
272
  // For "read" connections, we get here due to self join signal not arriving on time. We will need to
@@ -279,7 +283,7 @@ export class Container extends EventEmitterWithErrorHandling {
279
283
  clientShouldHaveLeft: (clientId) => {
280
284
  this.clientsWhoShouldHaveLeft.add(clientId);
281
285
  },
282
- }, this.deltaManager, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId);
286
+ }, this.deltaManager, pendingLocalState?.clientId);
283
287
  this.on(savedContainerEvent, () => {
284
288
  this.connectionStateHandler.containerSaved();
285
289
  });
@@ -291,8 +295,9 @@ export class Container extends EventEmitterWithErrorHandling {
291
295
  : combineAppAndProtocolSummary(summaryTree, this.captureProtocolSummary());
292
296
  // Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
293
297
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
294
- const forceEnableSummarizeProtocolTree = (_a = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _a !== void 0 ? _a : options.summarizeProtocolTree;
295
- this.storageAdapter = new ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
298
+ const forceEnableSummarizeProtocolTree = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2") ??
299
+ options.summarizeProtocolTree;
300
+ this.storageAdapter = new ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState?.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
296
301
  const isDomAvailable = typeof document === "object" &&
297
302
  document !== null &&
298
303
  typeof document.addEventListener === "function" &&
@@ -319,7 +324,7 @@ export class Container extends EventEmitterWithErrorHandling {
319
324
  * @internal
320
325
  */
321
326
  static async load(loadProps, createProps) {
322
- const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
327
+ const { version, pendingLocalState, loadMode, resolvedUrl, loadToSequenceNumber } = loadProps;
323
328
  const container = new Container(createProps, loadProps);
324
329
  const disableRecordHeapSize = container.mc.config.getBoolean("Fluid.Loader.DisableRecordHeapSize");
325
330
  return PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
@@ -327,19 +332,20 @@ export class Container extends EventEmitterWithErrorHandling {
327
332
  // if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
328
333
  // to return container, so ignore this value and use undefined for opsBeforeReturn
329
334
  const mode = pendingLocalState
330
- ? Object.assign(Object.assign({}, (loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode)), { opsBeforeReturn: undefined }) : loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode;
335
+ ? { ...(loadMode ?? defaultMode), opsBeforeReturn: undefined }
336
+ : loadMode ?? defaultMode;
331
337
  const onClosed = (err) => {
332
338
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
333
- reject(err !== null && err !== void 0 ? err : new GenericError("Container closed without error during load"));
339
+ reject(err ?? new GenericError("Container closed without error during load"));
334
340
  };
335
341
  container.on("closed", onClosed);
336
342
  container
337
- .load(version, mode, resolvedUrl, pendingLocalState)
343
+ .load(version, mode, resolvedUrl, pendingLocalState, loadToSequenceNumber)
338
344
  .finally(() => {
339
345
  container.removeListener("closed", onClosed);
340
346
  })
341
347
  .then((props) => {
342
- event.end(Object.assign(Object.assign({}, props), loadMode));
348
+ event.end({ ...props, ...loadMode });
343
349
  resolve(container);
344
350
  }, (error) => {
345
351
  const err = normalizeError(error);
@@ -407,7 +413,6 @@ export class Container extends EventEmitterWithErrorHandling {
407
413
  return this;
408
414
  }
409
415
  get resolvedUrl() {
410
- var _a;
411
416
  /**
412
417
  * All attached containers will have a document service,
413
418
  * this is required, as attached containers are attached to
@@ -419,7 +424,7 @@ export class Container extends EventEmitterWithErrorHandling {
419
424
  * is always the same as the containers, as we had to
420
425
  * obtain the resolved url, and then create the service from it.
421
426
  */
422
- return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
427
+ return this.service?.resolvedUrl;
423
428
  }
424
429
  get readOnlyInfo() {
425
430
  return this._deltaManager.readOnlyInfo;
@@ -447,8 +452,8 @@ export class Container extends EventEmitterWithErrorHandling {
447
452
  return this._clientId;
448
453
  }
449
454
  get offlineLoadEnabled() {
450
- var _a, _b;
451
- const enabled = (_a = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad")) !== null && _a !== void 0 ? _a : ((_b = this.options) === null || _b === void 0 ? void 0 : _b.enableOfflineLoad) === true;
455
+ const enabled = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ??
456
+ this.options?.enableOfflineLoad === true;
452
457
  // summarizer will not have any pending state we want to save
453
458
  return enabled && this.deltaManager.clientDetails.capabilities.interactive;
454
459
  }
@@ -485,18 +490,16 @@ export class Container extends EventEmitterWithErrorHandling {
485
490
  * {@inheritDoc @fluidframework/container-definitions#IContainer.entryPoint}
486
491
  */
487
492
  async getEntryPoint() {
488
- var _a, _b;
489
493
  if (this._disposed) {
490
494
  throw new UsageError("The context is already disposed");
491
495
  }
492
496
  if (this._runtime !== undefined) {
493
- return (_b = (_a = this._runtime).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a);
497
+ return this._runtime.getEntryPoint?.();
494
498
  }
495
499
  return new Promise((resolve, reject) => {
496
500
  const runtimeInstantiatedHandler = () => {
497
- var _a, _b;
498
501
  assert(this._runtime !== undefined, 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */);
499
- resolve((_b = (_a = this._runtime).getEntryPoint) === null || _b === void 0 ? void 0 : _b.call(_a));
502
+ resolve(this._runtime.getEntryPoint?.());
500
503
  this._lifecycleEvents.off("disposed", disposedHandler);
501
504
  };
502
505
  const disposedHandler = () => {
@@ -530,7 +533,6 @@ export class Container extends EventEmitterWithErrorHandling {
530
533
  assert(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
531
534
  }
532
535
  closeCore(error) {
533
- var _a;
534
536
  assert(!this.closed, 0x315 /* re-entrancy */);
535
537
  try {
536
538
  // Ensure that we raise all key events even if one of these throws
@@ -546,7 +548,7 @@ export class Container extends EventEmitterWithErrorHandling {
546
548
  : "generic",
547
549
  }, error);
548
550
  this._lifecycleState = "closing";
549
- (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
551
+ this._protocolHandler?.close();
550
552
  this.connectionStateHandler.dispose();
551
553
  }
552
554
  catch (exception) {
@@ -566,7 +568,6 @@ export class Container extends EventEmitterWithErrorHandling {
566
568
  }
567
569
  }
568
570
  disposeCore(error) {
569
- var _a, _b, _c;
570
571
  assert(!this._disposed, 0x54c /* Container already disposed */);
571
572
  this._disposed = true;
572
573
  try {
@@ -583,15 +584,15 @@ export class Container extends EventEmitterWithErrorHandling {
583
584
  if (this._lifecycleState !== "closed") {
584
585
  this._lifecycleState = "disposing";
585
586
  }
586
- (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
587
+ this._protocolHandler?.close();
587
588
  this.connectionStateHandler.dispose();
588
589
  const maybeError = error !== undefined ? new Error(error.message) : undefined;
589
- (_b = this._runtime) === null || _b === void 0 ? void 0 : _b.dispose(maybeError);
590
+ this._runtime?.dispose(maybeError);
590
591
  this.storageAdapter.dispose();
591
592
  // Notify storage about critical errors. They may be due to disconnect between client & server knowledge
592
593
  // about file, like file being overwritten in storage, but client having stale local cache.
593
594
  // Driver need to ensure all caches are cleared on critical errors
594
- (_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
595
+ this.service?.dispose(error);
595
596
  }
596
597
  catch (exception) {
597
598
  this.mc.logger.sendErrorEvent({ eventName: "ContainerDisposeException" }, exception);
@@ -607,15 +608,19 @@ export class Container extends EventEmitterWithErrorHandling {
607
608
  this._lifecycleEvents.emit("disposed");
608
609
  }
609
610
  }
610
- closeAndGetPendingLocalState() {
611
+ async closeAndGetPendingLocalState() {
611
612
  // runtime matches pending ops to successful ones by clientId and client seq num, so we need to close the
612
613
  // container at the same time we get pending state, otherwise this container could reconnect and resubmit with
613
614
  // a new clientId and a future container using stale pending state without the new clientId would resubmit them
614
- const pendingState = this.getPendingLocalState();
615
+ this.disconnect(); // TODO https://dev.azure.com/fluidframework/internal/_workitems/edit/5127
616
+ const pendingState = await this.getPendingLocalStateCore({ notifyImminentClosure: true });
615
617
  this.close();
616
618
  return pendingState;
617
619
  }
618
- getPendingLocalState() {
620
+ async getPendingLocalState() {
621
+ return this.getPendingLocalStateCore({ notifyImminentClosure: false });
622
+ }
623
+ async getPendingLocalStateCore(props) {
619
624
  if (!this.offlineLoadEnabled) {
620
625
  throw new UsageError("Can't get pending local state unless offline load is enabled");
621
626
  }
@@ -626,8 +631,9 @@ export class Container extends EventEmitterWithErrorHandling {
626
631
  assert(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
627
632
  assert(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
628
633
  assert(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
634
+ const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
629
635
  const pendingState = {
630
- pendingRuntimeState: this.runtime.getPendingLocalState(),
636
+ pendingRuntimeState,
631
637
  baseSnapshot: this.baseSnapshot,
632
638
  snapshotBlobs: this.baseSnapshotBlobs,
633
639
  savedOps: this.savedOps,
@@ -656,7 +662,6 @@ export class Container extends EventEmitterWithErrorHandling {
656
662
  }
657
663
  async attach(request) {
658
664
  await PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
659
- var _a;
660
665
  if (this._lifecycleState !== "loaded") {
661
666
  // pre-0.58 error message: containerNotValidForAttach
662
667
  throw new UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
@@ -748,7 +753,7 @@ export class Container extends EventEmitterWithErrorHandling {
748
753
  catch (error) {
749
754
  // add resolved URL on error object so that host has the ability to find this document and delete it
750
755
  const newError = normalizeError(error);
751
- newError.addTelemetryProperties({ resolvedUrl: (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.url });
756
+ newError.addTelemetryProperties({ resolvedUrl: this.resolvedUrl?.url });
752
757
  this.close(newError);
753
758
  throw newError;
754
759
  }
@@ -855,7 +860,6 @@ export class Container extends EventEmitterWithErrorHandling {
855
860
  * Determines if the currently loaded module satisfies the incoming constraint code details
856
861
  */
857
862
  async satisfies(constraintCodeDetails) {
858
- var _a, _b;
859
863
  // If we have no module, it can't satisfy anything.
860
864
  if (this._loadedModule === undefined) {
861
865
  return false;
@@ -865,8 +869,8 @@ export class Container extends EventEmitterWithErrorHandling {
865
869
  if (maybeCompareCodeLoader.IFluidCodeDetailsComparer !== undefined) {
866
870
  comparers.push(maybeCompareCodeLoader.IFluidCodeDetailsComparer);
867
871
  }
868
- const maybeCompareExport = (_a = this._loadedModule) === null || _a === void 0 ? void 0 : _a.module.fluidExport;
869
- if ((maybeCompareExport === null || maybeCompareExport === void 0 ? void 0 : maybeCompareExport.IFluidCodeDetailsComparer) !== undefined) {
872
+ const maybeCompareExport = this._loadedModule?.module.fluidExport;
873
+ if (maybeCompareExport?.IFluidCodeDetailsComparer !== undefined) {
870
874
  comparers.push(maybeCompareExport.IFluidCodeDetailsComparer);
871
875
  }
872
876
  // If there are no comparers, then it's impossible to know if the currently loaded package satisfies
@@ -876,7 +880,7 @@ export class Container extends EventEmitterWithErrorHandling {
876
880
  return false;
877
881
  }
878
882
  for (const comparer of comparers) {
879
- const satisfies = await comparer.satisfies((_b = this._loadedModule) === null || _b === void 0 ? void 0 : _b.details, constraintCodeDetails);
883
+ const satisfies = await comparer.satisfies(this._loadedModule?.details, constraintCodeDetails);
880
884
  if (satisfies === false) {
881
885
  return false;
882
886
  }
@@ -899,8 +903,7 @@ export class Container extends EventEmitterWithErrorHandling {
899
903
  *
900
904
  * @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
901
905
  */
902
- async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
903
- var _a, _b, _c;
906
+ async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
904
907
  this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
905
908
  // Ideally we always connect as "read" by default.
906
909
  // Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
@@ -949,9 +952,51 @@ export class Container extends EventEmitterWithErrorHandling {
949
952
  }
950
953
  const attributes = await this.getDocumentAttributes(this.storageAdapter, snapshot);
951
954
  // If we saved ops, we will replay them and don't need DeltaManager to fetch them
952
- const sequenceNumber = (_a = pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.savedOps[pendingLocalState.savedOps.length - 1]) === null || _a === void 0 ? void 0 : _a.sequenceNumber;
953
- const dmAttributes = sequenceNumber !== undefined ? Object.assign(Object.assign({}, attributes), { sequenceNumber }) : attributes;
955
+ const sequenceNumber = pendingLocalState?.savedOps[pendingLocalState.savedOps.length - 1]?.sequenceNumber;
956
+ const dmAttributes = sequenceNumber !== undefined ? { ...attributes, sequenceNumber } : attributes;
954
957
  let opsBeforeReturnP;
958
+ if (loadMode.pauseAfterLoad === true) {
959
+ // If we are trying to pause at a specific sequence number, ensure the latest snapshot is not newer than the desired sequence number.
960
+ if (loadMode.opsBeforeReturn === "sequenceNumber") {
961
+ assert(loadToSequenceNumber !== undefined, 0x727 /* sequenceNumber should be defined */);
962
+ // Note: It is possible that we think the latest snapshot is newer than the specified sequence number
963
+ // due to saved ops that may be replayed after the snapshot.
964
+ // https://dev.azure.com/fluidframework/internal/_workitems/edit/5055
965
+ if (dmAttributes.sequenceNumber > loadToSequenceNumber) {
966
+ throw new Error("Cannot satisfy request to pause the container at the specified sequence number. Most recent snapshot is newer than the specified sequence number.");
967
+ }
968
+ }
969
+ // Force readonly mode - this will ensure we don't receive an error for the lack of join op
970
+ this.forceReadonly(true);
971
+ // We need to setup a listener to stop op processing once we reach the desired sequence number (if specified).
972
+ const opHandler = () => {
973
+ if (loadToSequenceNumber === undefined) {
974
+ // If there is no specified sequence number, pause after the inbound queue is empty.
975
+ if (this.deltaManager.inbound.length !== 0) {
976
+ return;
977
+ }
978
+ }
979
+ else {
980
+ // If there is a specified sequence number, keep processing until we reach it.
981
+ if (this.deltaManager.lastSequenceNumber < loadToSequenceNumber) {
982
+ return;
983
+ }
984
+ }
985
+ // Pause op processing once we have processed the desired number of ops.
986
+ void this.deltaManager.inbound.pause();
987
+ void this.deltaManager.outbound.pause();
988
+ this.off("op", opHandler);
989
+ };
990
+ if ((loadToSequenceNumber === undefined && this.deltaManager.inbound.length === 0) ||
991
+ this.deltaManager.lastSequenceNumber === loadToSequenceNumber) {
992
+ // If we have already reached the desired sequence number, call opHandler() to pause immediately.
993
+ opHandler();
994
+ }
995
+ else {
996
+ // If we have not yet reached the desired sequence number, setup a listener to pause once we reach it.
997
+ this.on("op", opHandler);
998
+ }
999
+ }
955
1000
  // Attach op handlers to finish initialization and be able to start processing ops
956
1001
  // Kick off any ops fetching if required.
957
1002
  switch (loadMode.opsBeforeReturn) {
@@ -960,6 +1005,9 @@ export class Container extends EventEmitterWithErrorHandling {
960
1005
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
961
1006
  this.attachDeltaManagerOpHandler(dmAttributes, loadMode.deltaConnection !== "none" ? "all" : "none");
962
1007
  break;
1008
+ case "sequenceNumber":
1009
+ opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "sequenceNumber");
1010
+ break;
963
1011
  case "cached":
964
1012
  opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "cached");
965
1013
  break;
@@ -973,18 +1021,18 @@ export class Container extends EventEmitterWithErrorHandling {
973
1021
  // Initialize the protocol handler
974
1022
  await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
975
1023
  const codeDetails = this.getCodeDetailsFromQuorum();
976
- await this.instantiateRuntime(codeDetails, snapshot, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.pendingRuntimeState);
1024
+ await this.instantiateRuntime(codeDetails, snapshot, pendingLocalState?.pendingRuntimeState);
977
1025
  // replay saved ops
978
1026
  if (pendingLocalState) {
979
1027
  for (const message of pendingLocalState.savedOps) {
980
1028
  this.processRemoteMessage(message);
981
1029
  // allow runtime to apply stashed ops at this op's sequence number
982
- await ((_c = (_b = this.runtime).notifyOpReplay) === null || _c === void 0 ? void 0 : _c.call(_b, message));
1030
+ await this.runtime.notifyOpReplay?.(message);
983
1031
  }
984
1032
  pendingLocalState.savedOps = [];
985
1033
  // now set clientId to stashed clientId so live ops are correctly processed as local
986
1034
  assert(this.clientId === undefined, 0x5d6 /* Unexpected clientId when setting stashed clientId */);
987
- this._clientId = pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId;
1035
+ this._clientId = pendingLocalState?.clientId;
988
1036
  }
989
1037
  // We might have hit some failure that did not manifest itself in exception in this flow,
990
1038
  // do not start op processing in such case - static version of Container.load() will handle it correctly.
@@ -1015,6 +1063,19 @@ export class Container extends EventEmitterWithErrorHandling {
1015
1063
  unreachableCase(loadMode.deltaConnection);
1016
1064
  }
1017
1065
  }
1066
+ // If we have not yet reached `loadToSequenceNumber`, we will wait for ops to arrive until we reach it
1067
+ if (loadToSequenceNumber !== undefined &&
1068
+ this.deltaManager.lastSequenceNumber < loadToSequenceNumber) {
1069
+ await new Promise((resolve, reject) => {
1070
+ const opHandler = (message) => {
1071
+ if (message.sequenceNumber >= loadToSequenceNumber) {
1072
+ resolve();
1073
+ this.off("op", opHandler);
1074
+ }
1075
+ };
1076
+ this.on("op", opHandler);
1077
+ });
1078
+ }
1018
1079
  // Safety net: static version of Container.load() should have learned about it through "closed" handler.
1019
1080
  // But if that did not happen for some reason, fail load for sure.
1020
1081
  // Otherwise we can get into situations where container is closed and does not try to connect to ordering
@@ -1169,8 +1230,7 @@ export class Container extends EventEmitterWithErrorHandling {
1169
1230
  return pkg;
1170
1231
  }
1171
1232
  get client() {
1172
- var _a;
1173
- const client = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.client) !== undefined
1233
+ const client = this.options?.client !== undefined
1174
1234
  ? this.options.client
1175
1235
  : {
1176
1236
  details: {
@@ -1218,8 +1278,7 @@ export class Container extends EventEmitterWithErrorHandling {
1218
1278
  this.connectionStateHandler.cancelEstablishingConnection(reason);
1219
1279
  });
1220
1280
  deltaManager.on("disconnect", (reason, error) => {
1221
- var _a;
1222
- (_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyDisconnect();
1281
+ this.noopHeuristic?.notifyDisconnect();
1223
1282
  if (!this.closed) {
1224
1283
  this.connectionStateHandler.receivedDisconnectEvent(reason, error);
1225
1284
  }
@@ -1254,7 +1313,6 @@ export class Container extends EventEmitterWithErrorHandling {
1254
1313
  }, prefetchType);
1255
1314
  }
1256
1315
  logConnectionStateChangeTelemetry(value, oldState, reason, error) {
1257
- var _a;
1258
1316
  // Log actual event
1259
1317
  const time = performance.now();
1260
1318
  this.connectionTransitionTimes[value] = time;
@@ -1284,19 +1342,31 @@ export class Container extends EventEmitterWithErrorHandling {
1284
1342
  }
1285
1343
  connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
1286
1344
  }
1287
- this.mc.logger.sendPerformanceEvent(Object.assign({ eventName: `ConnectionStateChange_${ConnectionState[value]}`, from: ConnectionState[oldState], duration,
1345
+ this.mc.logger.sendPerformanceEvent({
1346
+ eventName: `ConnectionStateChange_${ConnectionState[value]}`,
1347
+ from: ConnectionState[oldState],
1348
+ duration,
1288
1349
  durationFromDisconnected,
1289
1350
  reason,
1290
- connectionInitiationReason, pendingClientId: this.connectionStateHandler.pendingClientId, clientId: this.clientId, autoReconnect,
1291
- opsBehind, online: OnlineStatus[isOnline()], lastVisible: this.lastVisible !== undefined
1351
+ connectionInitiationReason,
1352
+ pendingClientId: this.connectionStateHandler.pendingClientId,
1353
+ clientId: this.clientId,
1354
+ autoReconnect,
1355
+ opsBehind,
1356
+ online: OnlineStatus[isOnline()],
1357
+ lastVisible: this.lastVisible !== undefined
1292
1358
  ? performance.now() - this.lastVisible
1293
- : undefined, checkpointSequenceNumber, quorumSize: (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.quorum.getMembers().size, isDirty: this.isDirty }, this._deltaManager.connectionProps), error);
1359
+ : undefined,
1360
+ checkpointSequenceNumber,
1361
+ quorumSize: this._protocolHandler?.quorum.getMembers().size,
1362
+ isDirty: this.isDirty,
1363
+ ...this._deltaManager.connectionProps,
1364
+ }, error);
1294
1365
  if (value === ConnectionState.Connected) {
1295
1366
  this.firstConnection = false;
1296
1367
  }
1297
1368
  }
1298
1369
  propagateConnectionState(initialTransition, disconnectedReason) {
1299
- var _a;
1300
1370
  // When container loaded, we want to propagate initial connection state.
1301
1371
  // After that, we communicate only transitions to Connected & Disconnected states, skipping all other states.
1302
1372
  // This can be changed in the future, for example we likely should add "CatchingUp" event on Container.
@@ -1307,7 +1377,7 @@ export class Container extends EventEmitterWithErrorHandling {
1307
1377
  }
1308
1378
  const state = this.connectionState === ConnectionState.Connected;
1309
1379
  // Both protocol and context should not be undefined if we got so far.
1310
- this.setContextConnectedState(state, (_a = this.readOnlyInfo.readonly) !== null && _a !== void 0 ? _a : false);
1380
+ this.setContextConnectedState(state, this.readOnlyInfo.readonly ?? false);
1311
1381
  this.protocolHandler.setConnectionState(state, this.clientId);
1312
1382
  raiseConnectedEvent(this.mc.logger, this, state, this.clientId, disconnectedReason);
1313
1383
  }
@@ -1347,12 +1417,11 @@ export class Container extends EventEmitterWithErrorHandling {
1347
1417
  return this.submitMessage(MessageType.Summarize, JSON.stringify(summary), false /* batch */, undefined /* metadata */, undefined /* compression */, referenceSequenceNumber);
1348
1418
  }
1349
1419
  submitMessage(type, contents, batch, metadata, compression, referenceSequenceNumber) {
1350
- var _a;
1351
1420
  if (this.connectionState !== ConnectionState.Connected) {
1352
1421
  this.mc.logger.sendErrorEvent({ eventName: "SubmitMessageWithNoConnection", type });
1353
1422
  return -1;
1354
1423
  }
1355
- (_a = this.noopHeuristic) === null || _a === void 0 ? void 0 : _a.notifyMessageSent();
1424
+ this.noopHeuristic?.notifyMessageSent();
1356
1425
  return this._deltaManager.submit(type, contents, batch, metadata, compression, referenceSequenceNumber);
1357
1426
  }
1358
1427
  processRemoteMessage(message) {
@@ -1427,8 +1496,7 @@ export class Container extends EventEmitterWithErrorHandling {
1427
1496
  * @returns The snapshot requested, or the latest snapshot if no version was specified, plus version ID
1428
1497
  */
1429
1498
  async fetchSnapshotTree(specifiedVersion) {
1430
- var _a;
1431
- const version = await this.getVersion(specifiedVersion !== null && specifiedVersion !== void 0 ? specifiedVersion : null);
1499
+ const version = await this.getVersion(specifiedVersion ?? null);
1432
1500
  if (version === undefined && specifiedVersion !== undefined) {
1433
1501
  // We should have a defined version to load from if specified version requested
1434
1502
  this.mc.logger.sendErrorEvent({
@@ -1437,15 +1505,14 @@ export class Container extends EventEmitterWithErrorHandling {
1437
1505
  });
1438
1506
  }
1439
1507
  this._loadedFromVersion = version;
1440
- const snapshot = (_a = (await this.storageAdapter.getSnapshotTree(version))) !== null && _a !== void 0 ? _a : undefined;
1508
+ const snapshot = (await this.storageAdapter.getSnapshotTree(version)) ?? undefined;
1441
1509
  if (snapshot === undefined && version !== undefined) {
1442
1510
  this.mc.logger.sendErrorEvent({ eventName: "getSnapshotTreeFailed", id: version.id });
1443
1511
  }
1444
- return { snapshot, versionId: version === null || version === void 0 ? void 0 : version.id };
1512
+ return { snapshot, versionId: version?.id };
1445
1513
  }
1446
1514
  async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
1447
- var _a, _b;
1448
- assert(((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing runtime not disposed" */);
1515
+ assert(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
1449
1516
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1450
1517
  // are set. Global requests will still go directly to the loader
1451
1518
  const maybeLoader = this.scope;
@@ -1456,22 +1523,17 @@ export class Container extends EventEmitterWithErrorHandling {
1456
1523
  // An older interface ICodeLoader could return an IFluidModule which didn't have details.
1457
1524
  // If we're using one of those older ICodeLoaders, then we fix up the module with the specified details here.
1458
1525
  // TODO: Determine if this is still a realistic scenario or if this fixup could be removed.
1459
- details: (_b = loadCodeResult.details) !== null && _b !== void 0 ? _b : codeDetails,
1526
+ details: loadCodeResult.details ?? codeDetails,
1460
1527
  };
1461
1528
  const fluidExport = this._loadedModule.module.fluidExport;
1462
- const runtimeFactory = fluidExport === null || fluidExport === void 0 ? void 0 : fluidExport.IRuntimeFactory;
1529
+ const runtimeFactory = fluidExport?.IRuntimeFactory;
1463
1530
  if (runtimeFactory === undefined) {
1464
1531
  throw new Error(packageNotFactoryError);
1465
1532
  }
1466
- const getSpecifiedCodeDetails = () => {
1467
- var _a;
1468
- return ((_a = this.protocolHandler.quorum.get("code")) !== null && _a !== void 0 ? _a : this.protocolHandler.quorum.get("code2"));
1469
- };
1533
+ const getSpecifiedCodeDetails = () => (this.protocolHandler.quorum.get("code") ??
1534
+ this.protocolHandler.quorum.get("code2"));
1470
1535
  const existing = snapshot !== undefined;
1471
- const context = new ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; }, () => this.clientId, () => this._deltaManager.serviceConfiguration, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState);
1472
- this._lifecycleEvents.once("disposed", () => {
1473
- context.dispose();
1474
- });
1536
+ const context = new ContainerContext(this.options, this.scope, snapshot, this._loadedFromVersion, this._deltaManager, this.storageAdapter, this.protocolHandler.quorum, this.protocolHandler.audience, loader, (type, contents, batch, metadata) => this.submitContainerMessage(type, contents, batch, metadata), (summaryOp, referenceSequenceNumber) => this.submitSummaryMessage(summaryOp, referenceSequenceNumber), (batch, referenceSequenceNumber) => this.submitBatch(batch, referenceSequenceNumber), (message) => this.submitSignal(message), (error) => this.dispose(error), (error) => this.close(error), this.updateDirtyContainerState, this.getAbsoluteUrl, () => this.clientId, () => this.attachState, () => this.connected, getSpecifiedCodeDetails, this._deltaManager.clientDetails, existing, this.subLogger, pendingLocalState);
1475
1537
  this._runtime = await PerformanceEvent.timedExecAsync(this.subLogger, { eventName: "InstantiateRuntime" }, async () => runtimeFactory.instantiateRuntime(context, existing));
1476
1538
  this._lifecycleEvents.emit("runtimeInstantiated");
1477
1539
  this._loadedCodeDetails = codeDetails;
@@ -1483,8 +1545,7 @@ export class Container extends EventEmitterWithErrorHandling {
1483
1545
  * @param readonly - Is the container in readonly mode?
1484
1546
  */
1485
1547
  setContextConnectedState(state, readonly) {
1486
- var _a;
1487
- if (((_a = this._runtime) === null || _a === void 0 ? void 0 : _a.disposed) === false) {
1548
+ if (this._runtime?.disposed === false) {
1488
1549
  /**
1489
1550
  * We want to lie to the ContainerRuntime when we are in readonly mode to prevent issues with pending
1490
1551
  * ops getting through to the DeltaManager.