@fluidframework/container-loader 2.0.0-dev.4.4.0.162574 → 2.0.0-dev.5.2.0.169897

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 (114) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +27 -3
  3. package/dist/connectionManager.d.ts +3 -2
  4. package/dist/connectionManager.d.ts.map +1 -1
  5. package/dist/connectionManager.js +32 -13
  6. package/dist/connectionManager.js.map +1 -1
  7. package/dist/connectionStateHandler.d.ts +15 -3
  8. package/dist/connectionStateHandler.d.ts.map +1 -1
  9. package/dist/connectionStateHandler.js +24 -1
  10. package/dist/connectionStateHandler.js.map +1 -1
  11. package/dist/container.d.ts +74 -44
  12. package/dist/container.d.ts.map +1 -1
  13. package/dist/container.js +81 -111
  14. package/dist/container.js.map +1 -1
  15. package/dist/containerContext.d.ts +2 -2
  16. package/dist/containerContext.d.ts.map +1 -1
  17. package/dist/containerContext.js +3 -7
  18. package/dist/containerContext.js.map +1 -1
  19. package/dist/containerStorageAdapter.d.ts +3 -3
  20. package/dist/containerStorageAdapter.d.ts.map +1 -1
  21. package/dist/containerStorageAdapter.js +6 -15
  22. package/dist/containerStorageAdapter.js.map +1 -1
  23. package/dist/contracts.d.ts +8 -0
  24. package/dist/contracts.d.ts.map +1 -1
  25. package/dist/contracts.js.map +1 -1
  26. package/dist/deltaManager.d.ts +21 -9
  27. package/dist/deltaManager.d.ts.map +1 -1
  28. package/dist/deltaManager.js +42 -31
  29. package/dist/deltaManager.js.map +1 -1
  30. package/dist/deltaQueue.d.ts +2 -3
  31. package/dist/deltaQueue.d.ts.map +1 -1
  32. package/dist/deltaQueue.js +2 -3
  33. package/dist/deltaQueue.js.map +1 -1
  34. package/dist/index.d.ts +1 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/loader.d.ts +9 -7
  38. package/dist/loader.d.ts.map +1 -1
  39. package/dist/loader.js +47 -61
  40. package/dist/loader.js.map +1 -1
  41. package/dist/packageVersion.d.ts +1 -1
  42. package/dist/packageVersion.js +1 -1
  43. package/dist/packageVersion.js.map +1 -1
  44. package/dist/retriableDocumentStorageService.d.ts +3 -2
  45. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  46. package/dist/retriableDocumentStorageService.js.map +1 -1
  47. package/dist/tsdoc-metadata.json +11 -0
  48. package/dist/utils.d.ts +2 -0
  49. package/dist/utils.d.ts.map +1 -1
  50. package/dist/utils.js +8 -1
  51. package/dist/utils.js.map +1 -1
  52. package/lib/connectionManager.d.ts +3 -2
  53. package/lib/connectionManager.d.ts.map +1 -1
  54. package/lib/connectionManager.js +33 -14
  55. package/lib/connectionManager.js.map +1 -1
  56. package/lib/connectionStateHandler.d.ts +15 -3
  57. package/lib/connectionStateHandler.d.ts.map +1 -1
  58. package/lib/connectionStateHandler.js +25 -2
  59. package/lib/connectionStateHandler.js.map +1 -1
  60. package/lib/container.d.ts +74 -44
  61. package/lib/container.d.ts.map +1 -1
  62. package/lib/container.js +82 -112
  63. package/lib/container.js.map +1 -1
  64. package/lib/containerContext.d.ts +2 -2
  65. package/lib/containerContext.d.ts.map +1 -1
  66. package/lib/containerContext.js +3 -7
  67. package/lib/containerContext.js.map +1 -1
  68. package/lib/containerStorageAdapter.d.ts +3 -3
  69. package/lib/containerStorageAdapter.d.ts.map +1 -1
  70. package/lib/containerStorageAdapter.js +6 -15
  71. package/lib/containerStorageAdapter.js.map +1 -1
  72. package/lib/contracts.d.ts +8 -0
  73. package/lib/contracts.d.ts.map +1 -1
  74. package/lib/contracts.js.map +1 -1
  75. package/lib/deltaManager.d.ts +21 -9
  76. package/lib/deltaManager.d.ts.map +1 -1
  77. package/lib/deltaManager.js +44 -33
  78. package/lib/deltaManager.js.map +1 -1
  79. package/lib/deltaQueue.d.ts +2 -3
  80. package/lib/deltaQueue.d.ts.map +1 -1
  81. package/lib/deltaQueue.js +2 -3
  82. package/lib/deltaQueue.js.map +1 -1
  83. package/lib/index.d.ts +1 -2
  84. package/lib/index.d.ts.map +1 -1
  85. package/lib/index.js +1 -1
  86. package/lib/index.js.map +1 -1
  87. package/lib/loader.d.ts +9 -7
  88. package/lib/loader.d.ts.map +1 -1
  89. package/lib/loader.js +47 -61
  90. package/lib/loader.js.map +1 -1
  91. package/lib/packageVersion.d.ts +1 -1
  92. package/lib/packageVersion.js +1 -1
  93. package/lib/packageVersion.js.map +1 -1
  94. package/lib/retriableDocumentStorageService.d.ts +3 -2
  95. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  96. package/lib/retriableDocumentStorageService.js.map +1 -1
  97. package/lib/utils.d.ts +2 -0
  98. package/lib/utils.d.ts.map +1 -1
  99. package/lib/utils.js +7 -1
  100. package/lib/utils.js.map +1 -1
  101. package/package.json +16 -18
  102. package/src/connectionManager.ts +40 -22
  103. package/src/connectionStateHandler.ts +52 -8
  104. package/src/container.ts +191 -159
  105. package/src/containerContext.ts +3 -9
  106. package/src/containerStorageAdapter.ts +8 -20
  107. package/src/contracts.ts +10 -0
  108. package/src/deltaManager.ts +59 -37
  109. package/src/deltaQueue.ts +2 -3
  110. package/src/index.ts +1 -8
  111. package/src/loader.ts +85 -83
  112. package/src/packageVersion.ts +1 -1
  113. package/src/retriableDocumentStorageService.ts +3 -2
  114. package/src/utils.ts +15 -1
package/dist/container.js CHANGED
@@ -127,26 +127,18 @@ async function ReportIfTooLong(logger, eventName, action) {
127
127
  }
128
128
  exports.ReportIfTooLong = ReportIfTooLong;
129
129
  const summarizerClientType = "summarizer";
130
- /**
131
- * @deprecated - In the next release Container will no longer be exported, IContainer should be used in its place.
132
- */
133
130
  class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
134
131
  /**
135
132
  * @internal
136
133
  */
137
- constructor(loader, config, protocolHandlerBuilder) {
138
- var _a, _b, _c;
134
+ constructor(createProps, loadProps) {
135
+ var _a;
139
136
  super((name, error) => {
140
137
  this.mc.logger.sendErrorEvent({
141
138
  eventName: "ContainerEventHandlerException",
142
139
  name: typeof name === "string" ? name : undefined,
143
140
  }, error);
144
141
  });
145
- this.loader = loader;
146
- this.protocolHandlerBuilder = protocolHandlerBuilder;
147
- // Tells if container can reconnect on losing fist connection
148
- // If false, container gets closed on loss of connection.
149
- this._canReconnect = true;
150
142
  /**
151
143
  * Lifecycle state of the container, used mainly to prevent re-entrancy and telemetry
152
144
  *
@@ -174,26 +166,41 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
174
166
  this.savedOps = [];
175
167
  this.setAutoReconnectTime = common_utils_1.performance.now();
176
168
  this._disposed = false;
177
- this.clientDetailsOverride = config.clientDetailsOverride;
178
- this._resolvedUrl = config.resolvedUrl;
179
- if (config.canReconnect !== undefined) {
180
- this._canReconnect = config.canReconnect;
181
- }
169
+ const { canReconnect, clientDetailsOverride, urlResolver, documentServiceFactory, codeLoader, options, scope, subLogger, detachedBlobStorage, protocolHandlerBuilder, } = createProps;
170
+ this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = common_utils_1.performance.now();
171
+ const pendingLocalState = loadProps === null || loadProps === void 0 ? void 0 : loadProps.pendingLocalState;
172
+ this._canReconnect = canReconnect !== null && canReconnect !== void 0 ? canReconnect : true;
173
+ this.clientDetailsOverride = clientDetailsOverride;
174
+ this.urlResolver = urlResolver;
175
+ this.serviceFactory = documentServiceFactory;
176
+ this.codeLoader = codeLoader;
177
+ // Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
178
+ // all clients that were loaded from the same loader (including summarizer clients).
179
+ // Tracking alternative ways to handle this in AB#4129.
180
+ this.options = Object.assign({}, options);
181
+ this.scope = scope;
182
+ this.detachedBlobStorage = detachedBlobStorage;
183
+ this.protocolHandlerBuilder =
184
+ protocolHandlerBuilder !== null && protocolHandlerBuilder !== void 0 ? protocolHandlerBuilder : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
185
+ // Note that we capture the createProps here so we can replicate the creation call when we want to clone.
186
+ this.clone = async (_loadProps, createParamOverrides) => {
187
+ return Container.load(_loadProps, Object.assign(Object.assign({}, createProps), createParamOverrides));
188
+ };
182
189
  // Create logger for data stores to use
183
190
  const type = this.client.details.type;
184
191
  const interactive = this.client.details.capabilities.interactive;
185
192
  const clientType = `${interactive ? "interactive" : "noninteractive"}${type !== undefined && type !== "" ? `/${type}` : ""}`;
186
193
  // Need to use the property getter for docId because for detached flow we don't have the docId initially.
187
194
  // We assign the id later so property getter is used.
188
- this.subLogger = telemetry_utils_1.ChildLogger.create(loader.services.subLogger, undefined, {
195
+ this.subLogger = telemetry_utils_1.ChildLogger.create(subLogger, undefined, {
189
196
  all: {
190
197
  clientType,
191
198
  containerId: (0, uuid_1.v4)(),
192
- docId: () => { var _a, _b; return (_b = (_a = this._resolvedUrl) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : undefined; },
199
+ docId: () => { var _a; return (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.id; },
193
200
  containerAttachState: () => this._attachState,
194
201
  containerLifecycleState: () => this._lifecycleState,
195
202
  containerConnectionState: () => connectionState_1.ConnectionState[this.connectionState],
196
- serializedContainer: config.serializedContainerState !== undefined,
203
+ serializedContainer: pendingLocalState !== undefined,
197
204
  },
198
205
  // we need to be judicious with our logging here to avoid generating too much data
199
206
  // all data logged here should be broadly applicable, and not specific to a
@@ -216,10 +223,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
216
223
  });
217
224
  // Prefix all events in this file with container-loader
218
225
  this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(this.subLogger, "Container"));
219
- // Warning: this is only a shallow clone. Mutation of any individual loader option will mutate it for
220
- // all clients that were loaded from the same loader (including summarizer clients).
221
- // Tracking alternative ways to handle this in AB#4129.
222
- this.options = Object.assign({}, this.loader.services.options);
223
226
  this._deltaManager = this.createDeltaManager();
224
227
  this.connectionStateHandler = (0, connectionStateHandler_1.createConnectionStateHandler)({
225
228
  logger: this.mc.logger,
@@ -235,7 +238,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
235
238
  }
236
239
  },
237
240
  shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
238
- maxClientLeaveWaitTime: this.loader.services.options.maxClientLeaveWaitTime,
241
+ maxClientLeaveWaitTime: options.maxClientLeaveWaitTime,
239
242
  logConnectionIssue: (eventName, category, details) => {
240
243
  const mode = this.connectionMode;
241
244
  // We get here when socket does not receive any ops on "write" connection, including
@@ -259,7 +262,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
259
262
  this.connect();
260
263
  }
261
264
  },
262
- }, this.deltaManager, (_a = config.serializedContainerState) === null || _a === void 0 ? void 0 : _a.clientId);
265
+ }, this.deltaManager, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.clientId);
263
266
  this.on(savedContainerEvent, () => {
264
267
  this.connectionStateHandler.containerSaved();
265
268
  });
@@ -271,8 +274,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
271
274
  : (0, driver_utils_1.combineAppAndProtocolSummary)(summaryTree, this.captureProtocolSummary());
272
275
  // Whether the combined summary tree has been forced on by either the loader option or the monitoring context.
273
276
  // Even if not forced on via this flag, combined summaries may still be enabled by service policy.
274
- const forceEnableSummarizeProtocolTree = (_b = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _b !== void 0 ? _b : this.loader.services.options.summarizeProtocolTree;
275
- this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(this.loader.services.detachedBlobStorage, this.mc.logger, (_c = config.serializedContainerState) === null || _c === void 0 ? void 0 : _c.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
277
+ const forceEnableSummarizeProtocolTree = (_a = this.mc.config.getBoolean("Fluid.Container.summarizeProtocolTree2")) !== null && _a !== void 0 ? _a : options.summarizeProtocolTree;
278
+ this.storageAdapter = new containerStorageAdapter_1.ContainerStorageAdapter(detachedBlobStorage, this.mc.logger, pendingLocalState === null || pendingLocalState === void 0 ? void 0 : pendingLocalState.snapshotBlobs, addProtocolSummaryIfMissing, forceEnableSummarizeProtocolTree);
276
279
  const isDomAvailable = typeof document === "object" &&
277
280
  document !== null &&
278
281
  typeof document.addEventListener === "function" &&
@@ -298,33 +301,28 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
298
301
  * Load an existing container.
299
302
  * @internal
300
303
  */
301
- static async load(loader, loadOptions, pendingLocalState, protocolHandlerBuilder) {
302
- const container = new Container(loader, {
303
- clientDetailsOverride: loadOptions.clientDetailsOverride,
304
- resolvedUrl: loadOptions.resolvedUrl,
305
- canReconnect: loadOptions.canReconnect,
306
- serializedContainerState: pendingLocalState,
307
- }, protocolHandlerBuilder);
304
+ static async load(loadProps, createProps) {
305
+ const { version, pendingLocalState, loadMode, resolvedUrl } = loadProps;
306
+ const container = new Container(createProps, loadProps);
307
+ const disableRecordHeapSize = container.mc.config.getBoolean("Fluid.Loader.DisableRecordHeapSize");
308
308
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "Load" }, async (event) => new Promise((resolve, reject) => {
309
- var _a, _b;
310
- const version = loadOptions.version;
311
309
  const defaultMode = { opsBeforeReturn: "cached" };
312
310
  // if we have pendingLocalState, anything we cached is not useful and we shouldn't wait for connection
313
311
  // to return container, so ignore this value and use undefined for opsBeforeReturn
314
312
  const mode = pendingLocalState
315
- ? Object.assign(Object.assign({}, ((_a = loadOptions.loadMode) !== null && _a !== void 0 ? _a : defaultMode)), { opsBeforeReturn: undefined }) : (_b = loadOptions.loadMode) !== null && _b !== void 0 ? _b : defaultMode;
313
+ ? Object.assign(Object.assign({}, (loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode)), { opsBeforeReturn: undefined }) : loadMode !== null && loadMode !== void 0 ? loadMode : defaultMode;
316
314
  const onClosed = (err) => {
317
315
  // pre-0.58 error message: containerClosedWithoutErrorDuringLoad
318
316
  reject(err !== null && err !== void 0 ? err : new container_utils_1.GenericError("Container closed without error during load"));
319
317
  };
320
318
  container.on("closed", onClosed);
321
319
  container
322
- .load(version, mode, pendingLocalState)
320
+ .load(version, mode, resolvedUrl, pendingLocalState)
323
321
  .finally(() => {
324
322
  container.removeListener("closed", onClosed);
325
323
  })
326
324
  .then((props) => {
327
- event.end(Object.assign(Object.assign({}, props), loadOptions.loadMode));
325
+ event.end(Object.assign(Object.assign({}, props), loadMode));
328
326
  resolve(container);
329
327
  }, (error) => {
330
328
  const err = (0, telemetry_utils_1.normalizeError)(error);
@@ -334,13 +332,13 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
334
332
  container.close(err);
335
333
  onClosed(err);
336
334
  });
337
- }), { start: true, end: true, cancel: "generic" });
335
+ }), { start: true, end: true, cancel: "generic" }, disableRecordHeapSize !== true /* recordHeapSize */);
338
336
  }
339
337
  /**
340
338
  * Create a new container in a detached state.
341
339
  */
342
- static async createDetached(loader, codeDetails, protocolHandlerBuilder) {
343
- const container = new Container(loader, {}, protocolHandlerBuilder);
340
+ static async createDetached(createProps, codeDetails) {
341
+ const container = new Container(createProps);
344
342
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "CreateDetached" }, async (_event) => {
345
343
  await container.createDetached(codeDetails);
346
344
  return container;
@@ -350,8 +348,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
350
348
  * Create a new container in a detached state that is initialized with a
351
349
  * snapshot from a previous detached container.
352
350
  */
353
- static async rehydrateDetachedFromSnapshot(loader, snapshot, protocolHandlerBuilder) {
354
- const container = new Container(loader, {}, protocolHandlerBuilder);
351
+ static async rehydrateDetachedFromSnapshot(createProps, snapshot) {
352
+ const container = new Container(createProps);
355
353
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(container.mc.logger, { eventName: "RehydrateDetachedFromSnapshot" }, async (_event) => {
356
354
  const deserializedSummary = JSON.parse(snapshot);
357
355
  await container.rehydrateDetachedFromSnapshot(deserializedSummary);
@@ -395,7 +393,19 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
395
393
  return this;
396
394
  }
397
395
  get resolvedUrl() {
398
- return this._resolvedUrl;
396
+ var _a;
397
+ /**
398
+ * All attached containers will have a document service,
399
+ * this is required, as attached containers are attached to
400
+ * a service. Detached containers will neither have a document
401
+ * service or a resolved url as they only exist locally.
402
+ * in order to create a document service a resolved url must
403
+ * first be obtained, this is how the container is identified.
404
+ * Because of this, the document service's resolved url
405
+ * is always the same as the containers, as we had to
406
+ * obtain the resolved url, and then create the service from it.
407
+ */
408
+ return (_a = this.service) === null || _a === void 0 ? void 0 : _a.resolvedUrl;
399
409
  }
400
410
  get loadedFromVersion() {
401
411
  return this._loadedFromVersion;
@@ -481,18 +491,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
481
491
  get isDirty() {
482
492
  return this._dirtyContainer;
483
493
  }
484
- get serviceFactory() {
485
- return this.loader.services.documentServiceFactory;
486
- }
487
- get urlResolver() {
488
- return this.loader.services.urlResolver;
489
- }
490
- get scope() {
491
- return this.loader.services.scope;
492
- }
493
- get codeLoader() {
494
- return this.loader.services.codeLoader;
495
- }
496
494
  /**
497
495
  * {@inheritDoc @fluidframework/container-definitions#IContainer.entryPoint}
498
496
  */
@@ -532,7 +530,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
532
530
  return this.protocolHandler.quorum;
533
531
  }
534
532
  dispose(error) {
535
- this._deltaManager.close(error, true /* doDispose */);
533
+ this._deltaManager.dispose(error);
536
534
  this.verifyClosed();
537
535
  }
538
536
  close(error) {
@@ -548,7 +546,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
548
546
  (0, common_utils_1.assert)(this._lifecycleState === "closed" || this._lifecycleState === "disposed", 0x314 /* Container properly closed */);
549
547
  }
550
548
  closeCore(error) {
551
- var _a, _b, _c;
549
+ var _a;
552
550
  (0, common_utils_1.assert)(!this.closed, 0x315 /* re-entrancy */);
553
551
  try {
554
552
  // Ensure that we raise all key events even if one of these throws
@@ -566,12 +564,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
566
564
  this._lifecycleState = "closing";
567
565
  (_a = this._protocolHandler) === null || _a === void 0 ? void 0 : _a.close();
568
566
  this.connectionStateHandler.dispose();
569
- (_b = this._context) === null || _b === void 0 ? void 0 : _b.dispose(error !== undefined ? new Error(error.message) : undefined);
570
- this.storageAdapter.dispose();
571
- // Notify storage about critical errors. They may be due to disconnect between client & server knowledge
572
- // about file, like file being overwritten in storage, but client having stale local cache.
573
- // Driver need to ensure all caches are cleared on critical errors
574
- (_c = this.service) === null || _c === void 0 ? void 0 : _c.dispose(error);
575
567
  }
576
568
  catch (exception) {
577
569
  this.mc.logger.sendErrorEvent({ eventName: "ContainerCloseException" }, exception);
@@ -660,8 +652,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
660
652
  const appSummary = this.context.createSummary();
661
653
  const protocolSummary = this.captureProtocolSummary();
662
654
  const combinedSummary = (0, driver_utils_1.combineAppAndProtocolSummary)(appSummary, protocolSummary);
663
- if (this.loader.services.detachedBlobStorage &&
664
- this.loader.services.detachedBlobStorage.size > 0) {
655
+ if (this.detachedBlobStorage && this.detachedBlobStorage.size > 0) {
665
656
  combinedSummary.tree[".hasAttachmentBlobs"] = {
666
657
  type: protocol_definitions_1.SummaryType.Blob,
667
658
  content: "true",
@@ -680,8 +671,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
680
671
  (0, common_utils_1.assert)(this._attachState === container_definitions_1.AttachState.Detached && !this.attachStarted, 0x205 /* "attach() called more than once" */);
681
672
  this.attachStarted = true;
682
673
  // If attachment blobs were uploaded in detached state we will go through a different attach flow
683
- const hasAttachmentBlobs = this.loader.services.detachedBlobStorage !== undefined &&
684
- this.loader.services.detachedBlobStorage.size > 0;
674
+ const hasAttachmentBlobs = this.detachedBlobStorage !== undefined && this.detachedBlobStorage.size > 0;
685
675
  try {
686
676
  (0, common_utils_1.assert)(this.deltaManager.inbound.length === 0, 0x0d6 /* "Inbound queue should be empty when attaching" */);
687
677
  let summary;
@@ -705,31 +695,28 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
705
695
  }
706
696
  }
707
697
  // Actually go and create the resolved document
708
- const createNewResolvedUrl = await this.urlResolver.resolve(request);
709
- (0, driver_utils_1.ensureFluidResolvedUrl)(createNewResolvedUrl);
710
698
  if (this.service === undefined) {
711
- (0, common_utils_1.assert)(this.client.details.type !== summarizerClientType, 0x2c4 /* "client should not be summarizer before container is created" */);
699
+ const createNewResolvedUrl = await this.urlResolver.resolve(request);
700
+ (0, common_utils_1.assert)(this.client.details.type !== summarizerClientType &&
701
+ createNewResolvedUrl !== undefined, 0x2c4 /* "client should not be summarizer before container is created" */);
712
702
  this.service = await (0, driver_utils_1.runWithRetry)(async () => this.serviceFactory.createContainer(summary, createNewResolvedUrl, this.subLogger, false), "containerAttach", this.mc.logger, {
713
703
  cancel: this.closeSignal,
714
704
  });
715
705
  }
716
- const resolvedUrl = this.service.resolvedUrl;
717
- (0, driver_utils_1.ensureFluidResolvedUrl)(resolvedUrl);
718
- this._resolvedUrl = resolvedUrl;
719
706
  await this.storageAdapter.connectToService(this.service);
720
707
  if (hasAttachmentBlobs) {
721
708
  // upload blobs to storage
722
- (0, common_utils_1.assert)(!!this.loader.services.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
709
+ (0, common_utils_1.assert)(!!this.detachedBlobStorage, 0x24e /* "assertion for type narrowing" */);
723
710
  // build a table mapping IDs assigned locally to IDs assigned by storage and pass it to runtime to
724
711
  // support blob handles that only know about the local IDs
725
712
  const redirectTable = new Map();
726
713
  // if new blobs are added while uploading, upload them too
727
- while (redirectTable.size < this.loader.services.detachedBlobStorage.size) {
728
- const newIds = this.loader.services.detachedBlobStorage
714
+ while (redirectTable.size < this.detachedBlobStorage.size) {
715
+ const newIds = this.detachedBlobStorage
729
716
  .getBlobIds()
730
717
  .filter((id) => !redirectTable.has(id));
731
718
  for (const id of newIds) {
732
- const blob = await this.loader.services.detachedBlobStorage.readBlob(id);
719
+ const blob = await this.detachedBlobStorage.readBlob(id);
733
720
  const response = await this.storageAdapter.createBlob(blob);
734
721
  redirectTable.set(id, response.id);
735
722
  }
@@ -764,12 +751,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
764
751
  catch (error) {
765
752
  // add resolved URL on error object so that host has the ability to find this document and delete it
766
753
  const newError = (0, telemetry_utils_1.normalizeError)(error);
767
- const resolvedUrl = this.resolvedUrl;
768
- if ((0, driver_utils_1.isFluidResolvedUrl)(resolvedUrl)) {
769
- newError.addTelemetryProperties({ resolvedUrl: resolvedUrl.url });
770
- }
754
+ newError.addTelemetryProperties({ resolvedUrl: (_a = this.resolvedUrl) === null || _a === void 0 ? void 0 : _a.url });
771
755
  this.close(newError);
772
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
773
756
  throw newError;
774
757
  }
775
758
  }, { start: true, end: true, cancel: "generic" });
@@ -864,7 +847,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
864
847
  .catch(() => false);
865
848
  }
866
849
  async processCodeProposal() {
867
- var _a;
868
850
  const codeDetails = this.getCodeDetailsFromQuorum();
869
851
  await Promise.all([
870
852
  this.deltaManager.inbound.pause(),
@@ -878,19 +860,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
878
860
  // pre-0.58 error message: existingContextDoesNotSatisfyIncomingProposal
879
861
  const error = new container_utils_1.GenericError("Existing context does not satisfy incoming proposal");
880
862
  this.close(error);
881
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
882
863
  }
883
864
  async getVersion(version) {
884
865
  const versions = await this.storageAdapter.getVersions(version, 1);
885
866
  return versions[0];
886
867
  }
887
- recordConnectStartTime() {
888
- if (this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] === undefined) {
889
- this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected] = common_utils_1.performance.now();
890
- }
891
- }
892
868
  connectToDeltaStream(args) {
893
- this.recordConnectStartTime();
894
869
  // All agents need "write" access, including summarizer.
895
870
  if (!this._canReconnect || !this.client.details.capabilities.interactive) {
896
871
  args.mode = "write";
@@ -902,12 +877,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
902
877
  *
903
878
  * @param specifiedVersion - Version SHA to load snapshot. If not specified, will fetch the latest snapshot.
904
879
  */
905
- async load(specifiedVersion, loadMode, pendingLocalState) {
880
+ async load(specifiedVersion, loadMode, resolvedUrl, pendingLocalState) {
906
881
  var _a;
907
- if (this._resolvedUrl === undefined) {
908
- throw new Error("Attempting to load without a resolved url");
909
- }
910
- this.service = await this.serviceFactory.createDocumentService(this._resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
882
+ this.service = await this.serviceFactory.createDocumentService(resolvedUrl, this.subLogger, this.client.details.type === summarizerClientType);
911
883
  // Ideally we always connect as "read" by default.
912
884
  // Currently that works with SPO & r11s, because we get "write" connection when connecting to non-existing file.
913
885
  // We should not rely on it by (one of them will address the issue, but we need to address both)
@@ -933,9 +905,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
933
905
  else {
934
906
  // if we have pendingLocalState we can load without storage; don't wait for connection
935
907
  this.storageAdapter.connectToService(this.service).catch((error) => {
936
- var _a;
937
908
  this.close(error);
938
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error);
939
909
  });
940
910
  }
941
911
  this._attachState = container_definitions_1.AttachState.Attached;
@@ -1061,8 +1031,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1061
1031
  }
1062
1032
  async rehydrateDetachedFromSnapshot(detachedContainerSnapshot) {
1063
1033
  if (detachedContainerSnapshot.tree[".hasAttachmentBlobs"] !== undefined) {
1064
- (0, common_utils_1.assert)(!!this.loader.services.detachedBlobStorage &&
1065
- this.loader.services.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1034
+ (0, common_utils_1.assert)(!!this.detachedBlobStorage && this.detachedBlobStorage.size > 0, 0x250 /* "serialized container with attachment blobs must be rehydrated with detached blob storage" */);
1066
1035
  delete detachedContainerSnapshot.tree[".hasAttachmentBlobs"];
1067
1036
  }
1068
1037
  const snapshotTree = (0, utils_1.getSnapshotTreeFromSerializedContainer)(detachedContainerSnapshot);
@@ -1115,9 +1084,7 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1115
1084
  this.initializeProtocolState(attributes, quorumSnapshot);
1116
1085
  }
1117
1086
  initializeProtocolState(attributes, quorumSnapshot) {
1118
- var _a;
1119
- const protocolHandlerBuilder = (_a = this.protocolHandlerBuilder) !== null && _a !== void 0 ? _a : ((...args) => new protocol_1.ProtocolHandler(...args, new audience_1.Audience()));
1120
- const protocol = protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })));
1087
+ const protocol = this.protocolHandlerBuilder(attributes, quorumSnapshot, (key, value) => this.submitMessage(protocol_definitions_1.MessageType.Propose, JSON.stringify({ key, value })));
1121
1088
  const protocolLogger = telemetry_utils_1.ChildLogger.create(this.subLogger, "ProtocolHandler");
1122
1089
  protocol.quorum.on("error", (error) => {
1123
1090
  protocolLogger.sendErrorEvent(error);
@@ -1137,10 +1104,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1137
1104
  });
1138
1105
  }
1139
1106
  this.processCodeProposal().catch((error) => {
1140
- var _a;
1141
1107
  const normalizedError = (0, telemetry_utils_1.normalizeError)(error);
1142
1108
  this.close(normalizedError);
1143
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, normalizedError);
1144
1109
  throw error;
1145
1110
  });
1146
1111
  }
@@ -1224,6 +1189,12 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1224
1189
  (0, common_utils_1.assert)(this.connectionMode === details.mode, 0x4b7 /* mismatch */);
1225
1190
  this.connectionStateHandler.receivedConnectEvent(details);
1226
1191
  });
1192
+ deltaManager.on("establishingConnection", (reason) => {
1193
+ this.connectionStateHandler.establishingConnection(reason);
1194
+ });
1195
+ deltaManager.on("cancelEstablishingConnection", (reason) => {
1196
+ this.connectionStateHandler.cancelEstablishingConnection(reason);
1197
+ });
1227
1198
  deltaManager.on("disconnect", (reason, error) => {
1228
1199
  var _a;
1229
1200
  (_a = this.collabWindowTracker) === null || _a === void 0 ? void 0 : _a.stopSequenceNumberUpdate();
@@ -1280,8 +1251,8 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1280
1251
  time - this.connectionTransitionTimes[connectionState_1.ConnectionState.Disconnected];
1281
1252
  durationFromDisconnected = telemetry_utils_1.TelemetryLogger.formatTick(durationFromDisconnected);
1282
1253
  }
1283
- else {
1284
- // This info is of most interest on establishing connection only.
1254
+ else if (value === connectionState_1.ConnectionState.CatchingUp) {
1255
+ // This info is of most interesting while Catching Up.
1285
1256
  checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
1286
1257
  if (this.deltaManager.hasCheckpointSequenceNumber) {
1287
1258
  opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
@@ -1330,7 +1301,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1330
1301
  }
1331
1302
  // back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
1332
1303
  submitContainerMessage(type, contents, batch, metadata) {
1333
- var _a;
1334
1304
  switch (type) {
1335
1305
  case protocol_definitions_1.MessageType.Operation:
1336
1306
  return this.submitMessage(type, JSON.stringify(contents), batch, metadata);
@@ -1339,7 +1309,6 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1339
1309
  default: {
1340
1310
  const newError = new container_utils_1.GenericError("invalidContainerSubmitOpType", undefined /* error */, { messageType: type });
1341
1311
  this.close(newError);
1342
- (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, newError);
1343
1312
  return -1;
1344
1313
  }
1345
1314
  }
@@ -1448,8 +1417,9 @@ class Container extends telemetry_utils_1.EventEmitterWithErrorHandling {
1448
1417
  (0, common_utils_1.assert)(((_a = this._context) === null || _a === void 0 ? void 0 : _a.disposed) !== false, 0x0dd /* "Existing context not disposed" */);
1449
1418
  // The relative loader will proxy requests to '/' to the loader itself assuming no non-cache flags
1450
1419
  // are set. Global requests will still go directly to the loader
1451
- const loader = new loader_1.RelativeLoader(this, this.loader);
1452
- this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), 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) => { var _a; return (_a = this.dispose) === null || _a === void 0 ? void 0 : _a.call(this, error); }, (error) => this.close(error), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
1420
+ const maybeLoader = this.scope;
1421
+ const loader = new loader_1.RelativeLoader(this, maybeLoader.ILoader);
1422
+ this._context = await containerContext_1.ContainerContext.createOrLoad(this, this.scope, this.codeLoader, codeDetails, snapshot, new deltaManagerProxy_1.DeltaManagerProxy(this._deltaManager), new quorum_1.QuorumProxy(this.protocolHandler.quorum), 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), Container.version, (dirty) => this.updateDirtyContainerState(dirty), existing, pendingLocalState);
1453
1423
  this.emit("contextChanged", codeDetails);
1454
1424
  }
1455
1425
  updateDirtyContainerState(dirty) {