@fluidframework/container-loader 2.0.0-internal.6.1.1 → 2.0.0-internal.6.3.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 (130) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +4 -3
  3. package/dist/audience.js +2 -2
  4. package/dist/audience.js.map +1 -1
  5. package/dist/catchUpMonitor.js +2 -2
  6. package/dist/catchUpMonitor.js.map +1 -1
  7. package/dist/connectionManager.d.ts +1 -1
  8. package/dist/connectionManager.d.ts.map +1 -1
  9. package/dist/connectionManager.js +38 -37
  10. package/dist/connectionManager.js.map +1 -1
  11. package/dist/connectionStateHandler.js +24 -24
  12. package/dist/connectionStateHandler.js.map +1 -1
  13. package/dist/container.d.ts +8 -1
  14. package/dist/container.d.ts.map +1 -1
  15. package/dist/container.js +117 -98
  16. package/dist/container.js.map +1 -1
  17. package/dist/containerStorageAdapter.d.ts.map +1 -1
  18. package/dist/containerStorageAdapter.js +10 -9
  19. package/dist/containerStorageAdapter.js.map +1 -1
  20. package/dist/contracts.d.ts +2 -2
  21. package/dist/contracts.d.ts.map +1 -1
  22. package/dist/contracts.js.map +1 -1
  23. package/dist/debugLogger.js +2 -2
  24. package/dist/debugLogger.js.map +1 -1
  25. package/dist/deltaManager.d.ts +3 -4
  26. package/dist/deltaManager.d.ts.map +1 -1
  27. package/dist/deltaManager.js +39 -38
  28. package/dist/deltaManager.js.map +1 -1
  29. package/dist/deltaQueue.d.ts +1 -1
  30. package/dist/deltaQueue.d.ts.map +1 -1
  31. package/dist/deltaQueue.js +9 -8
  32. package/dist/deltaQueue.js.map +1 -1
  33. package/dist/disposal.d.ts +2 -2
  34. package/dist/disposal.d.ts.map +1 -1
  35. package/dist/disposal.js +1 -1
  36. package/dist/disposal.js.map +1 -1
  37. package/dist/error.d.ts +23 -0
  38. package/dist/error.d.ts.map +1 -0
  39. package/dist/error.js +32 -0
  40. package/dist/error.js.map +1 -0
  41. package/dist/loader.d.ts +9 -2
  42. package/dist/loader.d.ts.map +1 -1
  43. package/dist/loader.js +12 -7
  44. package/dist/loader.js.map +1 -1
  45. package/dist/noopHeuristic.d.ts +2 -2
  46. package/dist/noopHeuristic.d.ts.map +1 -1
  47. package/dist/noopHeuristic.js +6 -5
  48. package/dist/noopHeuristic.js.map +1 -1
  49. package/dist/packageVersion.d.ts +1 -1
  50. package/dist/packageVersion.js +1 -1
  51. package/dist/packageVersion.js.map +1 -1
  52. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  53. package/dist/retriableDocumentStorageService.js +4 -4
  54. package/dist/retriableDocumentStorageService.js.map +1 -1
  55. package/dist/utils.d.ts.map +1 -1
  56. package/dist/utils.js +9 -8
  57. package/dist/utils.js.map +1 -1
  58. package/lib/audience.js +1 -1
  59. package/lib/audience.js.map +1 -1
  60. package/lib/catchUpMonitor.js +1 -1
  61. package/lib/catchUpMonitor.js.map +1 -1
  62. package/lib/connectionManager.d.ts +1 -1
  63. package/lib/connectionManager.d.ts.map +1 -1
  64. package/lib/connectionManager.js +10 -9
  65. package/lib/connectionManager.js.map +1 -1
  66. package/lib/connectionStateHandler.js +1 -1
  67. package/lib/connectionStateHandler.js.map +1 -1
  68. package/lib/container.d.ts +8 -1
  69. package/lib/container.d.ts.map +1 -1
  70. package/lib/container.js +73 -54
  71. package/lib/container.js.map +1 -1
  72. package/lib/containerStorageAdapter.d.ts.map +1 -1
  73. package/lib/containerStorageAdapter.js +2 -1
  74. package/lib/containerStorageAdapter.js.map +1 -1
  75. package/lib/contracts.d.ts +2 -2
  76. package/lib/contracts.d.ts.map +1 -1
  77. package/lib/contracts.js.map +1 -1
  78. package/lib/debugLogger.js +1 -1
  79. package/lib/debugLogger.js.map +1 -1
  80. package/lib/deltaManager.d.ts +3 -4
  81. package/lib/deltaManager.d.ts.map +1 -1
  82. package/lib/deltaManager.js +6 -5
  83. package/lib/deltaManager.js.map +1 -1
  84. package/lib/deltaQueue.d.ts +1 -1
  85. package/lib/deltaQueue.d.ts.map +1 -1
  86. package/lib/deltaQueue.js +2 -1
  87. package/lib/deltaQueue.js.map +1 -1
  88. package/lib/disposal.d.ts +2 -2
  89. package/lib/disposal.d.ts.map +1 -1
  90. package/lib/disposal.js +1 -1
  91. package/lib/disposal.js.map +1 -1
  92. package/lib/error.d.ts +23 -0
  93. package/lib/error.d.ts.map +1 -0
  94. package/lib/error.js +28 -0
  95. package/lib/error.js.map +1 -0
  96. package/lib/loader.d.ts +9 -2
  97. package/lib/loader.d.ts.map +1 -1
  98. package/lib/loader.js +11 -6
  99. package/lib/loader.js.map +1 -1
  100. package/lib/noopHeuristic.d.ts +2 -2
  101. package/lib/noopHeuristic.d.ts.map +1 -1
  102. package/lib/noopHeuristic.js +2 -1
  103. package/lib/noopHeuristic.js.map +1 -1
  104. package/lib/packageVersion.d.ts +1 -1
  105. package/lib/packageVersion.js +1 -1
  106. package/lib/packageVersion.js.map +1 -1
  107. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  108. package/lib/retriableDocumentStorageService.js +2 -2
  109. package/lib/retriableDocumentStorageService.js.map +1 -1
  110. package/lib/utils.d.ts.map +1 -1
  111. package/lib/utils.js +4 -3
  112. package/lib/utils.js.map +1 -1
  113. package/package.json +21 -27
  114. package/src/audience.ts +1 -1
  115. package/src/catchUpMonitor.ts +1 -1
  116. package/src/connectionManager.ts +20 -10
  117. package/src/connectionStateHandler.ts +1 -1
  118. package/src/container.ts +120 -79
  119. package/src/containerStorageAdapter.ts +2 -1
  120. package/src/contracts.ts +1 -2
  121. package/src/debugLogger.ts +1 -1
  122. package/src/deltaManager.ts +16 -13
  123. package/src/deltaQueue.ts +2 -1
  124. package/src/disposal.ts +2 -2
  125. package/src/error.ts +44 -0
  126. package/src/loader.ts +30 -5
  127. package/src/noopHeuristic.ts +3 -2
  128. package/src/packageVersion.ts +1 -1
  129. package/src/retriableDocumentStorageService.ts +2 -4
  130. package/src/utils.ts +4 -8
package/dist/container.js CHANGED
@@ -11,9 +11,10 @@ exports.Container = exports.ReportIfTooLong = exports.waitContainerToCatchUp = v
11
11
  // eslint-disable-next-line import/no-internal-modules
12
12
  const merge_1 = __importDefault(require("lodash/merge"));
13
13
  const uuid_1 = require("uuid");
14
- const common_utils_1 = require("@fluidframework/common-utils");
14
+ const core_utils_1 = require("@fluidframework/core-utils");
15
+ const client_utils_1 = require("@fluid-internal/client-utils");
16
+ const core_interfaces_1 = require("@fluidframework/core-interfaces");
15
17
  const container_definitions_1 = require("@fluidframework/container-definitions");
16
- const container_utils_1 = require("@fluidframework/container-utils");
17
18
  const driver_utils_1 = require("@fluidframework/driver-utils");
18
19
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
19
20
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
@@ -54,7 +55,7 @@ const packageNotFactoryError = "Code package does not implement IRuntimeFactory"
54
55
  async function waitContainerToCatchUp(container) {
55
56
  // Make sure we stop waiting if container is closed.
56
57
  if (container.closed) {
57
- throw new container_utils_1.UsageError("waitContainerToCatchUp: Container closed");
58
+ throw new telemetry_utils_1.UsageError("waitContainerToCatchUp: Container closed");
58
59
  }
59
60
  return new Promise((resolve, reject) => {
60
61
  const deltaManager = container.deltaManager;
@@ -62,8 +63,8 @@ async function waitContainerToCatchUp(container) {
62
63
  container.off("closed", closedCallback);
63
64
  const baseMessage = "Container closed while waiting to catch up";
64
65
  reject(err !== undefined
65
- ? (0, telemetry_utils_1.wrapError)(err, (innerMessage) => new container_utils_1.GenericError(`${baseMessage}: ${innerMessage}`))
66
- : new container_utils_1.GenericError(baseMessage));
66
+ ? (0, telemetry_utils_1.wrapError)(err, (innerMessage) => new telemetry_utils_1.GenericError(`${baseMessage}: ${innerMessage}`))
67
+ : new telemetry_utils_1.GenericError(baseMessage));
67
68
  };
68
69
  container.on("closed", closedCallback);
69
70
  // Depending on config, transition to "connected" state may include the guarantee
@@ -71,11 +72,11 @@ async function waitContainerToCatchUp(container) {
71
72
  // Waiting for "connected" state in either case gets us at least to our own Join op
72
73
  // which is a reasonable approximation of "caught up"
73
74
  const waitForOps = () => {
74
- (0, common_utils_1.assert)(container.connectionState === connectionState_1.ConnectionState.CatchingUp ||
75
+ (0, core_utils_1.assert)(container.connectionState === connectionState_1.ConnectionState.CatchingUp ||
75
76
  container.connectionState === connectionState_1.ConnectionState.Connected, 0x0cd /* "Container disconnected while waiting for ops!" */);
76
77
  const hasCheckpointSequenceNumber = deltaManager.hasCheckpointSequenceNumber;
77
78
  const connectionOpSeqNumber = deltaManager.lastKnownSeqNumber;
78
- (0, common_utils_1.assert)(deltaManager.lastSequenceNumber <= connectionOpSeqNumber, 0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
79
+ (0, core_utils_1.assert)(deltaManager.lastSequenceNumber <= connectionOpSeqNumber, 0x266 /* "lastKnownSeqNumber should never be below last processed sequence number" */);
79
80
  if (deltaManager.lastSequenceNumber === connectionOpSeqNumber) {
80
81
  container.off("closed", closedCallback);
81
82
  resolve(hasCheckpointSequenceNumber);
@@ -163,8 +164,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
163
164
  this._dirtyContainer = false;
164
165
  this.savedOps = [];
165
166
  this.clientsWhoShouldHaveLeft = new Set();
166
- this.setAutoReconnectTime = common_utils_1.performance.now();
167
- this._lifecycleEvents = new common_utils_1.TypedEventEmitter();
167
+ this.setAutoReconnectTime = client_utils_1.performance.now();
168
+ this._lifecycleEvents = new client_utils_1.TypedEventEmitter();
168
169
  this._disposed = false;
169
170
  this.getAbsoluteUrl = async (relativeUrl) => {
170
171
  if (this.resolvedUrl === undefined) {
@@ -180,8 +181,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
180
181
  this.emit(dirty ? dirtyContainerEvent : savedContainerEvent);
181
182
  };
182
183
  const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
183
- this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = common_utils_1.performance.now();
184
+ this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = client_utils_1.performance.now();
184
185
  const pendingLocalState = loadProps?.pendingLocalState;
186
+ this._clientId = pendingLocalState?.clientId;
185
187
  this._canReconnect = canReconnect ?? true;
186
188
  this.clientDetailsOverride = clientDetailsOverride;
187
189
  this.urlResolver = urlResolver;
@@ -239,7 +241,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
239
241
  ? "null"
240
242
  : this.deltaManager?.lastMessage?.clientId,
241
243
  dmLastMsgClientSeq: () => this.deltaManager?.lastMessage?.clientSequenceNumber,
242
- connectionStateDuration: () => common_utils_1.performance.now() - this.connectionTransitionTimes[this.connectionState],
244
+ connectionStateDuration: () => client_utils_1.performance.now() - this.connectionTransitionTimes[this.connectionState],
243
245
  },
244
246
  },
245
247
  });
@@ -272,7 +274,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
272
274
  eventName,
273
275
  mode,
274
276
  category: this._lifecycleState === "loading" ? "generic" : category,
275
- duration: common_utils_1.performance.now() -
277
+ duration: client_utils_1.performance.now() -
276
278
  this.connectionTransitionTimes[connectionState_1.ConnectionState.CatchingUp],
277
279
  ...(details === undefined ? {} : { details: JSON.stringify(details) }),
278
280
  });
@@ -314,10 +316,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
314
316
  document.addEventListener !== null;
315
317
  // keep track of last time page was visible for telemetry (on interactive clients only)
316
318
  if (isDomAvailable && interactive) {
317
- this.lastVisible = document.hidden ? common_utils_1.performance.now() : undefined;
319
+ this.lastVisible = document.hidden ? client_utils_1.performance.now() : undefined;
318
320
  this.visibilityEventHandler = () => {
319
321
  if (document.hidden) {
320
- this.lastVisible = common_utils_1.performance.now();
322
+ this.lastVisible = client_utils_1.performance.now();
321
323
  }
322
324
  else {
323
325
  // settimeout so this will hopefully fire after disconnect event if being hidden caused it
@@ -346,7 +348,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
346
348
  : loadMode ?? defaultMode;
347
349
  const onClosed = (err) => {
348
350
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
349
- reject(err ?? new container_utils_1.GenericError("Container closed without error during load"));
351
+ reject(err ?? new telemetry_utils_1.GenericError("Container closed without error during load"));
350
352
  };
351
353
  container.on("closed", onClosed);
352
354
  container
@@ -362,7 +364,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
362
364
  // Depending where error happens, we can be attempting to connect to web socket
363
365
  // and continuously retrying (consider offline mode)
364
366
  // Host has no container to close, so it's prudent to do it here
367
+ // Note: We could only dispose the container instead of just close but that would
368
+ // the telemetry where users sometimes search for ContainerClose event to look
369
+ // for load failures. So not removing this at this time.
365
370
  container.close(err);
371
+ container.dispose(err);
366
372
  onClosed(err);
367
373
  });
368
374
  }), { start: true, end: true, cancel: "generic" }, disableRecordHeapSize !== true /* recordHeapSize */);
@@ -501,14 +507,14 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
501
507
  */
502
508
  async getEntryPoint() {
503
509
  if (this._disposed) {
504
- throw new container_utils_1.UsageError("The context is already disposed");
510
+ throw new telemetry_utils_1.UsageError("The context is already disposed");
505
511
  }
506
512
  if (this._runtime !== undefined) {
507
513
  return this._runtime.getEntryPoint?.();
508
514
  }
509
515
  return new Promise((resolve, reject) => {
510
516
  const runtimeInstantiatedHandler = () => {
511
- (0, common_utils_1.assert)(this._runtime !== undefined, 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */);
517
+ (0, core_utils_1.assert)(this._runtime !== undefined, 0x5a3 /* runtimeInstantiated fired but runtime is still undefined */);
512
518
  resolve(this._runtime.getEntryPoint?.());
513
519
  this._lifecycleEvents.off("disposed", disposedHandler);
514
520
  };
@@ -539,11 +545,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
539
545
  this.verifyClosed();
540
546
  }
541
547
  verifyClosed() {
542
- (0, common_utils_1.assert)(this.connectionState === connectionState_1.ConnectionState.Disconnected, 0x0cf /* "disconnect event was not raised!" */);
543
- (0, common_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
548
+ (0, core_utils_1.assert)(this.connectionState === connectionState_1.ConnectionState.Disconnected, 0x0cf /* "disconnect event was not raised!" */);
549
+ (0, core_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
544
550
  }
545
551
  closeCore(error) {
546
- (0, common_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
552
+ (0, core_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
547
553
  try {
548
554
  // Ensure that we raise all key events even if one of these throws
549
555
  try {
@@ -578,7 +584,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
578
584
  }
579
585
  }
580
586
  disposeCore(error) {
581
- (0, common_utils_1.assert)(!this._disposed, 0x54c /* Container already disposed */);
587
+ (0, core_utils_1.assert)(!this._disposed, 0x54c /* Container already disposed */);
582
588
  this._disposed = true;
583
589
  try {
584
590
  // Ensure that we raise all key events even if one of these throws
@@ -631,34 +637,41 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
631
637
  return this.getPendingLocalStateCore({ notifyImminentClosure: false });
632
638
  }
633
639
  async getPendingLocalStateCore(props) {
634
- if (!this.offlineLoadEnabled) {
635
- throw new container_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
636
- }
637
- if (this.closed || this._disposed) {
638
- throw new container_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
639
- }
640
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
641
- (0, common_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
642
- (0, common_utils_1.assert)(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
643
- (0, common_utils_1.assert)(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
644
- const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
645
- const pendingState = {
646
- pendingRuntimeState,
647
- baseSnapshot: this.baseSnapshot,
648
- snapshotBlobs: this.baseSnapshotBlobs,
649
- savedOps: this.savedOps,
650
- url: this.resolvedUrl.url,
651
- term: protocol_1.OnlyValidTermValue,
640
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
641
+ eventName: "getPendingLocalState",
642
+ notifyImminentClosure: props.notifyImminentClosure,
643
+ savedOpsSize: this.savedOps.length,
652
644
  clientId: this.clientId,
653
- };
654
- this.mc.logger.sendTelemetryEvent({ eventName: "GetPendingLocalState" });
655
- return JSON.stringify(pendingState);
645
+ }, async () => {
646
+ if (!this.offlineLoadEnabled) {
647
+ throw new telemetry_utils_1.UsageError("Can't get pending local state unless offline load is enabled");
648
+ }
649
+ if (this.closed || this._disposed) {
650
+ throw new telemetry_utils_1.UsageError("Pending state cannot be retried if the container is closed or disposed");
651
+ }
652
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x0d1 /* "Container should be attached before close" */);
653
+ (0, core_utils_1.assert)(this.resolvedUrl !== undefined && this.resolvedUrl.type === "fluid", 0x0d2 /* "resolved url should be valid Fluid url" */);
654
+ (0, core_utils_1.assert)(!!this.baseSnapshot, 0x5d4 /* no base snapshot */);
655
+ (0, core_utils_1.assert)(!!this.baseSnapshotBlobs, 0x5d5 /* no snapshot blobs */);
656
+ const pendingRuntimeState = await this.runtime.getPendingLocalState(props);
657
+ const pendingState = {
658
+ pendingRuntimeState,
659
+ baseSnapshot: this.baseSnapshot,
660
+ snapshotBlobs: this.baseSnapshotBlobs,
661
+ savedOps: this.savedOps,
662
+ url: this.resolvedUrl.url,
663
+ term: protocol_1.OnlyValidTermValue,
664
+ // no need to save this if there is no pending runtime state
665
+ clientId: pendingRuntimeState !== undefined ? this.clientId : undefined,
666
+ };
667
+ return JSON.stringify(pendingState);
668
+ });
656
669
  }
657
670
  get attachState() {
658
671
  return this._attachState;
659
672
  }
660
673
  serialize() {
661
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
674
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Detached, 0x0d3 /* "Should only be called in detached container" */);
662
675
  const appSummary = this.runtime.createSummary();
663
676
  const protocolSummary = this.captureProtocolSummary();
664
677
  const combinedSummary = (0, utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
@@ -670,19 +683,19 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
670
683
  }
671
684
  return JSON.stringify(combinedSummary);
672
685
  }
673
- async attach(request) {
686
+ async attach(request, attachProps) {
674
687
  await telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
675
688
  if (this._lifecycleState !== "loaded") {
676
689
  // pre-0.58 error message: containerNotValidForAttach
677
- throw new container_utils_1.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
690
+ throw new telemetry_utils_1.UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
678
691
  }
679
692
  // If container is already attached or attach is in progress, throw an error.
680
- (0, common_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
693
+ (0, core_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
681
694
  this.attachStarted = true;
682
695
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
683
696
  const hasAttachmentBlobs = this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0;
684
697
  try {
685
- (0, common_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
698
+ (0, core_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
686
699
  let summary;
687
700
  if (!hasAttachmentBlobs) {
688
701
  // Get the document state post attach - possibly can just call attach but we need to change the
@@ -707,7 +720,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
707
720
  // Actually go and create the resolved document
708
721
  if (this.service === undefined) {
709
722
  const createNewResolvedUrl = await this.urlResolver.resolve(request);
710
- (0, common_utils_1.assert)(this.client.details.type !== summarizerClientType &&
723
+ (0, core_utils_1.assert)(this.client.details.type !== summarizerClientType &&
711
724
  createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
712
725
  this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
713
726
  cancel: this._deltaManager.closeAbortController.signal,
@@ -716,7 +729,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
716
729
  await this.storageAdapter.connectToService(this.service);
717
730
  if (hasAttachmentBlobs) {
718
731
  // upload blobs to storage
719
- (0, common_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
732
+ (0, core_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
720
733
  // build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
721
734
  // support blob handles that only know about the local IDs
722
735
  const redirectTable = new Map();
@@ -754,10 +767,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
754
767
  this.runtime.setAttachState(container_definitions_1.AttachState.Attached);
755
768
  this.emit("attached");
756
769
  if (!this.closed) {
757
- this.resumeInternal({
770
+ this.handleDeltaConnectionArg({
758
771
  fetchOpsFromStorage: false,
759
772
  reason: { text: "createDetached" },
760
- });
773
+ }, attachProps?.deltaConnection);
761
774
  }
762
775
  }
763
776
  catch (error) {
@@ -777,7 +790,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
777
790
  if (currentMode === mode) {
778
791
  return;
779
792
  }
780
- const now = common_utils_1.performance.now();
793
+ const now = client_utils_1.performance.now();
781
794
  const duration = now - this.setAutoReconnectTime;
782
795
  this.setAutoReconnectTime = now;
783
796
  this.mc.logger.sendTelemetryEvent({
@@ -790,10 +803,10 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
790
803
  }
791
804
  connect() {
792
805
  if (this.closed) {
793
- throw new container_utils_1.UsageError(`The Container is closed and cannot be connected`);
806
+ throw new telemetry_utils_1.UsageError(`The Container is closed and cannot be connected`);
794
807
  }
795
808
  else if (this._attachState !== container_definitions_1.AttachState.Attached) {
796
- throw new container_utils_1.UsageError(`The Container is not attached and cannot be connected`);
809
+ throw new telemetry_utils_1.UsageError(`The Container is not attached and cannot be connected`);
797
810
  }
798
811
  else if (!this.connected) {
799
812
  // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler().
@@ -806,8 +819,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
806
819
  }
807
820
  }
808
821
  connectInternal(args) {
809
- (0, common_utils_1.assert)(!this.closed, 0x2c5 /* "Attempting to connect() a closed Container" */);
810
- (0, common_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
822
+ (0, core_utils_1.assert)(!this.closed, 0x2c5 /* "Attempting to connect() a closed Container" */);
823
+ (0, core_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Attached, 0x2c6 /* "Attempting to connect() a container that is not attached" */);
811
824
  // Resume processing ops and connect to delta stream
812
825
  this.resumeInternal(args);
813
826
  // Set Auto Reconnect Mode
@@ -816,20 +829,20 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
816
829
  }
817
830
  disconnect() {
818
831
  if (this.closed) {
819
- throw new container_utils_1.UsageError(`The Container is closed and cannot be disconnected`);
832
+ throw new telemetry_utils_1.UsageError(`The Container is closed and cannot be disconnected`);
820
833
  }
821
834
  else {
822
835
  this.disconnectInternal({ text: "DocumentDisconnect" });
823
836
  }
824
837
  }
825
838
  disconnectInternal(reason) {
826
- (0, common_utils_1.assert)(!this.closed, 0x2c7 /* "Attempting to disconnect() a closed Container" */);
839
+ (0, core_utils_1.assert)(!this.closed, 0x2c7 /* "Attempting to disconnect() a closed Container" */);
827
840
  // Set Auto Reconnect Mode
828
841
  const mode = contracts_1.ReconnectMode.Disabled;
829
842
  this.setAutoReconnectInternal(mode, reason);
830
843
  }
831
844
  resumeInternal(args) {
832
- (0, common_utils_1.assert)(!this.closed, 0x0d9 /* "Attempting to connect() a closed DeltaManager" */);
845
+ (0, core_utils_1.assert)(!this.closed, 0x0d9 /* "Attempting to connect() a closed DeltaManager" */);
833
846
  // Resume processing ops
834
847
  if (this.inboundQueuePausedFromInit) {
835
848
  this.inboundQueuePausedFromInit = false;
@@ -866,7 +879,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
866
879
  return;
867
880
  }
868
881
  // pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
869
- const error = new container_utils_1.GenericError("Existing context does not satisfy incoming proposal");
882
+ const error = new telemetry_utils_1.GenericError("Existing context does not satisfy incoming proposal");
870
883
  this.close(error);
871
884
  }
872
885
  /**
@@ -917,6 +930,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
917
930
  * @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
918
931
  */
919
932
  async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState, loadToSequenceNumber) {
933
+ const timings = { phase1: client_utils_1.performance.now() };
920
934
  this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
921
935
  // Ideally we always connect as "read" by default.
922
936
  // Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
@@ -947,6 +961,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
947
961
  });
948
962
  }
949
963
  this._attachState = container_definitions_1.AttachState.Attached;
964
+ timings.phase2 = client_utils_1.performance.now();
950
965
  // Fetch specified snapshot.
951
966
  const { snapshot, versionId } = pendingLocalState === undefined
952
967
  ? await this.fetchSnapshotTree(specifiedVersion)
@@ -956,7 +971,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
956
971
  this.baseSnapshotBlobs = pendingLocalState.snapshotBlobs;
957
972
  }
958
973
  else {
959
- (0, common_utils_1.assert)(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
974
+ (0, core_utils_1.assert)(snapshot !== undefined, 0x237 /* "Snapshot should exist" */);
960
975
  if (this.offlineLoadEnabled) {
961
976
  this.baseSnapshot = snapshot;
962
977
  // Save contents of snapshot now, otherwise closeAndGetPendingLocalState() must be async
@@ -971,7 +986,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
971
986
  if (loadMode.pauseAfterLoad === true) {
972
987
  // If we are trying to pause at a specific sequence number, ensure the latest snapshot is not newer than the desired sequence number.
973
988
  if (loadMode.opsBeforeReturn === "sequenceNumber") {
974
- (0, common_utils_1.assert)(loadToSequenceNumber !== undefined, 0x727 /* sequenceNumber should be defined */);
989
+ (0, core_utils_1.assert)(loadToSequenceNumber !== undefined, 0x727 /* sequenceNumber should be defined */);
975
990
  // Note: It is possible that we think the latest snapshot is newer than the specified sequence number
976
991
  // due to saved ops that may be replayed after the snapshot.
977
992
  // https://dev.azure.com/fluidframework/internal/_workitems/edit/5055
@@ -1019,22 +1034,21 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1019
1034
  this.attachDeltaManagerOpHandler(dmAttributes, loadMode.deltaConnection !== "none" ? "all" : "none");
1020
1035
  break;
1021
1036
  case "sequenceNumber":
1022
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "sequenceNumber");
1023
- break;
1024
1037
  case "cached":
1025
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "cached");
1026
- break;
1027
1038
  case "all":
1028
- opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, "all");
1039
+ opsBeforeReturnP = this.attachDeltaManagerOpHandler(dmAttributes, loadMode.opsBeforeReturn);
1029
1040
  break;
1030
1041
  default:
1031
- (0, common_utils_1.unreachableCase)(loadMode.opsBeforeReturn);
1042
+ (0, core_utils_1.unreachableCase)(loadMode.opsBeforeReturn);
1032
1043
  }
1033
1044
  // ...load in the existing quorum
1034
1045
  // Initialize the protocol handler
1035
1046
  await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
1047
+ timings.phase3 = client_utils_1.performance.now();
1036
1048
  const codeDetails = this.getCodeDetailsFromQuorum();
1037
- await this.instantiateRuntime(codeDetails, snapshot, pendingLocalState?.pendingRuntimeState);
1049
+ await this.instantiateRuntime(codeDetails, snapshot,
1050
+ // give runtime a dummy value so it knows we're loading from a stash blob
1051
+ pendingLocalState ? pendingLocalState?.pendingRuntimeState ?? {} : undefined);
1038
1052
  // replay saved ops
1039
1053
  if (pendingLocalState) {
1040
1054
  for (const message of pendingLocalState.savedOps) {
@@ -1043,9 +1057,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1043
1057
  await this.runtime.notifyOpReplay?.(message);
1044
1058
  }
1045
1059
  pendingLocalState.savedOps = [];
1046
- // now set clientId to stashed clientId so live ops are correctly processed as local
1047
- (0, common_utils_1.assert)(this.clientId === undefined, 0x5d6 /* Unexpected clientId when setting stashed clientId */);
1048
- this._clientId = pendingLocalState?.clientId;
1049
1060
  }
1050
1061
  // We might have hit some failure that did not manifest itself in exception in this flow,
1051
1062
  // do not start op processing in such case - static version of Container.load() will handle it correctly.
@@ -1057,24 +1068,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1057
1068
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1058
1069
  this._deltaManager.inbound.pause();
1059
1070
  }
1060
- switch (loadMode.deltaConnection) {
1061
- case undefined:
1062
- if (pendingLocalState) {
1063
- // connect to delta stream now since we did not before
1064
- this.connectToDeltaStream(connectionArgs);
1065
- }
1066
- // intentional fallthrough
1067
- case "delayed":
1068
- (0, common_utils_1.assert)(this.inboundQueuePausedFromInit, 0x346 /* inboundQueuePausedFromInit should be true */);
1069
- this.inboundQueuePausedFromInit = false;
1070
- this._deltaManager.inbound.resume();
1071
- this._deltaManager.inboundSignal.resume();
1072
- break;
1073
- case "none":
1074
- break;
1075
- default:
1076
- (0, common_utils_1.unreachableCase)(loadMode.deltaConnection);
1077
- }
1071
+ this.handleDeltaConnectionArg(connectionArgs, loadMode.deltaConnection, pendingLocalState !== undefined);
1078
1072
  }
1079
1073
  // If we have not yet reached `loadToSequenceNumber`, we will wait for ops to arrive until we reach it
1080
1074
  if (loadToSequenceNumber !== undefined &&
@@ -1099,6 +1093,11 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1099
1093
  }
1100
1094
  // Internal context is fully loaded at this point
1101
1095
  this.setLoaded();
1096
+ timings.end = client_utils_1.performance.now();
1097
+ this.subLogger.sendTelemetryEvent({
1098
+ eventName: "LoadStagesTimings",
1099
+ details: JSON.stringify(timings),
1100
+ }, undefined, core_interfaces_1.LogLevel.verbose);
1102
1101
  return {
1103
1102
  sequenceNumber: attributes.sequenceNumber,
1104
1103
  version: versionId,
@@ -1125,7 +1124,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1125
1124
  }
1126
1125
  async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
1127
1126
  if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
1128
- (0, common_utils_1.assert)(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1127
+ (0, core_utils_1.assert)(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1129
1128
  delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
1130
1129
  }
1131
1130
  const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
@@ -1281,7 +1280,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1281
1280
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1282
1281
  deltaManager.inboundSignal.pause();
1283
1282
  deltaManager.on("connect", (details, _opsBehind) => {
1284
- (0, common_utils_1.assert)(this.connectionMode === details.mode, 0x4b7 /* mismatch */);
1283
+ (0, core_utils_1.assert)(this.connectionMode === details.mode, 0x4b7 /* mismatch */);
1285
1284
  this.connectionStateHandler.receivedConnectEvent(details);
1286
1285
  });
1287
1286
  deltaManager.on("establishingConnection", (reason) => {
@@ -1327,7 +1326,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1327
1326
  }
1328
1327
  logConnectionStateChangeTelemetry(value, oldState, reason) {
1329
1328
  // Log actual event
1330
- const time = common_utils_1.performance.now();
1329
+ const time = client_utils_1.performance.now();
1331
1330
  this.connectionTransitionTimes[value] = time;
1332
1331
  const duration = time - this.connectionTransitionTimes[oldState];
1333
1332
  let durationFromDisconnected;
@@ -1368,7 +1367,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1368
1367
  opsBehind,
1369
1368
  online: driver_utils_1.OnlineStatus[(0, driver_utils_1.isOnline)()],
1370
1369
  lastVisible: this.lastVisible !== undefined
1371
- ? common_utils_1.performance.now() - this.lastVisible
1370
+ ? client_utils_1.performance.now() - this.lastVisible
1372
1371
  : undefined,
1373
1372
  checkpointSequenceNumber,
1374
1373
  quorumSize: this._protocolHandler?.quorum.getMembers().size,
@@ -1402,7 +1401,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1402
1401
  case protocol_definitions_1.MessageType.Summarize:
1403
1402
  return this.submitSummaryMessage(contents);
1404
1403
  default: {
1405
- const newError = new container_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type });
1404
+ const newError = new telemetry_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type });
1406
1405
  this.close(newError);
1407
1406
  return -1;
1408
1407
  }
@@ -1454,13 +1453,13 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1454
1453
  // That means that if relay service changes settings, such changes will impact only newly booted
1455
1454
  // clients.
1456
1455
  // All existing will continue to use settings they got earlier.
1457
- (0, common_utils_1.assert)(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
1456
+ (0, core_utils_1.assert)(serviceConfiguration !== undefined, 0x2e4 /* "there should be service config for active connection" */);
1458
1457
  this.noopHeuristic = new noopHeuristic_1.NoopHeuristic(serviceConfiguration.noopTimeFrequency, serviceConfiguration.noopCountFrequency);
1459
1458
  this.noopHeuristic.on("wantsNoop", () => {
1460
1459
  // On disconnect we notify the heuristic which should prevent it from wanting a noop.
1461
1460
  // Hitting this assert would imply we lost activeConnection between notifying the heuristic of a processed message and
1462
1461
  // running the microtask that the heuristic queued in response.
1463
- (0, common_utils_1.assert)(this.activeConnection(), 0x241 /* "Trying to send noop without active connection" */);
1462
+ (0, core_utils_1.assert)(this.activeConnection(), 0x241 /* "Trying to send noop without active connection" */);
1464
1463
  this.submitMessage(protocol_definitions_1.MessageType.NoOp);
1465
1464
  });
1466
1465
  }
@@ -1508,7 +1507,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1508
1507
  return { snapshot, versionId: version?.id };
1509
1508
  }
1510
1509
  async instantiateRuntime(codeDetails, snapshot, pendingLocalState) {
1511
- (0, common_utils_1.assert)(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
1510
+ (0, core_utils_1.assert)(this._runtime?.disposed !== false, 0x0dd /* "Existing runtime not disposed" */);
1512
1511
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1513
1512
  // are set. Global requests will still go directly to the loader
1514
1513
  const maybeLoader = this.scope;
@@ -1551,6 +1550,26 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1551
1550
  this.runtime.setConnectionState(state && !readonly, this.clientId);
1552
1551
  }
1553
1552
  }
1553
+ handleDeltaConnectionArg(connectionArgs, deltaConnectionArg, canConnect = true) {
1554
+ switch (deltaConnectionArg) {
1555
+ case undefined:
1556
+ if (canConnect) {
1557
+ // connect to delta stream now since we did not before
1558
+ this.connectToDeltaStream(connectionArgs);
1559
+ }
1560
+ // intentional fallthrough
1561
+ case "delayed":
1562
+ (0, core_utils_1.assert)(this.inboundQueuePausedFromInit, 0x346 /* inboundQueuePausedFromInit should be true */);
1563
+ this.inboundQueuePausedFromInit = false;
1564
+ this._deltaManager.inbound.resume();
1565
+ this._deltaManager.inboundSignal.resume();
1566
+ break;
1567
+ case "none":
1568
+ break;
1569
+ default:
1570
+ (0, core_utils_1.unreachableCase)(deltaConnectionArg);
1571
+ }
1572
+ }
1554
1573
  }
1555
1574
  exports.Container = Container;
1556
1575
  //# sourceMappingURL=container.js.map